UNPKG

jodit

Version:

Jodit is an awesome and useful wysiwyg editor with filebrowser

312 lines (311 loc) 11.5 kB
/*! * Jodit Editor (https://xdsoft.net/jodit/) * Released under MIT see LICENSE.txt in the project root for license information. * Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import * as consts from "../../core/constants.js"; import { autobind } from "../../core/decorators/index.js"; import { Dom } from "../../core/dom/dom.js"; import { pluginSystem } from "../../core/global.js"; import { $$, call, dataBind, getContentWidth, offset } from "../../core/helpers/index.js"; import { Plugin, Table } from "../../modules/index.js"; import "./config.js"; const key = 'table_processor_observer-resize'; /** * Process tables in editor */ export class resizeCells extends Plugin { constructor() { super(...arguments); this.selectMode = false; this.resizeDelta = 0; this.createResizeHandle = () => { if (!this.resizeHandler) { this.resizeHandler = this.j.c.div('jodit-table-resizer'); this.j.e .on(this.resizeHandler, 'mousedown.table touchstart.table', this.onHandleMouseDown) .on(this.resizeHandler, 'mouseenter.table', () => { this.j.async.clearTimeout(this.hideTimeout); }); } }; this.hideTimeout = 0; this.drag = false; this.minX = 0; this.maxX = 0; this.startX = 0; } /** * Shortcut for Table module */ get module() { return this.j.getInstance('Table', this.j.o); } /** * Now editor has rtl direction */ get isRTL() { return this.j.o.direction === 'rtl'; } showResizeHandle() { this.j.async.clearTimeout(this.hideTimeout); this.j.workplace.appendChild(this.resizeHandler); } hideResizeHandle() { this.hideTimeout = this.j.async.setTimeout(() => { Dom.safeRemove(this.resizeHandler); }, { timeout: this.j.defaultTimeout, label: 'hideResizer' }); } /** * Click on resize handle */ onHandleMouseDown(event) { if (this.j.isLocked) { return; } this.drag = true; this.j.e .on(this.j.ow, 'mouseup.resize-cells touchend.resize-cells', this.onMouseUp) .on(this.j.ew, 'mousemove.table touchmove.table', this.onMouseMove); this.startX = event.clientX; this.j.lock(key); this.resizeHandler.classList.add('jodit-table-resizer_moved'); let box, tableBox = this.workTable.getBoundingClientRect(); this.minX = 0; this.maxX = 1000000; if (this.wholeTable != null) { tableBox = this.workTable.parentNode.getBoundingClientRect(); this.minX = tableBox.left; this.maxX = this.minX + tableBox.width; } else { // find maximum columns const coordinate = this.module.formalCoordinate(this.workTable, this.workCell, true); this.module.formalMatrix(this.workTable, (td, i, j) => { if (coordinate[1] === j) { box = td.getBoundingClientRect(); this.minX = Math.max(box.left + consts.NEARBY / 2, this.minX); } if (coordinate[1] + (this.isRTL ? -1 : 1) === j) { box = td.getBoundingClientRect(); this.maxX = Math.min(box.left + box.width - consts.NEARBY / 2, this.maxX); } }); } return false; } /** * Mouse move after click on resize handle */ onMouseMove(event) { if (!this.drag) { return; } this.j.e.fire('closeAllPopups'); let x = event.clientX; const workplacePosition = offset((this.resizeHandler.parentNode || this.j.od.documentElement), this.j, this.j.od, true); if (x < this.minX) { x = this.minX; } if (x > this.maxX) { x = this.maxX; } this.resizeDelta = x - this.startX + (!this.j.o.iframe ? 0 : workplacePosition.left); this.resizeHandler.style.left = x - (this.j.o.iframe ? 0 : workplacePosition.left) + 'px'; const sel = this.j.s.sel; sel && sel.removeAllRanges(); } /** * Mouse up every where after move and click */ onMouseUp(e) { if (this.selectMode || this.drag) { this.selectMode = false; this.j.unlock(); } if (!this.resizeHandler || !this.drag) { return; } this.drag = false; this.j.e.off(this.j.ew, 'mousemove.table touchmove.table', this.onMouseMove); this.resizeHandler.classList.remove('jodit-table-resizer_moved'); if (this.startX !== e.clientX) { // resize column if (this.wholeTable == null) { this.resizeColumns(); } else { this.resizeTable(); } } this.j.synchronizeValues(); this.j.s.focus(); } /** * Resize only one column */ resizeColumns() { const delta = this.resizeDelta; const marked = []; const tableModule = this.module; tableModule.setColumnWidthByDelta(this.workTable, tableModule.formalCoordinate(this.workTable, this.workCell, true)[1], delta, true, marked); const nextTD = call(this.isRTL ? Dom.prev : Dom.next, this.workCell, Dom.isCell, this.workCell.parentNode); tableModule.setColumnWidthByDelta(this.workTable, tableModule.formalCoordinate(this.workTable, nextTD)[1], -delta, false, marked); } /** * Resize whole table */ resizeTable() { const delta = this.resizeDelta * (this.isRTL ? -1 : 1); const width = this.workTable.offsetWidth, parentWidth = getContentWidth(this.workTable.parentNode, this.j.ew); // for RTL use mirror logic const rightSide = !this.wholeTable; const needChangeWidth = this.isRTL ? !rightSide : rightSide; // right side if (needChangeWidth) { this.workTable.style.width = ((width + delta) / parentWidth) * 100 + '%'; } else { const side = this.isRTL ? 'marginRight' : 'marginLeft'; const margin = parseInt(this.j.ew.getComputedStyle(this.workTable)[side] || '0', 10); this.workTable.style.width = ((width - delta) / parentWidth) * 100 + '%'; this.workTable.style[side] = ((margin + delta) / parentWidth) * 100 + '%'; } } /** * Memoize current cell * * @param wholeTable - resize whole table by left side, * false - resize whole table by right side, null - resize column */ setWorkCell(cell, wholeTable = null) { this.wholeTable = wholeTable; this.workCell = cell; this.workTable = Dom.up(cell, (elm) => Dom.isTag(elm, 'table'), this.j.editor); } /** * Calc helper resize handle position */ calcHandlePosition(table, cell, offsetX = 0, delta = 0) { const box = offset(cell, this.j, this.j.ed); if (offsetX > consts.NEARBY && offsetX < box.width - consts.NEARBY) { this.hideResizeHandle(); return; } const workplacePosition = offset(this.j.workplace, this.j, this.j.od, true), parentBox = offset(table, this.j, this.j.ed); this.resizeHandler.style.left = (offsetX <= consts.NEARBY ? box.left : box.left + box.width) - workplacePosition.left + delta + 'px'; Object.assign(this.resizeHandler.style, { height: parentBox.height + 'px', top: parentBox.top - workplacePosition.top + 'px' }); this.showResizeHandle(); if (offsetX <= consts.NEARBY) { const prevTD = call(this.isRTL ? Dom.next : Dom.prev, cell, Dom.isCell, cell.parentNode); this.setWorkCell(prevTD || cell, prevTD ? null : true); } else { const nextTD = call(!this.isRTL ? Dom.next : Dom.prev, cell, Dom.isCell, cell.parentNode); this.setWorkCell(cell, !nextTD ? false : null); } } /** @override */ afterInit(editor) { if (!editor.o.tableAllowCellResize) { return; } editor.e .off(this.j.ow, '.resize-cells') .off('.resize-cells') .on('change.resize-cells afterCommand.resize-cells afterSetMode.resize-cells', () => { $$('table', editor.editor).forEach(this.observe); }) .on(this.j.ow, 'scroll.resize-cells', () => { if (!this.drag) { return; } const parent = Dom.up(this.workCell, (elm) => Dom.isTag(elm, 'table'), editor.editor); if (parent) { const parentBox = parent.getBoundingClientRect(); this.resizeHandler.style.top = parentBox.top + 'px'; } }) .on('beforeSetMode.resize-cells', () => { const tableModule = this.module; tableModule.getAllSelectedCells().forEach(td => { tableModule.removeSelection(td); tableModule.normalizeTable(Dom.closest(td, 'table', editor.editor)); }); }); } /** * Add to every Table listeners */ observe(table) { if (dataBind(table, key)) { return; } dataBind(table, key, true); this.j.e .on(table, 'mouseleave.resize-cells', (e) => { if (this.resizeHandler && this.resizeHandler !== e.relatedTarget) { this.hideResizeHandle(); } }) .on(table, 'mousemove.resize-cells touchmove.resize-cells', this.j.async.throttle((event) => { if (this.j.isLocked) { return; } const cell = Dom.up(event.target, Dom.isCell, table); if (!cell) { return; } this.calcHandlePosition(table, cell, event.offsetX); }, { timeout: this.j.defaultTimeout })); this.createResizeHandle(); } beforeDestruct(jodit) { if (jodit.events) { jodit.e.off(this.j.ow, '.resize-cells'); jodit.e.off('.resize-cells'); } } } __decorate([ autobind ], resizeCells.prototype, "onHandleMouseDown", null); __decorate([ autobind ], resizeCells.prototype, "onMouseMove", null); __decorate([ autobind ], resizeCells.prototype, "onMouseUp", null); __decorate([ autobind ], resizeCells.prototype, "observe", null); pluginSystem.add('resizeCells', resizeCells);