You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.8 KiB

// Helper for creating a schema that supports tables.
function getCellAttrs(dom, extraAttrs) {
let widthAttr = dom.getAttribute('data-colwidth');
let widths =
widthAttr && /^\d+(,\d+)*$/.test(widthAttr)
? widthAttr.split(',').map((s) => Number(s))
: null;
let colspan = Number(dom.getAttribute('colspan') || 1);
let result = {
colspan,
rowspan: Number(dom.getAttribute('rowspan') || 1),
colwidth: widths && widths.length == colspan ? widths : null,
};
for (let prop in extraAttrs) {
let getter = extraAttrs[prop].getFromDOM;
let value = getter && getter(dom);
if (value != null) result[prop] = value;
}
return result;
}
function setCellAttrs(node, extraAttrs) {
let attrs = {};
if (node.attrs.colspan != 1) attrs.colspan = node.attrs.colspan;
if (node.attrs.rowspan != 1) attrs.rowspan = node.attrs.rowspan;
if (node.attrs.colwidth)
attrs['data-colwidth'] = node.attrs.colwidth.join(',');
for (let prop in extraAttrs) {
let setter = extraAttrs[prop].setDOMAttr;
if (setter) setter(node.attrs[prop], attrs);
}
return attrs;
}
// :: (Object) → Object
//
// This function creates a set of [node
// specs](http://prosemirror.net/docs/ref/#model.SchemaSpec.nodes) for
// `table`, `table_row`, and `table_cell` nodes types as used by this
// module. The result can then be added to the set of nodes when
// creating a a schema.
//
// options::- The following options are understood:
//
// tableGroup:: ?string
// A group name (something like `"block"`) to add to the table
// node type.
//
// cellContent:: string
// The content expression for table cells.
//
// cellAttributes:: ?Object
// Additional attributes to add to cells. Maps attribute names to
// objects with the following properties:
//
// default:: any
// The attribute's default value.
//
// getFromDOM:: ?(dom.Node) → any
// A function to read the attribute's value from a DOM node.
//
// setDOMAttr:: ?(value: any, attrs: Object)
// A function to add the attribute's value to an attribute
// object that's used to render the cell's DOM.
export function tableNodes(options) {
let extraAttrs = options.cellAttributes || {};
let cellAttrs = {
colspan: { default: 1 },
rowspan: { default: 1 },
colwidth: { default: null },
};
for (let prop in extraAttrs)
cellAttrs[prop] = { default: extraAttrs[prop].default };
return {
table: {
content: 'table_row+',
tableRole: 'table',
isolating: true,
group: options.tableGroup,
parseDOM: [{ tag: 'table' }],
toDOM() {
return ['table', ['tbody', 0]];
},
},
table_row: {
content: '(table_cell | table_header)*',
tableRole: 'row',
parseDOM: [{ tag: 'tr' }],
toDOM() {
return ['tr', 0];
},
},
table_cell: {
content: options.cellContent,
attrs: cellAttrs,
tableRole: 'cell',
isolating: true,
parseDOM: [
{ tag: 'td', getAttrs: (dom) => getCellAttrs(dom, extraAttrs) },
],
toDOM(node) {
return ['td', setCellAttrs(node, extraAttrs), 0];
},
},
table_header: {
content: options.cellContent,
attrs: cellAttrs,
tableRole: 'header_cell',
isolating: true,
parseDOM: [
{ tag: 'th', getAttrs: (dom) => getCellAttrs(dom, extraAttrs) },
],
toDOM(node) {
return ['th', setCellAttrs(node, extraAttrs), 0];
},
},
};
}
export function tableNodeTypes(schema) {
let result = schema.cached.tableNodeTypes;
if (!result) {
result = schema.cached.tableNodeTypes = {};
for (let name in schema.nodes) {
let type = schema.nodes[name],
role = type.spec.tableRole;
if (role) result[role] = type;
}
}
return result;
}