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.
308 lines
12 KiB
308 lines
12 KiB
3 years ago
|
(function (global, factory) {
|
||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/core'), require('@tiptap/prosemirror-tables'), require('prosemirror-state')) :
|
||
|
typeof define === 'function' && define.amd ? define(['exports', '@tiptap/core', '@tiptap/prosemirror-tables', 'prosemirror-state'], factory) :
|
||
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/extension-table"] = {}, global.core, global.prosemirrorTables, global.prosemirrorState));
|
||
|
})(this, (function (exports, core, prosemirrorTables, prosemirrorState) { 'use strict';
|
||
|
|
||
|
function updateColumns(node, colgroup, table, cellMinWidth, overrideCol, overrideValue) {
|
||
|
let totalWidth = 0;
|
||
|
let fixedWidth = true;
|
||
|
let nextDOM = colgroup.firstChild;
|
||
|
const row = node.firstChild;
|
||
|
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];
|
||
|
const cssWidth = hasWidth ? `${hasWidth}px` : '';
|
||
|
totalWidth += hasWidth || cellMinWidth;
|
||
|
if (!hasWidth) {
|
||
|
fixedWidth = false;
|
||
|
}
|
||
|
if (!nextDOM) {
|
||
|
colgroup.appendChild(document.createElement('col')).style.width = cssWidth;
|
||
|
}
|
||
|
else {
|
||
|
if (nextDOM.style.width !== cssWidth) {
|
||
|
nextDOM.style.width = cssWidth;
|
||
|
}
|
||
|
nextDOM = nextDOM.nextSibling;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (nextDOM) {
|
||
|
const after = nextDOM.nextSibling;
|
||
|
nextDOM.parentNode.removeChild(nextDOM);
|
||
|
nextDOM = after;
|
||
|
}
|
||
|
if (fixedWidth) {
|
||
|
table.style.width = `${totalWidth}px`;
|
||
|
table.style.minWidth = '';
|
||
|
}
|
||
|
else {
|
||
|
table.style.width = '';
|
||
|
table.style.minWidth = `${totalWidth}px`;
|
||
|
}
|
||
|
}
|
||
|
class TableView {
|
||
|
constructor(node, cellMinWidth) {
|
||
|
this.node = node;
|
||
|
this.cellMinWidth = cellMinWidth;
|
||
|
this.dom = document.createElement('div');
|
||
|
this.dom.className = 'tableWrapper';
|
||
|
this.table = this.dom.appendChild(document.createElement('table'));
|
||
|
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) {
|
||
|
if (node.type !== this.node.type) {
|
||
|
return false;
|
||
|
}
|
||
|
this.node = node;
|
||
|
updateColumns(node, this.colgroup, this.table, this.cellMinWidth);
|
||
|
return true;
|
||
|
}
|
||
|
ignoreMutation(mutation) {
|
||
|
return mutation.type === 'attributes' && (mutation.target === this.table || this.colgroup.contains(mutation.target));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function createCell(cellType, cellContent) {
|
||
|
if (cellContent) {
|
||
|
return cellType.createChecked(null, cellContent);
|
||
|
}
|
||
|
return cellType.createAndFill();
|
||
|
}
|
||
|
|
||
|
function getTableNodeTypes(schema) {
|
||
|
if (schema.cached.tableNodeTypes) {
|
||
|
return schema.cached.tableNodeTypes;
|
||
|
}
|
||
|
const roles = {};
|
||
|
Object.keys(schema.nodes).forEach(type => {
|
||
|
const nodeType = schema.nodes[type];
|
||
|
if (nodeType.spec.tableRole) {
|
||
|
roles[nodeType.spec.tableRole] = nodeType;
|
||
|
}
|
||
|
});
|
||
|
schema.cached.tableNodeTypes = roles;
|
||
|
return roles;
|
||
|
}
|
||
|
|
||
|
function createTable(schema, rowsCount, colsCount, withHeaderRow, cellContent) {
|
||
|
const types = getTableNodeTypes(schema);
|
||
|
const headerCells = [];
|
||
|
const cells = [];
|
||
|
for (let index = 0; index < colsCount; index += 1) {
|
||
|
const cell = createCell(types.cell, cellContent);
|
||
|
if (cell) {
|
||
|
cells.push(cell);
|
||
|
}
|
||
|
if (withHeaderRow) {
|
||
|
const headerCell = createCell(types.header_cell, cellContent);
|
||
|
if (headerCell) {
|
||
|
headerCells.push(headerCell);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const rows = [];
|
||
|
for (let index = 0; index < rowsCount; index += 1) {
|
||
|
rows.push(types.row.createChecked(null, withHeaderRow && index === 0 ? headerCells : cells));
|
||
|
}
|
||
|
return types.table.createChecked(null, rows);
|
||
|
}
|
||
|
|
||
|
function isCellSelection(value) {
|
||
|
return value instanceof prosemirrorTables.CellSelection;
|
||
|
}
|
||
|
|
||
|
const deleteTableWhenAllCellsSelected = ({ editor }) => {
|
||
|
const { selection } = editor.state;
|
||
|
if (!isCellSelection(selection)) {
|
||
|
return false;
|
||
|
}
|
||
|
let cellCount = 0;
|
||
|
const table = core.findParentNodeClosestToPos(selection.ranges[0].$from, node => {
|
||
|
return node.type.name === 'table';
|
||
|
});
|
||
|
table === null || table === void 0 ? void 0 : table.node.descendants(node => {
|
||
|
if (node.type.name === 'table') {
|
||
|
return false;
|
||
|
}
|
||
|
if (['tableCell', 'tableHeader'].includes(node.type.name)) {
|
||
|
cellCount += 1;
|
||
|
}
|
||
|
});
|
||
|
const allCellsSelected = cellCount === selection.ranges.length;
|
||
|
if (!allCellsSelected) {
|
||
|
return false;
|
||
|
}
|
||
|
editor.commands.deleteTable();
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
const Table = core.Node.create({
|
||
|
name: 'table',
|
||
|
// @ts-ignore
|
||
|
addOptions() {
|
||
|
return {
|
||
|
HTMLAttributes: {},
|
||
|
resizable: false,
|
||
|
handleWidth: 5,
|
||
|
cellMinWidth: 25,
|
||
|
// TODO: fix
|
||
|
View: TableView,
|
||
|
lastColumnResizable: true,
|
||
|
allowTableNodeSelection: false,
|
||
|
};
|
||
|
},
|
||
|
content: 'tableRow+',
|
||
|
tableRole: 'table',
|
||
|
isolating: true,
|
||
|
group: 'block',
|
||
|
parseHTML() {
|
||
|
return [
|
||
|
{ tag: 'table' },
|
||
|
];
|
||
|
},
|
||
|
renderHTML({ HTMLAttributes }) {
|
||
|
return ['table', core.mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), ['tbody', 0]];
|
||
|
},
|
||
|
addCommands() {
|
||
|
return {
|
||
|
insertTable: ({ rows = 3, cols = 3, withHeaderRow = true } = {}) => ({ tr, dispatch, editor }) => {
|
||
|
const node = createTable(editor.schema, rows, cols, withHeaderRow);
|
||
|
if (dispatch) {
|
||
|
const offset = tr.selection.anchor + 1;
|
||
|
tr.replaceSelectionWith(node)
|
||
|
.scrollIntoView()
|
||
|
.setSelection(prosemirrorState.TextSelection.near(tr.doc.resolve(offset)));
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
addColumnBefore: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.addColumnBefore(state, dispatch);
|
||
|
},
|
||
|
addColumnAfter: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.addColumnAfter(state, dispatch);
|
||
|
},
|
||
|
deleteColumn: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.deleteColumn(state, dispatch);
|
||
|
},
|
||
|
addRowBefore: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.addRowBefore(state, dispatch);
|
||
|
},
|
||
|
addRowAfter: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.addRowAfter(state, dispatch);
|
||
|
},
|
||
|
deleteRow: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.deleteRow(state, dispatch);
|
||
|
},
|
||
|
deleteTable: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.deleteTable(state, dispatch);
|
||
|
},
|
||
|
mergeCells: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.mergeCells(state, dispatch);
|
||
|
},
|
||
|
splitCell: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.splitCell(state, dispatch);
|
||
|
},
|
||
|
toggleHeaderColumn: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.toggleHeader('column')(state, dispatch);
|
||
|
},
|
||
|
toggleHeaderRow: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.toggleHeader('row')(state, dispatch);
|
||
|
},
|
||
|
toggleHeaderCell: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.toggleHeaderCell(state, dispatch);
|
||
|
},
|
||
|
mergeOrSplit: () => ({ state, dispatch }) => {
|
||
|
if (prosemirrorTables.mergeCells(state, dispatch)) {
|
||
|
return true;
|
||
|
}
|
||
|
return prosemirrorTables.splitCell(state, dispatch);
|
||
|
},
|
||
|
setCellAttribute: (name, value) => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.setCellAttr(name, value)(state, dispatch);
|
||
|
},
|
||
|
goToNextCell: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.goToNextCell(1)(state, dispatch);
|
||
|
},
|
||
|
goToPreviousCell: () => ({ state, dispatch }) => {
|
||
|
return prosemirrorTables.goToNextCell(-1)(state, dispatch);
|
||
|
},
|
||
|
fixTables: () => ({ state, dispatch }) => {
|
||
|
if (dispatch) {
|
||
|
prosemirrorTables.fixTables(state);
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
setCellSelection: position => ({ tr, dispatch }) => {
|
||
|
if (dispatch) {
|
||
|
const selection = prosemirrorTables.CellSelection.create(tr.doc, position.anchorCell, position.headCell);
|
||
|
// @ts-ignore
|
||
|
tr.setSelection(selection);
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
};
|
||
|
},
|
||
|
addKeyboardShortcuts() {
|
||
|
return {
|
||
|
Tab: () => {
|
||
|
if (this.editor.commands.goToNextCell()) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!this.editor.can().addRowAfter()) {
|
||
|
return false;
|
||
|
}
|
||
|
return this.editor
|
||
|
.chain()
|
||
|
.addRowAfter()
|
||
|
.goToNextCell()
|
||
|
.run();
|
||
|
},
|
||
|
'Shift-Tab': () => this.editor.commands.goToPreviousCell(),
|
||
|
Backspace: deleteTableWhenAllCellsSelected,
|
||
|
'Mod-Backspace': deleteTableWhenAllCellsSelected,
|
||
|
Delete: deleteTableWhenAllCellsSelected,
|
||
|
'Mod-Delete': deleteTableWhenAllCellsSelected,
|
||
|
};
|
||
|
},
|
||
|
addProseMirrorPlugins() {
|
||
|
const isResizable = this.options.resizable && this.editor.isEditable;
|
||
|
return [
|
||
|
...(isResizable ? [prosemirrorTables.columnResizing({
|
||
|
handleWidth: this.options.handleWidth,
|
||
|
cellMinWidth: this.options.cellMinWidth,
|
||
|
View: this.options.View,
|
||
|
// TODO: PR for @types/prosemirror-tables
|
||
|
// @ts-ignore (incorrect type)
|
||
|
lastColumnResizable: this.options.lastColumnResizable,
|
||
|
})] : []),
|
||
|
prosemirrorTables.tableEditing({
|
||
|
allowTableNodeSelection: this.options.allowTableNodeSelection,
|
||
|
}),
|
||
|
];
|
||
|
},
|
||
|
extendNodeSchema(extension) {
|
||
|
const context = {
|
||
|
name: extension.name,
|
||
|
options: extension.options,
|
||
|
storage: extension.storage,
|
||
|
};
|
||
|
return {
|
||
|
tableRole: core.callOrReturn(core.getExtensionField(extension, 'tableRole', context)),
|
||
|
};
|
||
|
},
|
||
|
});
|
||
|
|
||
|
exports.Table = Table;
|
||
|
exports.createTable = createTable;
|
||
|
exports["default"] = Table;
|
||
|
|
||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||
|
|
||
|
}));
|
||
|
//# sourceMappingURL=tiptap-extension-table.umd.js.map
|