Editor.js

  1. /**
  2. * Provide a word-processor-like control.
  3. * <br><br>
  4. * This class is a wrapper around the public CKEditor 5 utility. It is intended that this class be used exclusively
  5. * rather than any of the raw CKEditor API. It provides a higher-level and more convenient API.
  6. * <br><br>
  7. * Please refer to CKEditor documentation on <a href="https://ckeditor.com/docs">https://ckeditor.com/docs</a> for more information.
  8. */
  9. class Editor {
  10. constructor(parentId) {
  11. this.parentId = parentId;
  12. this.editorId = parentId + "-editor";
  13. this.toolbarId = parentId + "-toolbar";
  14. }
  15. async initialize() {
  16. const self = this;
  17. const parentDiv = document.getElementById(this.parentId);
  18. parentDiv.style.border = '1px solid black';
  19. parentDiv.style.backgroundColor = 'white';
  20. // Create toolbar div
  21. const toolbarDiv = document.createElement('div');
  22. toolbarDiv .id = this.toolbarId;
  23. parentDiv.appendChild(toolbarDiv );
  24. // Create editor div
  25. const editorDiv = document.createElement('div');
  26. editorDiv.id = this.editorId;
  27. const parentHeight = parseInt(parentDiv.style.height);
  28. editorDiv.style.height = (parentHeight - 41) + 'px';
  29. parentDiv.appendChild(editorDiv);
  30. return new Promise(function (resolve, reject) {
  31. DecoupledEditor
  32. .create( editorDiv, {
  33. fontSize: {
  34. options: [
  35. 9,
  36. 11,
  37. 13,
  38. 'default',
  39. 17,
  40. 19,
  41. 21,
  42. 23,
  43. 25
  44. ],
  45. supportAllValues: true
  46. }
  47. } )
  48. .then( editor => {
  49. toolbarDiv.appendChild(editor.ui.view.toolbar.element);
  50. resolve( editor );
  51. } )
  52. .catch( error => {
  53. console.error( error );
  54. reject( undefined );
  55. } );
  56. });
  57. }
  58. /**
  59. * Creates a new instance of the Editor class and initializes it.
  60. *
  61. * @param {string} parentId - The ID of the editor div.
  62. * @return {Promise<Editor>} A promise that resolves to the initialized Editor instance.
  63. */
  64. static async create(parentId) {
  65. const ins = new Editor(parentId);
  66. ins.editor = await ins.initialize();
  67. Editor.addEditor(ins);
  68. return ins;
  69. }
  70. /**
  71. * Retrieves the HTML content from the editor.
  72. *
  73. * @return {string} The HTML content of the editor.
  74. */
  75. getHtml() {
  76. return this.editor.getData();
  77. }
  78. /**
  79. * Retrieves the text (not HTML) content of the editor.
  80. *
  81. * @returns {string}
  82. */
  83. getText() {
  84. return Utils.htmlToText(this.editor.getData());
  85. }
  86. /**
  87. * Sets the HTML content in the editor.
  88. *
  89. * @param html
  90. */
  91. setHtml(html) {
  92. this.editor.setData(html);
  93. }
  94. /**
  95. * Clears the content of the editor.
  96. */
  97. clear() {
  98. this.editor.setData('');
  99. }
  100. /**
  101. * Sets the editor to read-only mode.
  102. */
  103. readOnly() {
  104. this.editor.enableReadOnlyMode('xx');
  105. }
  106. /**
  107. * Sets the editor to read-write mode.
  108. */
  109. readWrite() {
  110. this.editor.disableReadOnlyMode('xx');
  111. }
  112. /**
  113. * Dispose of the editor when it is no longer needed.
  114. * Generally, Kiss handles this automatically.
  115. */
  116. dispose() {
  117. this.editor.destroy().then(() => {
  118. const parentDiv = document.getElementById(this.parentId);
  119. // Check if the first child exists and remove it
  120. const toolbar = document.getElementById(this.toolbarId);
  121. if (toolbar)
  122. parentDiv.removeChild(toolbar);
  123. // Check if the second child exists and remove it
  124. const editor = document.getElementById(this.editorId);
  125. if (editor)
  126. parentDiv.removeChild(editor);
  127. } ).catch(error => {
  128. console.log(error);
  129. });
  130. }
  131. /**
  132. * Create a new editor context.
  133. */
  134. static newEditorContext() {
  135. Editor.editorContext.push([]);
  136. }
  137. /**
  138. * Add an editor to the current context.
  139. *
  140. * @param editor
  141. */
  142. static addEditor(editor) {
  143. const cc = Editor.editorContext[Editor.editorContext.length - 1];
  144. cc.push(editor);
  145. }
  146. /**
  147. * Destroy all editors in last context and remove the context
  148. */
  149. static popEditorContext() {
  150. const c = Editor.editorContext.pop();
  151. if (c)
  152. for (let i = 0; i < c.length; i++)
  153. c[i].dispose();
  154. }
  155. /**
  156. * Destroys all popup and screen editors that have been created
  157. */
  158. static popAllEditorContexts() {
  159. while (Editor.editorContext.length)
  160. Editor.popEditorContext();
  161. }
  162. /**
  163. * Print the contents of the editor
  164. */
  165. printEditorContent() {
  166. const printWindow = window.open('', '_blank');
  167. printWindow.document.write('<html lang="en"><head><title>Print</title></head><body>');
  168. printWindow.document.write(this.editor.getData()); // Get the data from CKEditor
  169. printWindow.document.write('</body></html>');
  170. printWindow.document.close();
  171. printWindow.focus();
  172. printWindow.print();
  173. printWindow.close();
  174. }
  175. }
  176. Editor.editorContext = []; // An array of arrays. The outer array represents a stack of contexts.
  177. // The inner array is an array of editors that'll need to be disposed.
  178. // Basically, each context (except the first) represents a popup.
  179. // The first represents the current screen.
  180. // Each inner array contains an array of editors in that context.