editor.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import Quill from "https://cdn.skypack.dev/pin/quill@v1.3.7-AhkYF0UBjqu955pdu0pJ/mode=imports,min/optimized/quill.js"
  2. // 📙 Package Documentation: https://www.skypack.dev/view/quill
  3. // https://quilljs.com/docs/quickstart/
  4. Quill.register("modules/htmlEditButton", htmlEditButton)
  5. // https://github.com/benwinding/quill-html-edit-button/
  6. import htmlEditButton from "https://cdn.skypack.dev/pin/quill-html-edit-button@v2.2.12-bQePZLc6oeJp4TdDNJk2/mode=imports,min/optimized/quill-html-edit-button.js"
  7. // 📙 Package Documentation: https://www.skypack.dev/view/quill-html-edit-button
  8. import editorSettings from "./editor-settings.js"
  9. import {showToolbar} from "./ios-keyboard-bug.js"
  10. export default function editor(selector) {
  11. const contractHtmlFile = 'data/contract-content.html'
  12. const editor = new Quill(selector, editorSettings)
  13. // ios-keyboard-bug
  14. // add an event listener to scroll to check if
  15. // toolbar position has moved off the page
  16. window.addEventListener("scroll", showToolbar);
  17. // add an event listener to blur as iOS keyboard may have closed
  18. // and toolbar position needs to be checked again //editor.addEventListener("blur", showToolbar);
  19. // https://codepen.io/DmitrySkripkin/pen/eeXpZB
  20. editor.on('selection-change', function (range, oldRange) {
  21. if (range === null && oldRange !== null) {
  22. showToolbar()
  23. // console.log('editor blur')
  24. }
  25. });
  26. // Quill Autosave
  27. // https://codepen.io/quill/pen/RRYBEP
  28. const Delta = Quill.import('delta');
  29. // Store accumulated changes
  30. let change = new Delta();
  31. editor.on('text-change', function (delta) {
  32. change = change.compose(delta);
  33. // console.log(change)
  34. // // if is empty
  35. // if (isQuillEmpty(editor)) {
  36. // console.log("The editor is empty")
  37. // localStorage.setItem("contract_html","")
  38. // }
  39. });
  40. // Save periodically
  41. setInterval(function () {
  42. if (change.length() > 0) {
  43. // console.log('Saving changes', change);
  44. /*
  45. Partial changes: { partial: JSON.stringify(change) }
  46. Entire document: { doc: JSON.stringify(editor.getContents()) }
  47. */
  48. localStorage.setItem("contract_html", JSON.stringify(editor.getContents()))
  49. change = new Delta();
  50. }
  51. }, 10 * 1000);
  52. // save when Ctrl|CMD + S key is pressed (useful for debugging when saving setInterval is large)
  53. document.addEventListener('keydown', (e) => {
  54. if (e.key?.toLowerCase() === 's' && e.metaKey) {
  55. e.preventDefault();
  56. if (change.length() > 0) {
  57. localStorage.setItem("contract_html", JSON.stringify(editor.getContents()))
  58. change = new Delta();
  59. }
  60. }
  61. });
  62. // Check for unsaved data
  63. window.onbeforeunload = function () {
  64. if (change.length() > 0) {
  65. localStorage.setItem("contract_html", JSON.stringify(editor.getContents()))
  66. change = new Delta();
  67. }
  68. }
  69. // ✅ contract_html init
  70. if (!localStorage.getItem("contract_html") || isEmpty(localStorage.getItem("contract_html"))) {
  71. // if (!localStorage.getItem("contract_html") || isQuillEmpty(editor) ) {
  72. getHtmlFromFile(editor, contractHtmlFile)
  73. } else {
  74. let data = localStorage.getItem("contract_html")
  75. // data = stripSlashes(data)
  76. // const delta = editor.clipboard.convert(data)
  77. const delta = JSON.parse(data)
  78. editor.setContents(delta, "silent")
  79. if (isQuillEmpty(editor)) {
  80. console.log("The editor is empty -- initializing from file.")
  81. localStorage.setItem("contract_html", "")
  82. getHtmlFromFile(editor, contractHtmlFile)
  83. }
  84. }
  85. }
  86. function getHtmlFromFile(editor, contractHtmlFile) {
  87. // init contract_html from file
  88. fetch(contractHtmlFile).then((response) => response.text()).then((data) => {
  89. // data = stripSlashes(data)
  90. const delta = editor.clipboard.convert(data)
  91. // const delta = JSON.parse(data)
  92. // console.log(data)
  93. // console.log(delta)
  94. editor.setContents(delta, "silent")
  95. localStorage.setItem("contract_html", JSON.stringify(delta))
  96. })
  97. }
  98. // Helper functions
  99. // this is needed because contract.php needs single quotes escaped (\')
  100. const stripSlashes = (str) => {
  101. return str
  102. .replace(/\\'/g, '\'')
  103. // .replace(/\"/g, '"')
  104. // .replace(/\\\\/g, '\\')
  105. // .replace(/\\0/g, '\0')
  106. }
  107. // detect empty html tags (eg: <p><br></p>)
  108. const isEmpty = (htmlString) => {
  109. const parser = new DOMParser();
  110. const { textContent } = parser.parseFromString(htmlString, "text/html").documentElement;
  111. return !textContent.trim();
  112. }
  113. // https://github.com/quilljs/quill/issues/163#issuecomment-561341501
  114. function isQuillEmpty(quill) {
  115. if ((quill.getContents()['ops'] || []).length !== 1) { return false }
  116. return quill.getText().trim().length === 0
  117. }