jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
179 lines (178 loc) • 7.61 kB
JavaScript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../core/dom/index.js";
import { $$, css, scrollIntoViewIfNeeded } from "../../core/helpers/index.js";
import { attr } from "../../core/helpers/utils/index.js";
import { Icon } from "../../core/ui/icon.js";
import { Config } from "../../config.js";
import tableIcon from "./table.svg.js";
Config.prototype.table = {
splitBlockOnInsertTable: true,
selectionCellStyle: 'border: 1px double #1e88e5 !important;',
useExtraClassesOptions: false
};
Icon.set('table', tableIcon);
Config.prototype.controls.table = {
data: {
cols: 10,
rows: 10,
classList: {
'table table-bordered': 'Bootstrap Bordered',
'table table-striped': 'Bootstrap Striped',
'table table-dark': 'Bootstrap Dark'
}
},
popup: (editor, current, close, button) => {
editor.editor.normalize();
const snapshot = editor.history.snapshot.make();
const control = button.control;
const default_rows_count = control.data && control.data.rows ? control.data.rows : 10, default_cols_count = control.data && control.data.cols ? control.data.cols : 10;
const generateExtraClasses = () => {
if (!editor.o.table.useExtraClassesOptions) {
return '';
}
const out = [];
if (control.data) {
const classList = control.data.classList;
Object.keys(classList).forEach((classes) => {
out.push(`<label class="jodit_vertical_middle"><input class="jodit-checkbox" value="${classes}" type="checkbox"/>${classList[classes]}</label>`);
});
}
return out.join('');
};
const form = editor.c.fromHTML('<form class="jodit-form jodit-form__inserter">' +
'<div class="jodit-form__table-creator-box">' +
'<div class="jodit-form__container"></div>' +
'<div class="jodit-form__options">' +
generateExtraClasses() +
'</div>' +
'</div>' +
'<label class="jodit-form__center">' +
'<span>1</span> × <span>1</span>' +
'</label>' +
'</form>'), rows = form.querySelectorAll('span')[0], cols = form.querySelectorAll('span')[1], blocksContainer = form.querySelector('.jodit-form__container'), options = form.querySelector('.jodit-form__options'), cells = [];
const cnt = default_rows_count * default_cols_count;
for (let i = 0; i < cnt; i += 1) {
if (!cells[i]) {
cells.push(editor.c.element('span', {
dataIndex: i
}));
}
}
const mouseenter = (e, index) => {
const dv = e.target;
if (!Dom.isTag(dv, 'span')) {
return;
}
const k = index === undefined || isNaN(index)
? parseInt(attr(dv, '-index') || '0', 10)
: index || 0;
const rows_count = Math.ceil((k + 1) / default_cols_count), cols_count = (k % default_cols_count) + 1;
for (let i = 0; i < cells.length; i += 1) {
if (cols_count >= (i % default_cols_count) + 1 &&
rows_count >= Math.ceil((i + 1) / default_cols_count)) {
cells[i].className = 'jodit_hovered';
}
else {
cells[i].className = '';
}
}
cols.textContent = cols_count.toString();
rows.textContent = rows_count.toString();
};
editor.e
.on(blocksContainer, 'mousemove', mouseenter)
.on(blocksContainer, 'touchstart mousedown', (e) => {
const dv = e.target;
e.preventDefault();
e.stopImmediatePropagation();
if (!Dom.isTag(dv, 'span')) {
return;
}
const k = parseInt(attr(dv, '-index') || '0', 10);
const rows_count = Math.ceil((k + 1) / default_cols_count), cols_count = (k % default_cols_count) + 1;
const crt = editor.createInside, tbody = crt.element('tbody'), table = crt.element('table');
table.appendChild(tbody);
let first_td = null, tr, td;
for (let i = 1; i <= rows_count; i += 1) {
tr = crt.element('tr');
for (let j = 1; j <= cols_count; j += 1) {
td = crt.element('td');
if (!first_td) {
first_td = td;
}
css(td, 'width', (100 / cols_count).toFixed(4) + '%');
td.appendChild(crt.element('br'));
tr.appendChild(crt.text('\n'));
tr.appendChild(crt.text('\t'));
tr.appendChild(td);
}
tbody.appendChild(crt.text('\n'));
tbody.appendChild(tr);
}
$$('input[type=checkbox]:checked', options).forEach((input) => {
input.value
.split(/[\s]+/)
.forEach((className) => {
table.classList.add(className);
});
});
editor.s.restore();
editor.s.removeMarkers();
editor.editor.normalize();
editor.history.snapshot.restore(snapshot);
const block = Dom.furthest(editor.s.current(), Dom.isBlock, editor.editor);
if (block && Dom.isEmpty(block)) {
Dom.replace(block, table, undefined, false, true);
}
else {
if (block) {
const fake = crt.text('\n');
if (!editor.o.table.splitBlockOnInsertTable) {
Dom.after(block, fake);
Dom.after(fake, table);
}
else {
const range = editor.s.range;
range.collapse(false);
range.insertNode(fake);
range.collapse(false);
editor.s.selectRange(range);
const firstPart = editor.s.splitSelection(block, fake);
if (firstPart) {
Dom.after(firstPart, table);
}
else {
Dom.after(block, table);
}
}
}
else {
editor.s.insertNode(table, false);
}
}
if (first_td) {
editor.s.setCursorIn(first_td);
scrollIntoViewIfNeeded(first_td, editor.editor, editor.ed);
}
close();
});
if (button && button.parentElement) {
for (let i = 0; i < default_rows_count; i += 1) {
const row = editor.c.div();
for (let j = 0; j < default_cols_count; j += 1) {
row.appendChild(cells[i * default_cols_count + j]);
}
blocksContainer.appendChild(row);
}
if (cells[0]) {
cells[0].className = 'hovered';
}
}
return form;
},
tooltip: 'Insert table'
};