import { Plugin } from 'prosemirror-state';
import { Node as PMNode } from 'prosemirror-model';
import { tableEditing, columnResizing, TableView } from 'prosemirror-tables';
import { tableStyles } from '../schema';
/** TableView that also puts the author's class/id and fidelity table styles on the inner `
`. */
class HtmlAttrTableView extends TableView {
constructor(node: PMNode, defaultCellMinWidth: number) {
super(node, defaultCellMinWidth);
this.applyHtmlAttrs(node);
}
private applyHtmlAttrs(node: PMNode): void {
const htmlClass = node.attrs.htmlClass as string | null;
const htmlId = node.attrs.htmlId as string | null;
this.table.className = htmlClass ?? '';
if (htmlId) this.table.id = htmlId;
else this.table.removeAttribute('id');
// Email-fidelity attrs (width, max-width, background, border, centring).
// Width is only overridden when set, so column-resize sizing still applies.
const style = this.table.style;
// tableStyles() entries can hold several declarations ('color: x; font-family: y'
// for the table text style or an allowedStyles extension), so flatten them first.
const decls = tableStyles(node.attrs)
.flatMap(entry => entry.split(';'))
.map(decl => decl.trim())
.filter(decl => decl.includes(':'));
for (const prop of [
'max-width', 'background-color', 'border', 'margin-left', 'margin-right',
'color', 'font-family', 'font-size', 'font-weight', 'line-height',
]) {
style.removeProperty(prop);
}
// Clear any per-app extension properties first so a value that changed (or an
// entry that was removed) doesn't linger from the previous application.
for (const decl of decls) style.removeProperty(decl.slice(0, decl.indexOf(':')).trim());
for (const decl of decls) {
const idx = decl.indexOf(':');
style.setProperty(decl.slice(0, idx).trim(), decl.slice(idx + 1).trim());
}
// A layout table with no width of its own (an email button) shrinks to fit
// under email-fidelity; the host CSS keys off this hook.
this.table.toggleAttribute('data-autowidth', Boolean(node.attrs.layout && !node.attrs.width));
// Lets the host CSS drop column resizing's min-width on layout tables.
this.table.toggleAttribute('data-layout-table', Boolean(node.attrs.layout));
}
update(node: PMNode): boolean {
const updated = super.update(node);
if (updated) this.applyHtmlAttrs(node);
return updated;
}
}
/**
* prosemirror-tables wiring: cell selections, fix-tables normalization, and
* draggable column resizing (widths persist as `data-colwidth`). The CSS
* these plugins rely on (.selectedCell, .column-resize-handle, .resize-cursor)
* is inlined in nile-wysiwyg-editor.css.ts.
*/
export function tablePlugins(): Plugin[] {
return [
columnResizing({ View: HtmlAttrTableView }),
tableEditing({ allowTableNodeSelection: true }),
];
}