37f89d1858169fdf8eb54073e11be4fde0b2d79ba5f58edd1fd8d125d1f9b7650ccaff430d2ee15cf15c215453dbafa752ebb49f20cd9f7f2925365492e5ec 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import Block from '../blots/block.js';
  2. import Container from '../blots/container.js';
  3. class TableCell extends Block {
  4. static blotName = 'table';
  5. static tagName = 'TD';
  6. static create(value) {
  7. const node = super.create();
  8. if (value) {
  9. node.setAttribute('data-row', value);
  10. } else {
  11. node.setAttribute('data-row', tableId());
  12. }
  13. return node;
  14. }
  15. static formats(domNode) {
  16. if (domNode.hasAttribute('data-row')) {
  17. return domNode.getAttribute('data-row');
  18. }
  19. return undefined;
  20. }
  21. cellOffset() {
  22. if (this.parent) {
  23. return this.parent.children.indexOf(this);
  24. }
  25. return -1;
  26. }
  27. format(name, value) {
  28. if (name === TableCell.blotName && value) {
  29. this.domNode.setAttribute('data-row', value);
  30. } else {
  31. super.format(name, value);
  32. }
  33. }
  34. row() {
  35. return this.parent;
  36. }
  37. rowOffset() {
  38. if (this.row()) {
  39. return this.row().rowOffset();
  40. }
  41. return -1;
  42. }
  43. table() {
  44. return this.row() && this.row().table();
  45. }
  46. }
  47. class TableRow extends Container {
  48. static blotName = 'table-row';
  49. static tagName = 'TR';
  50. checkMerge() {
  51. // @ts-expect-error
  52. if (super.checkMerge() && this.next.children.head != null) {
  53. // @ts-expect-error
  54. const thisHead = this.children.head.formats();
  55. // @ts-expect-error
  56. const thisTail = this.children.tail.formats();
  57. // @ts-expect-error
  58. const nextHead = this.next.children.head.formats();
  59. // @ts-expect-error
  60. const nextTail = this.next.children.tail.formats();
  61. return thisHead.table === thisTail.table && thisHead.table === nextHead.table && thisHead.table === nextTail.table;
  62. }
  63. return false;
  64. }
  65. optimize(context) {
  66. super.optimize(context);
  67. this.children.forEach(child => {
  68. if (child.next == null) return;
  69. const childFormats = child.formats();
  70. const nextFormats = child.next.formats();
  71. if (childFormats.table !== nextFormats.table) {
  72. const next = this.splitAfter(child);
  73. if (next) {
  74. // @ts-expect-error TODO: parameters of optimize() should be a optional
  75. next.optimize();
  76. }
  77. // We might be able to merge with prev now
  78. if (this.prev) {
  79. // @ts-expect-error TODO: parameters of optimize() should be a optional
  80. this.prev.optimize();
  81. }
  82. }
  83. });
  84. }
  85. rowOffset() {
  86. if (this.parent) {
  87. return this.parent.children.indexOf(this);
  88. }
  89. return -1;
  90. }
  91. table() {
  92. return this.parent && this.parent.parent;
  93. }
  94. }
  95. class TableBody extends Container {
  96. static blotName = 'table-body';
  97. static tagName = 'TBODY';
  98. }
  99. class TableContainer extends Container {
  100. static blotName = 'table-container';
  101. static tagName = 'TABLE';
  102. balanceCells() {
  103. const rows = this.descendants(TableRow);
  104. const maxColumns = rows.reduce((max, row) => {
  105. return Math.max(row.children.length, max);
  106. }, 0);
  107. rows.forEach(row => {
  108. new Array(maxColumns - row.children.length).fill(0).forEach(() => {
  109. let value;
  110. if (row.children.head != null) {
  111. value = TableCell.formats(row.children.head.domNode);
  112. }
  113. const blot = this.scroll.create(TableCell.blotName, value);
  114. row.appendChild(blot);
  115. // @ts-expect-error TODO: parameters of optimize() should be a optional
  116. blot.optimize(); // Add break blot
  117. });
  118. });
  119. }
  120. cells(column) {
  121. return this.rows().map(row => row.children.at(column));
  122. }
  123. deleteColumn(index) {
  124. // @ts-expect-error
  125. const [body] = this.descendant(TableBody);
  126. if (body == null || body.children.head == null) return;
  127. body.children.forEach(row => {
  128. const cell = row.children.at(index);
  129. if (cell != null) {
  130. cell.remove();
  131. }
  132. });
  133. }
  134. insertColumn(index) {
  135. // @ts-expect-error
  136. const [body] = this.descendant(TableBody);
  137. if (body == null || body.children.head == null) return;
  138. body.children.forEach(row => {
  139. const ref = row.children.at(index);
  140. // @ts-expect-error
  141. const value = TableCell.formats(row.children.head.domNode);
  142. const cell = this.scroll.create(TableCell.blotName, value);
  143. row.insertBefore(cell, ref);
  144. });
  145. }
  146. insertRow(index) {
  147. // @ts-expect-error
  148. const [body] = this.descendant(TableBody);
  149. if (body == null || body.children.head == null) return;
  150. const id = tableId();
  151. const row = this.scroll.create(TableRow.blotName);
  152. body.children.head.children.forEach(() => {
  153. const cell = this.scroll.create(TableCell.blotName, id);
  154. row.appendChild(cell);
  155. });
  156. const ref = body.children.at(index);
  157. body.insertBefore(row, ref);
  158. }
  159. rows() {
  160. const body = this.children.head;
  161. if (body == null) return [];
  162. return body.children.map(row => row);
  163. }
  164. }
  165. TableContainer.allowedChildren = [TableBody];
  166. TableBody.requiredContainer = TableContainer;
  167. TableBody.allowedChildren = [TableRow];
  168. TableRow.requiredContainer = TableBody;
  169. TableRow.allowedChildren = [TableCell];
  170. TableCell.requiredContainer = TableRow;
  171. function tableId() {
  172. const id = Math.random().toString(36).slice(2, 6);
  173. return `row-${id}`;
  174. }
  175. export { TableCell, TableRow, TableBody, TableContainer, tableId };
  176. //# sourceMappingURL=table.js.map