code.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import Delta from 'quill-delta';
  2. import Parchment from 'parchment';
  3. import Block from '../blots/block';
  4. import Inline from '../blots/inline';
  5. import TextBlot from '../blots/text';
  6. class Code extends Inline {}
  7. Code.blotName = 'code';
  8. Code.tagName = 'CODE';
  9. class CodeBlock extends Block {
  10. static create(value) {
  11. let domNode = super.create(value);
  12. domNode.setAttribute('spellcheck', false);
  13. return domNode;
  14. }
  15. static formats() {
  16. return true;
  17. }
  18. delta() {
  19. let text = this.domNode.textContent;
  20. if (text.endsWith('\n')) { // Should always be true
  21. text = text.slice(0, -1);
  22. }
  23. return text.split('\n').reduce((delta, frag) => {
  24. return delta.insert(frag).insert('\n', this.formats());
  25. }, new Delta());
  26. }
  27. format(name, value) {
  28. if (name === this.statics.blotName && value) return;
  29. let [text, ] = this.descendant(TextBlot, this.length() - 1);
  30. if (text != null) {
  31. text.deleteAt(text.length() - 1, 1);
  32. }
  33. super.format(name, value);
  34. }
  35. formatAt(index, length, name, value) {
  36. if (length === 0) return;
  37. if (Parchment.query(name, Parchment.Scope.BLOCK) == null ||
  38. (name === this.statics.blotName && value === this.statics.formats(this.domNode))) {
  39. return;
  40. }
  41. let nextNewline = this.newlineIndex(index);
  42. if (nextNewline < 0 || nextNewline >= index + length) return;
  43. let prevNewline = this.newlineIndex(index, true) + 1;
  44. let isolateLength = nextNewline - prevNewline + 1;
  45. let blot = this.isolate(prevNewline, isolateLength);
  46. let next = blot.next;
  47. blot.format(name, value);
  48. if (next instanceof CodeBlock) {
  49. next.formatAt(0, index - prevNewline + length - isolateLength, name, value);
  50. }
  51. }
  52. insertAt(index, value, def) {
  53. if (def != null) return;
  54. let [text, offset] = this.descendant(TextBlot, index);
  55. text.insertAt(offset, value);
  56. }
  57. length() {
  58. let length = this.domNode.textContent.length;
  59. if (!this.domNode.textContent.endsWith('\n')) {
  60. return length + 1;
  61. }
  62. return length;
  63. }
  64. newlineIndex(searchIndex, reverse = false) {
  65. if (!reverse) {
  66. let offset = this.domNode.textContent.slice(searchIndex).indexOf('\n');
  67. return offset > -1 ? searchIndex + offset : -1;
  68. } else {
  69. return this.domNode.textContent.slice(0, searchIndex).lastIndexOf('\n');
  70. }
  71. }
  72. optimize(context) {
  73. if (!this.domNode.textContent.endsWith('\n')) {
  74. this.appendChild(Parchment.create('text', '\n'));
  75. }
  76. super.optimize(context);
  77. let next = this.next;
  78. if (next != null && next.prev === this &&
  79. next.statics.blotName === this.statics.blotName &&
  80. this.statics.formats(this.domNode) === next.statics.formats(next.domNode)) {
  81. next.optimize(context);
  82. next.moveChildren(this);
  83. next.remove();
  84. }
  85. }
  86. replace(target) {
  87. super.replace(target);
  88. [].slice.call(this.domNode.querySelectorAll('*')).forEach(function(node) {
  89. let blot = Parchment.find(node);
  90. if (blot == null) {
  91. node.parentNode.removeChild(node);
  92. } else if (blot instanceof Parchment.Embed) {
  93. blot.remove();
  94. } else {
  95. blot.unwrap();
  96. }
  97. });
  98. }
  99. }
  100. CodeBlock.blotName = 'code-block';
  101. CodeBlock.tagName = 'PRE';
  102. CodeBlock.TAB = ' ';
  103. export { Code, CodeBlock as default };