mirror of
https://github.com/docmost/docmost.git
synced 2026-06-13 19:19:53 +00:00
159 lines
4.1 KiB
TypeScript
159 lines
4.1 KiB
TypeScript
import type { Node as ProseMirrorNode } from '@tiptap/pm/model';
|
|
import type { NodeView, ViewMutationRecord } from '@tiptap/pm/view';
|
|
import { getColStyleDeclaration } from './utils/col-style';
|
|
|
|
export function updateColumns(
|
|
node: ProseMirrorNode,
|
|
colgroup: HTMLElement,
|
|
table: HTMLTableElement,
|
|
cellMinWidth: number,
|
|
overrideCol?: number,
|
|
overrideValue?: number,
|
|
) {
|
|
let totalWidth = 0;
|
|
let fixedWidth = true;
|
|
let nextDOM = colgroup.firstChild;
|
|
const row = node.firstChild;
|
|
|
|
if (row !== null) {
|
|
for (let i = 0, col = 0; i < row.childCount; i += 1) {
|
|
const { colspan, colwidth } = row.child(i).attrs;
|
|
|
|
for (let j = 0; j < colspan; j += 1, col += 1) {
|
|
const hasWidth =
|
|
overrideCol === col
|
|
? overrideValue
|
|
: ((colwidth && colwidth[j]) as number | undefined);
|
|
const cssWidth = hasWidth ? `${hasWidth}px` : '';
|
|
|
|
totalWidth += hasWidth || cellMinWidth;
|
|
|
|
if (!hasWidth) {
|
|
fixedWidth = false;
|
|
}
|
|
|
|
if (!nextDOM) {
|
|
const colElement = document.createElement('col');
|
|
|
|
const [propertyKey, propertyValue] = getColStyleDeclaration(
|
|
cellMinWidth,
|
|
hasWidth,
|
|
);
|
|
|
|
colElement.style.setProperty(propertyKey, propertyValue);
|
|
|
|
colgroup.appendChild(colElement);
|
|
} else {
|
|
if ((nextDOM as HTMLTableColElement).style.width !== cssWidth) {
|
|
const [propertyKey, propertyValue] = getColStyleDeclaration(
|
|
cellMinWidth,
|
|
hasWidth,
|
|
);
|
|
|
|
(nextDOM as HTMLTableColElement).style.setProperty(
|
|
propertyKey,
|
|
propertyValue,
|
|
);
|
|
}
|
|
|
|
nextDOM = nextDOM.nextSibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
while (nextDOM) {
|
|
const after = nextDOM.nextSibling;
|
|
|
|
nextDOM.parentNode?.removeChild(nextDOM);
|
|
nextDOM = after;
|
|
}
|
|
|
|
const hasUserWidth =
|
|
node.attrs.style &&
|
|
typeof node.attrs.style === 'string' &&
|
|
/\bwidth\s*:/i.test(node.attrs.style);
|
|
|
|
if (fixedWidth && !hasUserWidth) {
|
|
table.style.width = `${totalWidth}px`;
|
|
table.style.minWidth = '';
|
|
} else {
|
|
table.style.width = '';
|
|
table.style.minWidth = `${totalWidth}px`;
|
|
}
|
|
}
|
|
|
|
export class TableView implements NodeView {
|
|
node: ProseMirrorNode;
|
|
|
|
cellMinWidth: number;
|
|
|
|
dom: HTMLDivElement;
|
|
|
|
table: HTMLTableElement;
|
|
|
|
colgroup: HTMLTableColElement;
|
|
|
|
contentDOM: HTMLTableSectionElement;
|
|
|
|
constructor(node: ProseMirrorNode, cellMinWidth: number) {
|
|
this.node = node;
|
|
this.cellMinWidth = cellMinWidth;
|
|
this.dom = document.createElement('div');
|
|
this.dom.className = 'tableWrapper';
|
|
this.table = this.dom.appendChild(document.createElement('table'));
|
|
|
|
if (node.attrs.style) {
|
|
this.table.style.cssText = node.attrs.style;
|
|
}
|
|
|
|
this.colgroup = this.table.appendChild(document.createElement('colgroup'));
|
|
updateColumns(node, this.colgroup, this.table, cellMinWidth);
|
|
this.contentDOM = this.table.appendChild(document.createElement('tbody'));
|
|
}
|
|
|
|
update(node: ProseMirrorNode) {
|
|
if (node.type !== this.node.type) return false;
|
|
|
|
this.node = node;
|
|
updateColumns(node, this.colgroup, this.table, this.cellMinWidth);
|
|
|
|
return true;
|
|
}
|
|
|
|
ignoreMutation(mutation: ViewMutationRecord) {
|
|
const target = mutation.target as Node;
|
|
const isInsideWrapper = this.dom.contains(target);
|
|
const isInsideContent = this.contentDOM.contains(target);
|
|
|
|
if (isInsideWrapper && !isInsideContent) {
|
|
if (
|
|
mutation.type === 'attributes' ||
|
|
mutation.type === 'childList' ||
|
|
mutation.type === 'characterData'
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Chevron span (.tableReadonlySortChevron) added/removed by sort plugin.
|
|
if (mutation.type === 'childList') {
|
|
const nodes = [
|
|
...Array.from(mutation.addedNodes),
|
|
...Array.from(mutation.removedNodes),
|
|
];
|
|
if (
|
|
nodes.some(
|
|
(n) =>
|
|
n instanceof Element &&
|
|
n.classList.contains('tableReadonlySortChevron'),
|
|
)
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|