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
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;
|
|
}
|