From d66835ae73917076f2656de38d285bf01b49790f Mon Sep 17 00:00:00 2001 From: Jiuqing Song Date: Fri, 20 Mar 2020 22:19:01 -0700 Subject: [PATCH 01/20] Table Resize 2 --- packages/roosterjs-editor-dom/lib/index.ts | 1 + .../lib/selection/getPositionRect.ts | 15 +- .../lib/utils/normalizeRect.ts | 17 + .../lib/TableResize/TableResize.ts | 718 ++++++++++++++---- 4 files changed, 587 insertions(+), 164 deletions(-) create mode 100644 packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts diff --git a/packages/roosterjs-editor-dom/lib/index.ts b/packages/roosterjs-editor-dom/lib/index.ts index 789d336f416..c2c6bc4d982 100644 --- a/packages/roosterjs-editor-dom/lib/index.ts +++ b/packages/roosterjs-editor-dom/lib/index.ts @@ -42,6 +42,7 @@ export { getNextLeafSibling, getPreviousLeafSibling } from './utils/getLeafSibli export { getFirstLeafNode, getLastLeafNode } from './utils/getLeafNode'; export { default as getTextContent } from './utils/getTextContent'; export { default as splitTextNode } from './utils/splitTextNode'; +export { default as normalizeRect } from './utils/normalizeRect'; export { default as VTable, VCell } from './table/VTable'; diff --git a/packages/roosterjs-editor-dom/lib/selection/getPositionRect.ts b/packages/roosterjs-editor-dom/lib/selection/getPositionRect.ts index c3ee853a173..4e54ec39be9 100644 --- a/packages/roosterjs-editor-dom/lib/selection/getPositionRect.ts +++ b/packages/roosterjs-editor-dom/lib/selection/getPositionRect.ts @@ -1,4 +1,5 @@ import createRange from './createRange'; +import normalizeRect from '../utils/normalizeRect'; import { NodePosition, NodeType, Rect } from 'roosterjs-editor-types'; /** @@ -52,17 +53,3 @@ export default function getPositionRect(position: NodePosition): Rect { return null; } - -function normalizeRect(clientRect: ClientRect): Rect { - // A ClientRect of all 0 is possible. i.e. chrome returns a ClientRect of 0 when the cursor is on an empty p - // We validate that and only return a rect when the passed in ClientRect is valid - let { left, right, top, bottom } = clientRect || {}; - return left + right + top + bottom > 0 - ? { - left: Math.round(left), - right: Math.round(right), - top: Math.round(top), - bottom: Math.round(bottom), - } - : null; -} diff --git a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts new file mode 100644 index 00000000000..79ce16b8235 --- /dev/null +++ b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts @@ -0,0 +1,17 @@ +import { Rect } from 'roosterjs-editor-types'; + +/** + * A ClientRect of all 0 is possible. i.e. chrome returns a ClientRect of 0 when the cursor is on an empty p + * We validate that and only return a rect when the passed in ClientRect is valid + */ +export default function normalizeRect(clientRect: ClientRect): Rect { + let { left, right, top, bottom } = clientRect || {}; + return left + right + top + bottom > 0 + ? { + left: Math.round(left), + right: Math.round(right), + top: Math.round(top), + bottom: Math.round(bottom), + } + : null; +} diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index a266d4b471f..bd65d4ef013 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -1,27 +1,83 @@ -import { contains, fromHtml, isRtl, VTable } from 'roosterjs-editor-dom'; import { Editor, EditorPlugin } from 'roosterjs-editor-core'; -import { isNode } from 'roosterjs-cross-window'; +import { fromHtml, normalizeRect, VTable } from 'roosterjs-editor-dom'; +// import { editTable } from 'roosterjs/lib'; import { ContentPosition, PluginEvent, PluginEventType, - PluginMouseEvent, + Rect, ChangeSource, + TableOperation, + // TableOperation, + // PositionType, } from 'roosterjs-editor-types'; +// import { contains, fromHtml, isRtl, VTable } from 'roosterjs-editor-dom'; +// import { isNode } from 'roosterjs-cross-window'; +// import { +// ContentPosition, +// PluginEvent, +// PluginEventType, +// PluginMouseEvent, +// ChangeSource, +// } from 'roosterjs-editor-types'; -const TABLE_RESIZE_HANDLE_KEY = 'TABLE_RESIZE_HANDLE'; -const HANDLE_WIDTH = 6; -const CONTAINER_HTML = `
`; +// const TABLE_RESIZE_HANDLE_KEY = 'TABLE_RESIZE_HANDLE'; +// const HANDLE_WIDTH = 6; +// const CONTAINER_HTML = `
`; + +const TABLE_MOVER_WIDTH = 20; +const CELL_RESIZER_WIDTH = 4; +const MOVE_HANDLE_HTML = + '
+
'; + +const HORIZONTAL_INSERTER_HTML = + '
+
'; +const VERTICAL_INSERTER_HTML = + '
+
'; + +const HORITONZAL_RESIZER_HTML = + '
'; +const VERTICAL_RESIZER_HTML = + '
'; + +const enum ResizeState { + None, + Horizontal, + Vertical, +} /** * TableResize plugin, provides the ability to resize a table by drag-and-drop */ export default class TableResize implements EditorPlugin { private editor: Editor; - private onMouseOverDisposer: () => void; - private td: HTMLTableCellElement; - private pageX = -1; - private initialPageX: number; + // private onMouseOverDisposer: () => void; + // private td: HTMLTableCellElement; + // private pageX = -1; + // private initialPageX: number; + + private onMouseMoveDisposer: () => void; + private tableRectMap: { table: HTMLTableElement; rect: Rect }[] = null; + private resizerContainer: HTMLDivElement; + private currentTable: HTMLTableElement; + private currentTd: HTMLTableCellElement; + private horizontalResizer: HTMLDivElement; + private verticalResizer: HTMLDivElement; + private moveHandle: HTMLDivElement; + + private resizerStartPos: number = null; + private resizingState: ResizeState = ResizeState.None; + + private currentInsertTd: HTMLTableCellElement; + private insertingState: ResizeState = ResizeState.None; + private inserter: HTMLDivElement; + + /** + * Get a friendly name of this plugin + */ + getName() { + return 'TableResize'; + } /** * Initialize this plugin. This should only be called from Editor @@ -29,192 +85,554 @@ export default class TableResize implements EditorPlugin { */ initialize(editor: Editor) { this.editor = editor; - this.onMouseOverDisposer = this.editor.addDomEventHandler('mouseover', this.onMouseOver); - } + // this.onMouseOverDisposer = this.editor.addDomEventHandler('mouseover', this.onMouseOver); + this.setupResizerContainer(); - /** - * Get a friendly name of this plugin - */ - getName() { - return 'TableResize'; + this.onMouseMoveDisposer = this.editor.addDomEventHandler('mousemove', this.onMouseMove); } /** * Dispose this plugin */ dispose() { - this.detachMouseEvents(); + this.onMouseMoveDisposer(); + this.destoryRectMap(); + this.removeResizerContainer(); + this.editor = null; - this.onMouseOverDisposer(); + // this.detachMouseEvents(); + // this.onMouseOverDisposer(); } - /** - * Handle events triggered from editor - * @param event PluginEvent object - */ - onPluginEvent(event: PluginEvent) { - if ( - this.td && - (event.eventType == PluginEventType.KeyDown || - event.eventType == PluginEventType.ContentChanged || - (event.eventType == PluginEventType.MouseDown && !this.clickIntoCurrentTd(event))) - ) { - this.td = null; - this.calcAndShowHandle(); + onPluginEvent(e: PluginEvent) { + switch (e.eventType) { + case PluginEventType.Input: + case PluginEventType.ContentChanged: + case PluginEventType.Scroll: + this.destoryRectMap(); + break; } } - private clickIntoCurrentTd(event: PluginMouseEvent) { - let mouseEvent = event.rawEvent; - let target = mouseEvent.target; - return isNode(target) && contains(this.td, target, true /*treatSameNodeAsContain*/); + private setupResizerContainer() { + this.resizerContainer = this.editor.getDocument().createElement('div'); + this.editor.insertNode(this.resizerContainer, { + updateCursor: false, + insertOnNewLine: false, + replaceSelection: false, + position: ContentPosition.Outside, + }); + } + + private removeResizerContainer() { + this.resizerContainer.parentNode.removeChild(this.resizerContainer); + this.resizerContainer = null; } - private onMouseOver = (e: MouseEvent) => { - let node = (e.srcElement || e.target); - if ( - this.pageX < 0 && - node && - (node.tagName == 'TD' || node.tagName == 'TH') && - node != this.td - ) { - this.td = node; - this.calcAndShowHandle(); + private onMouseMove = (e: MouseEvent) => { + if (this.resizingState != ResizeState.None) { + return; + } + + if (!this.tableRectMap) { + this.cacheRects(); + } + + if (this.tableRectMap) { + let i = this.tableRectMap.length - 1; + for (; i >= 0; i--) { + const { table, rect } = this.tableRectMap[i]; + if ( + e.pageX >= rect.left - TABLE_MOVER_WIDTH && + e.pageX <= rect.right && + e.pageY >= rect.top - TABLE_MOVER_WIDTH && + e.pageY <= rect.bottom + ) { + this.setCurrentTable(table, rect); + break; + } + } + + if (i < 0) { + this.setCurrentTable(null); + } + + if (this.currentTable) { + const map = this.tableRectMap.filter(map => map.table == this.currentTable)[0]; + + for (let i = 0; i < this.currentTable.rows.length; i++) { + const tr = this.currentTable.rows[i]; + + let j = 0; + for (; j < tr.cells.length; j++) { + const td = tr.cells[Math.max(0, j)]; + const tdRect = normalizeRect(td.getBoundingClientRect()); + + if (e.pageX <= tdRect.right && e.pageY < tdRect.bottom) { + if (i == 0 && e.pageY < tdRect.top) { + this.setCurrentTd(null); + this.setCurrentInsertTd(ResizeState.Vertical, td, map.rect); + break; + } else if (j == 0 && e.pageX < tdRect.left) { + this.setCurrentTd(null); + this.setCurrentInsertTd(ResizeState.Horizontal, td, map.rect); + break; + } else { + this.setCurrentTd(td, map.rect, tdRect.right, tdRect.bottom); + this.setCurrentInsertTd(ResizeState.None); + break; + } + } + } + if (j < tr.cells.length) { + break; + } + } + } } }; - private calcAndShowHandle() { - if (this.td) { - let tr = this.editor.getElementAtCursor('TR', this.td); - let table = this.editor.getElementAtCursor('TABLE', tr); - if (tr && table) { - let [left, top] = this.getPosition(table); - let handle = this.getResizeHandle(); - - left += - this.td.offsetLeft + (isRtl(table) ? 0 : this.td.offsetWidth - HANDLE_WIDTH); - handle.style.display = ''; - handle.style.top = top + 'px'; - handle.style.height = table.offsetHeight + 'px'; - handle.style.left = left + 'px'; + private setCurrentInsertTd(insertingState: ResizeState.None): void; + private setCurrentInsertTd( + insertingState: ResizeState, + td: HTMLTableCellElement, + tableRect: Rect + ): void; + private setCurrentInsertTd( + insertingState: ResizeState, + td?: HTMLTableCellElement, + tableRect?: Rect + ) { + if (td != this.currentInsertTd || insertingState != this.insertingState) { + if (this.currentInsertTd) { + this.resizerContainer.removeChild(this.inserter); + this.inserter = null; + } + this.insertingState = insertingState; + this.currentInsertTd = td; + if (this.currentInsertTd) { + this.inserter = this.createInserter(tableRect); + this.resizerContainer.appendChild(this.inserter); } - } else { - this.getResizeHandle().style.display = 'none'; } } - private adjustHandle(pageX: number) { - let handle = this.getResizeHandle(); - handle.style.left = handle.offsetLeft + pageX - this.pageX + 'px'; - this.pageX = pageX; - } + private createInserter(tableRect: Rect) { + const rect = normalizeRect(this.currentInsertTd.getBoundingClientRect()); + const inserter = fromHtml( + this.insertingState == ResizeState.Horizontal + ? HORIZONTAL_INSERTER_HTML + : VERTICAL_INSERTER_HTML, + this.editor.getDocument() + )[0] as HTMLDivElement; + + if (this.insertingState == ResizeState.Horizontal) { + inserter.style.left = rect.left - 12 + 'px'; + inserter.style.top = rect.bottom - 8 + 'px'; + (inserter.firstChild as HTMLElement).style.width = + tableRect.right - tableRect.left + 'px'; + } else { + inserter.style.left = rect.right - 8 + 'px'; + inserter.style.top = rect.top - 12 + 'px'; + (inserter.firstChild as HTMLElement).style.height = + tableRect.bottom - tableRect.top + 'px'; + } - private getPosition(e: HTMLElement): [number, number] { - let parent = e.offsetParent; - let [left, top] = parent ? this.getPosition(parent) : [0, 0]; - return [left + e.offsetLeft - e.scrollLeft, top + e.offsetTop - e.scrollTop]; + inserter.addEventListener('click', this.insertTd); + + return inserter; } - private getResizeHandle() { - return this.editor.getCustomData( - TABLE_RESIZE_HANDLE_KEY, - () => { - let document = this.editor.getDocument(); - let handle = fromHtml(CONTAINER_HTML, document)[0] as HTMLElement; - this.editor.insertNode(handle, { - position: ContentPosition.Outside, - updateCursor: false, - replaceSelection: false, - insertOnNewLine: false, - }); - handle.addEventListener('mousedown', this.onMouseDown); - return handle; - }, - handle => { - handle.removeEventListener('mousedown', this.onMouseDown); - handle.parentNode.removeChild(handle); + private insertTd = () => { + this.editor.addUndoSnapshot((start, end) => { + const vtable = new VTable(this.currentInsertTd); + vtable.edit( + this.insertingState == ResizeState.Horizontal + ? TableOperation.InsertBelow + : TableOperation.InsertRight + ); + vtable.writeBack(); + this.editor.select(start, end); + this.setCurrentInsertTd(ResizeState.None); + }, ChangeSource.Format); + }; + + private setCurrentTable(table: HTMLTableElement, rect: Rect): void; + private setCurrentTable(table: null): void; + private setCurrentTable(table: HTMLTableElement, rect?: Rect) { + if (this.currentTable != table) { + this.setCurrentTd(null); + this.setCurrentInsertTd(null); + if (this.currentTable) { + this.resizerContainer.removeChild(this.moveHandle); } - ); + this.currentTable = table; + if (this.currentTable) { + this.moveHandle = this.createMoveHandle(rect); + this.resizerContainer.appendChild(this.moveHandle); + } + } } - private cancelEvent(e: MouseEvent) { - e.stopPropagation(); - e.preventDefault(); - } + private setCurrentTd(td: null): void; + private setCurrentTd( + td: HTMLTableCellElement, + tableRect: Rect, + right: number, + bottom: number + ): void; + private setCurrentTd( + td: HTMLTableCellElement, + tableRect?: Rect, + right?: number, + bottom?: number + ) { + if (this.currentTd != td) { + if (this.currentTd) { + this.resizerContainer.removeChild(this.horizontalResizer); + this.resizerContainer.removeChild(this.verticalResizer); + this.horizontalResizer = null; + this.verticalResizer = null; + } - private onMouseDown = (e: MouseEvent) => { - if (!this.editor || this.editor.isDisposed()) { - return; + this.currentTd = td; + + if (this.currentTd) { + this.horizontalResizer = this.createResizer( + true /*horizontal*/, + tableRect.left, + bottom - CELL_RESIZER_WIDTH + 1, + tableRect.right - tableRect.left, + CELL_RESIZER_WIDTH + ); + this.verticalResizer = this.createResizer( + false /*horizontal*/, + right - CELL_RESIZER_WIDTH + 1, + tableRect.top, + CELL_RESIZER_WIDTH, + tableRect.bottom - tableRect.top + ); + + this.resizerContainer.appendChild(this.horizontalResizer); + this.resizerContainer.appendChild(this.verticalResizer); + } } + } + + private createResizer( + horizontal: boolean, + left: number, + top: number, + width: number, + height: number + ) { + const div = fromHtml( + horizontal ? HORITONZAL_RESIZER_HTML : VERTICAL_RESIZER_HTML, + this.editor.getDocument() + )[0] as HTMLDivElement; + div.style.top = top + 'px'; + div.style.left = left + 'px'; + div.style.width = width + 'px'; + div.style.height = height + 'px'; + + div.addEventListener( + 'mousedown', + horizontal ? this.startHorizontalResizeTable : this.startVerticalResizeTable + ); - this.pageX = e.pageX; - this.initialPageX = e.pageX; - this.attachMouseEvents(); + // div.firstChild.addEventListener( + // 'click', + // horizontal ? this.onInsertBelow : this.onInsertRight + // ); - let handle = this.getResizeHandle(); - handle.style.borderWidth = '0 1px'; + return div; + } - this.cancelEvent(e); + private startHorizontalResizeTable = (e: MouseEvent) => { + this.resizingState = ResizeState.Horizontal; + this.startResizeTable(e); }; - private onMouseMove = (e: MouseEvent) => { - this.adjustHandle(e.pageX); - this.cancelEvent(e); + private startVerticalResizeTable = (e: MouseEvent) => { + this.resizingState = ResizeState.Vertical; + this.startResizeTable(e); }; - private onMouseUp = (e: MouseEvent) => { - this.detachMouseEvents(); - - let handle = this.getResizeHandle(); - handle.style.borderWidth = '0'; - - let table = this.editor.getElementAtCursor('TABLE', this.td) as HTMLTableElement; - let cellPadding = parseInt(table.cellPadding); - cellPadding = isNaN(cellPadding) ? 0 : cellPadding; - - if (e.pageX != this.initialPageX) { - let newWidth = - this.td.clientWidth - - cellPadding * 2 + - (e.pageX - this.initialPageX) * (isRtl(table) ? -1 : 1); - this.editor.addUndoSnapshot((start, end) => { - this.setTableColumnWidth(newWidth + 'px'); - this.editor.select(start, end); - }, ChangeSource.Format); + private startResizeTable(e: MouseEvent) { + this.resizerStartPos = this.resizingState == ResizeState.Horizontal ? e.pageY : e.pageX; + const doc = this.editor.getDocument(); + doc.addEventListener('mousemove', this.resizeTable, true); + doc.addEventListener('mouseup', this.endResizeTable, true); + + const resizer = + this.resizingState == ResizeState.Horizontal + ? this.horizontalResizer + : this.verticalResizer; + resizer.style.borderStyle = 'solid'; + } + + private resizeTable = (e: MouseEvent) => { + const rect = normalizeRect(this.currentTd.getBoundingClientRect()); + if (this.resizingState == ResizeState.Horizontal) { + const delta = e.pageY - this.resizerStartPos; + const newPos = rect.bottom + delta - CELL_RESIZER_WIDTH + 1; + this.horizontalResizer.style.top = newPos + 'px'; + } else { + const delta = e.pageX - this.resizerStartPos; + const newPos = rect.right + delta - CELL_RESIZER_WIDTH + 1; + this.verticalResizer.style.left = newPos + 'px'; } + }; + + private endResizeTable = (e: MouseEvent) => { + const doc = this.editor.getDocument(); + doc.removeEventListener('mousemove', this.resizeTable, true); + doc.removeEventListener('mouseup', this.endResizeTable, true); + + const rect = normalizeRect(this.currentTd.getBoundingClientRect()); + const newPos = + (this.resizingState == ResizeState.Horizontal + ? rect.bottom + e.pageY + : rect.right + e.pageX) - this.resizerStartPos; - this.pageX = -1; - this.calcAndShowHandle(); - this.editor.focus(); - this.cancelEvent(e); + this.editor.addUndoSnapshot((start, end) => { + let vtable = new VTable(this.currentTd); + + if (this.resizingState == ResizeState.Horizontal) { + vtable.table.style.height = null; + vtable.forEachCellOfCurrentRow(cell => { + if (cell.td) { + cell.td.style.height = + cell.td == this.currentTd ? newPos - rect.top + 'px' : null; + } + }); + } else { + vtable.table.style.width = ''; + vtable.table.width = ''; + vtable.forEachCellOfCurrentColumn(cell => { + if (cell.td) { + cell.td.style.width = + cell.td == this.currentTd ? newPos - rect.left + 'px' : null; + } + }); + } + vtable.writeBack(); + this.editor.select(start, end); + }, ChangeSource.Format); + + this.setCurrentTd(null); + this.resizingState = ResizeState.None; }; - private attachMouseEvents() { - if (this.editor && !this.editor.isDisposed()) { - let document = this.editor.getDocument(); - document.addEventListener('mousemove', this.onMouseMove, true); - document.addEventListener('mouseup', this.onMouseUp, true); - } + private createMoveHandle(rect: Rect) { + const div = fromHtml(MOVE_HANDLE_HTML, this.editor.getDocument())[0] as HTMLDivElement; + div.style.left = rect.left - TABLE_MOVER_WIDTH + 'px'; + div.style.top = rect.top - TABLE_MOVER_WIDTH + 'px'; + return div; } - private detachMouseEvents() { - if (this.editor && !this.editor.isDisposed()) { - let document = this.editor.getDocument(); - document.removeEventListener('mousemove', this.onMouseMove, true); - document.removeEventListener('mouseup', this.onMouseUp, true); - } + private destoryRectMap() { + this.setCurrentTable(null); + this.tableRectMap = null; } - private setTableColumnWidth(width: string) { - let vtable = new VTable(this.td); - vtable.table.style.width = ''; - vtable.table.width = ''; - vtable.forEachCellOfCurrentColumn(cell => { - if (cell.td) { - cell.td.style.width = cell.td == this.td ? width : ''; + private cacheRects() { + this.destoryRectMap(); + this.tableRectMap = []; + this.editor.queryElements('table', table => { + const rect = normalizeRect(table.getBoundingClientRect()); + if (rect) { + this.tableRectMap.push({ + table, + rect, + }); } }); - vtable.writeBack(); - return this.editor.contains(this.td) ? this.td : vtable.getCurrentTd(); } + + // private onInsertBelow = () => { + // if (this.currentTd) { + // this.editor.focus(); + // this.editor.select(this.currentTd, PositionType.Begin); + // editTable(this.editor, TableOperation.InsertBelow); + // } + // }; + + // private onInsertRight = () => { + // if (this.currentTd) { + // this.editor.focus(); + // this.editor.select(this.currentTd, PositionType.Begin); + // editTable(this.editor, TableOperation.InsertRight); + // } + // }; + + // /** + // * Handle events triggered from editor + // * @param event PluginEvent object + // */ + // onPluginEvent(event: PluginEvent) { + // if ( + // this.td && + // (event.eventType == PluginEventType.KeyDown || + // event.eventType == PluginEventType.ContentChanged || + // (event.eventType == PluginEventType.MouseDown && !this.clickIntoCurrentTd(event))) + // ) { + // this.td = null; + // this.calcAndShowHandle(); + // } + // } + + // private clickIntoCurrentTd(event: PluginMouseEvent) { + // let mouseEvent = event.rawEvent; + // let target = mouseEvent.target; + // return isNode(target) && contains(this.td, target, true /*treatSameNodeAsContain*/); + // } + + // private onMouseOver = (e: MouseEvent) => { + // let node = (e.srcElement || e.target); + // if ( + // this.pageX < 0 && + // node && + // (node.tagName == 'TD' || node.tagName == 'TH') && + // node != this.td + // ) { + // this.td = node; + // this.calcAndShowHandle(); + // } + // }; + + // private calcAndShowHandle() { + // if (this.td) { + // let tr = this.editor.getElementAtCursor('TR', this.td); + // let table = this.editor.getElementAtCursor('TABLE', tr); + // if (tr && table) { + // let [left, top] = this.getPosition(table); + // let handle = this.getResizeHandle(); + + // left += + // this.td.offsetLeft + (isRtl(table) ? 0 : this.td.offsetWidth - HANDLE_WIDTH); + // handle.style.display = ''; + // handle.style.top = top + 'px'; + // handle.style.height = table.offsetHeight + 'px'; + // handle.style.left = left + 'px'; + // } + // } else { + // this.getResizeHandle().style.display = 'none'; + // } + // } + + // private adjustHandle(pageX: number) { + // let handle = this.getResizeHandle(); + // handle.style.left = handle.offsetLeft + pageX - this.pageX + 'px'; + // this.pageX = pageX; + // } + + // private getPosition(e: HTMLElement): [number, number] { + // let parent = e.offsetParent; + // let [left, top] = parent ? this.getPosition(parent) : [0, 0]; + // return [left + e.offsetLeft - e.scrollLeft, top + e.offsetTop - e.scrollTop]; + // } + + // private getResizeHandle() { + // return this.editor.getCustomData( + // TABLE_RESIZE_HANDLE_KEY, + // () => { + // let document = this.editor.getDocument(); + // let handle = fromHtml(CONTAINER_HTML, document)[0] as HTMLElement; + // this.editor.insertNode(handle, { + // position: ContentPosition.Outside, + // updateCursor: false, + // replaceSelection: false, + // insertOnNewLine: false, + // }); + // handle.addEventListener('mousedown', this.onMouseDown); + // return handle; + // }, + // handle => { + // handle.removeEventListener('mousedown', this.onMouseDown); + // handle.parentNode.removeChild(handle); + // } + // ); + // } + + // private cancelEvent(e: MouseEvent) { + // e.stopPropagation(); + // e.preventDefault(); + // } + + // private onMouseDown = (e: MouseEvent) => { + // if (!this.editor || this.editor.isDisposed()) { + // return; + // } + + // this.pageX = e.pageX; + // this.initialPageX = e.pageX; + // this.attachMouseEvents(); + + // let handle = this.getResizeHandle(); + // handle.style.borderWidth = '0 1px'; + + // this.cancelEvent(e); + // }; + + // private onMouseMove = (e: MouseEvent) => { + // this.adjustHandle(e.pageX); + // this.cancelEvent(e); + // }; + + // private onMouseUp = (e: MouseEvent) => { + // this.detachMouseEvents(); + + // let handle = this.getResizeHandle(); + // handle.style.borderWidth = '0'; + + // let table = this.editor.getElementAtCursor('TABLE', this.td) as HTMLTableElement; + // let cellPadding = parseInt(table.cellPadding); + // cellPadding = isNaN(cellPadding) ? 0 : cellPadding; + + // if (e.pageX != this.initialPageX) { + // let newWidth = + // this.td.clientWidth - + // cellPadding * 2 + + // (e.pageX - this.initialPageX) * (isRtl(table) ? -1 : 1); + // this.editor.addUndoSnapshot((start, end) => { + // this.setTableColumnWidth(newWidth + 'px'); + // this.editor.select(start, end); + // }, ChangeSource.Format); + // } + + // this.pageX = -1; + // this.calcAndShowHandle(); + // this.editor.focus(); + // this.cancelEvent(e); + // }; + + // private attachMouseEvents() { + // if (this.editor && !this.editor.isDisposed()) { + // let document = this.editor.getDocument(); + // document.addEventListener('mousemove', this.onMouseMove, true); + // document.addEventListener('mouseup', this.onMouseUp, true); + // } + // } + + // private detachMouseEvents() { + // if (this.editor && !this.editor.isDisposed()) { + // let document = this.editor.getDocument(); + // document.removeEventListener('mousemove', this.onMouseMove, true); + // document.removeEventListener('mouseup', this.onMouseUp, true); + // } + // } + + // private setTableColumnWidth(width: string) { + // let vtable = new VTable(this.td); + // vtable.table.style.width = ''; + // vtable.table.width = ''; + // vtable.forEachCellOfCurrentColumn(cell => { + // if (cell.td) { + // cell.td.style.width = cell.td == this.td ? width : ''; + // } + // }); + // vtable.writeBack(); + // return this.editor.contains(this.td) ? this.td : vtable.getCurrentTd(); + // } } From 383d5f1974e3edb6bf70b22a54eea6571eea2198 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Wed, 5 Aug 2020 20:44:54 -0700 Subject: [PATCH 02/20] Change col and row cursors --- .../roosterjs-editor-plugins/lib/TableResize/TableResize.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index bd65d4ef013..b759c9429d9 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -36,9 +36,9 @@ const VERTICAL_INSERTER_HTML = '
+
'; const HORITONZAL_RESIZER_HTML = - '
'; + '
'; const VERTICAL_RESIZER_HTML = - '
'; + '
'; const enum ResizeState { None, From f517ae2d09483214690018c05545747136552b9e Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 13:28:05 -0700 Subject: [PATCH 03/20] Style the inserter - colors are right and + is centered --- .../lib/TableResize/TableResize.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index b759c9429d9..49545de87fd 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -30,10 +30,9 @@ const CELL_RESIZER_WIDTH = 4; const MOVE_HANDLE_HTML = '
+
'; -const HORIZONTAL_INSERTER_HTML = - '
+
'; -const VERTICAL_INSERTER_HTML = - '
+
'; +const INSERTER_COLOR = '#4A4A4A'; +const HORIZONTAL_INSERTER_HTML = `
+
`; +const VERTICAL_INSERTER_HTML = `
+
`; const HORITONZAL_RESIZER_HTML = '
'; @@ -219,6 +218,8 @@ export default class TableResize implements EditorPlugin { private createInserter(tableRect: Rect) { const rect = normalizeRect(this.currentInsertTd.getBoundingClientRect()); + let backgroundColor = this.editor.getDefaultFormat().backgroundColor || 'white'; + backgroundColor = backgroundColor; const inserter = fromHtml( this.insertingState == ResizeState.Horizontal ? HORIZONTAL_INSERTER_HTML From 8f5dc347395b93b4febed36658354ad045a54b65 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 13:37:27 -0700 Subject: [PATCH 04/20] Clean up string concats a bit --- .../lib/TableResize/TableResize.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 49545de87fd..54bfc3ee1bd 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -228,15 +228,15 @@ export default class TableResize implements EditorPlugin { )[0] as HTMLDivElement; if (this.insertingState == ResizeState.Horizontal) { - inserter.style.left = rect.left - 12 + 'px'; - inserter.style.top = rect.bottom - 8 + 'px'; - (inserter.firstChild as HTMLElement).style.width = - tableRect.right - tableRect.left + 'px'; + inserter.style.left = `${rect.left - 12}px`; + inserter.style.top = `${rect.bottom - 8}px`; + (inserter.firstChild as HTMLElement).style.width = `${tableRect.right - + tableRect.left}px`; } else { - inserter.style.left = rect.right - 8 + 'px'; - inserter.style.top = rect.top - 12 + 'px'; - (inserter.firstChild as HTMLElement).style.height = - tableRect.bottom - tableRect.top + 'px'; + inserter.style.left = `${rect.right - 8}px`; + inserter.style.top = `${rect.top - 12}px`; + (inserter.firstChild as HTMLElement).style.height = `${tableRect.bottom - + tableRect.top}px`; } inserter.addEventListener('click', this.insertTd); @@ -331,10 +331,10 @@ export default class TableResize implements EditorPlugin { horizontal ? HORITONZAL_RESIZER_HTML : VERTICAL_RESIZER_HTML, this.editor.getDocument() )[0] as HTMLDivElement; - div.style.top = top + 'px'; - div.style.left = left + 'px'; - div.style.width = width + 'px'; - div.style.height = height + 'px'; + div.style.top = `${top}px`; + div.style.left = `${left}px`; + div.style.width = `${width}px`; + div.style.height = `${height}px`; div.addEventListener( 'mousedown', @@ -377,11 +377,11 @@ export default class TableResize implements EditorPlugin { if (this.resizingState == ResizeState.Horizontal) { const delta = e.pageY - this.resizerStartPos; const newPos = rect.bottom + delta - CELL_RESIZER_WIDTH + 1; - this.horizontalResizer.style.top = newPos + 'px'; + this.horizontalResizer.style.top = `${newPos}px`; } else { const delta = e.pageX - this.resizerStartPos; const newPos = rect.right + delta - CELL_RESIZER_WIDTH + 1; - this.verticalResizer.style.left = newPos + 'px'; + this.verticalResizer.style.left = `${newPos}px`; } }; @@ -404,7 +404,7 @@ export default class TableResize implements EditorPlugin { vtable.forEachCellOfCurrentRow(cell => { if (cell.td) { cell.td.style.height = - cell.td == this.currentTd ? newPos - rect.top + 'px' : null; + cell.td == this.currentTd ? `${newPos - rect.top}px` : null; } }); } else { @@ -413,7 +413,7 @@ export default class TableResize implements EditorPlugin { vtable.forEachCellOfCurrentColumn(cell => { if (cell.td) { cell.td.style.width = - cell.td == this.currentTd ? newPos - rect.left + 'px' : null; + cell.td == this.currentTd ? `${newPos - rect.left}px` : null; } }); } @@ -427,8 +427,8 @@ export default class TableResize implements EditorPlugin { private createMoveHandle(rect: Rect) { const div = fromHtml(MOVE_HANDLE_HTML, this.editor.getDocument())[0] as HTMLDivElement; - div.style.left = rect.left - TABLE_MOVER_WIDTH + 'px'; - div.style.top = rect.top - TABLE_MOVER_WIDTH + 'px'; + div.style.left = `${rect.left - TABLE_MOVER_WIDTH}px`; + div.style.top = `${rect.top - TABLE_MOVER_WIDTH}px`; return div; } From 22207cf97467aad8708bf64bbc7862a6866037f7 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 14:22:46 -0700 Subject: [PATCH 05/20] Ensure the move handle is centered --- .../lib/TableResize/TableResize.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 54bfc3ee1bd..3250ef385a3 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -27,12 +27,11 @@ import { const TABLE_MOVER_WIDTH = 20; const CELL_RESIZER_WIDTH = 4; -const MOVE_HANDLE_HTML = - '
+
'; - const INSERTER_COLOR = '#4A4A4A'; -const HORIZONTAL_INSERTER_HTML = `
+
`; -const VERTICAL_INSERTER_HTML = `
+
`; +const MOVE_HANDLE_HTML = `
+
`; + +const HORIZONTAL_INSERTER_HTML = `
+
`; +const VERTICAL_INSERTER_HTML = `
+
`; const HORITONZAL_RESIZER_HTML = '
'; From 9169b8b35af7334322fa3e9051459dce604a82e5 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 21:16:01 -0700 Subject: [PATCH 06/20] Add end lines --- .../roosterjs-editor-plugins/lib/TableResize/TableResize.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 3250ef385a3..517397d09a4 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -30,8 +30,8 @@ const CELL_RESIZER_WIDTH = 4; const INSERTER_COLOR = '#4A4A4A'; const MOVE_HANDLE_HTML = `
+
`; -const HORIZONTAL_INSERTER_HTML = `
+
`; -const VERTICAL_INSERTER_HTML = `
+
`; +const HORIZONTAL_INSERTER_HTML = `
+
`; +const VERTICAL_INSERTER_HTML = `
+
`; const HORITONZAL_RESIZER_HTML = '
'; @@ -217,8 +217,6 @@ export default class TableResize implements EditorPlugin { private createInserter(tableRect: Rect) { const rect = normalizeRect(this.currentInsertTd.getBoundingClientRect()); - let backgroundColor = this.editor.getDefaultFormat().backgroundColor || 'white'; - backgroundColor = backgroundColor; const inserter = fromHtml( this.insertingState == ResizeState.Horizontal ? HORIZONTAL_INSERTER_HTML From 07dfe13f8b059be93a986919c2482615c02566f2 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 21:53:58 -0700 Subject: [PATCH 07/20] Get everything lines up correctly --- .../lib/TableResize/TableResize.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 517397d09a4..a7e9726d396 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -11,6 +11,7 @@ import { // TableOperation, // PositionType, } from 'roosterjs-editor-types'; + // import { contains, fromHtml, isRtl, VTable } from 'roosterjs-editor-dom'; // import { isNode } from 'roosterjs-cross-window'; // import { @@ -30,8 +31,10 @@ const CELL_RESIZER_WIDTH = 4; const INSERTER_COLOR = '#4A4A4A'; const MOVE_HANDLE_HTML = `
+
`; -const HORIZONTAL_INSERTER_HTML = `
+
`; -const VERTICAL_INSERTER_HTML = `
+
`; +const INSERTER_SIDE_LENGTH = 12; +const INSERTER_BORDER_SIZE = 1; +const HORIZONTAL_INSERTER_HTML = `
+
`; +const VERTICAL_INSERTER_HTML = `
+
`; const HORITONZAL_RESIZER_HTML = '
'; @@ -225,13 +228,15 @@ export default class TableResize implements EditorPlugin { )[0] as HTMLDivElement; if (this.insertingState == ResizeState.Horizontal) { - inserter.style.left = `${rect.left - 12}px`; + inserter.style.left = `${rect.left - + (INSERTER_SIDE_LENGTH + 2 * INSERTER_BORDER_SIZE)}px`; inserter.style.top = `${rect.bottom - 8}px`; (inserter.firstChild as HTMLElement).style.width = `${tableRect.right - tableRect.left}px`; } else { inserter.style.left = `${rect.right - 8}px`; - inserter.style.top = `${rect.top - 12}px`; + inserter.style.top = `${rect.top - + (INSERTER_SIDE_LENGTH + 2 * INSERTER_BORDER_SIZE)}px`; (inserter.firstChild as HTMLElement).style.height = `${tableRect.bottom - tableRect.top}px`; } From 0281d95462d2ead2bb2dd5b4b35a74e87e7bc0d5 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Thu, 6 Aug 2020 22:11:42 -0700 Subject: [PATCH 08/20] fix misplacement --- .../roosterjs-editor-plugins/lib/TableResize/TableResize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index a7e9726d396..9eb82ef3c10 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -236,7 +236,7 @@ export default class TableResize implements EditorPlugin { } else { inserter.style.left = `${rect.right - 8}px`; inserter.style.top = `${rect.top - - (INSERTER_SIDE_LENGTH + 2 * INSERTER_BORDER_SIZE)}px`; + (INSERTER_SIDE_LENGTH - 1 + 2 * INSERTER_BORDER_SIZE)}px`; (inserter.firstChild as HTMLElement).style.height = `${tableRect.bottom - tableRect.top}px`; } From e618c9ccb861bfb31a7863beaf183aadcbf1b749 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Fri, 7 Aug 2020 12:55:13 -0700 Subject: [PATCH 09/20] Remove commented code and unused code --- .../lib/TableResize/TableResize.ts | 237 +----------------- 1 file changed, 2 insertions(+), 235 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 9eb82ef3c10..c3722620f0f 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -1,41 +1,23 @@ import { Editor, EditorPlugin } from 'roosterjs-editor-core'; import { fromHtml, normalizeRect, VTable } from 'roosterjs-editor-dom'; -// import { editTable } from 'roosterjs/lib'; import { - ContentPosition, PluginEvent, PluginEventType, Rect, ChangeSource, TableOperation, - // TableOperation, - // PositionType, + ContentPosition, } from 'roosterjs-editor-types'; -// import { contains, fromHtml, isRtl, VTable } from 'roosterjs-editor-dom'; -// import { isNode } from 'roosterjs-cross-window'; -// import { -// ContentPosition, -// PluginEvent, -// PluginEventType, -// PluginMouseEvent, -// ChangeSource, -// } from 'roosterjs-editor-types'; - -// const TABLE_RESIZE_HANDLE_KEY = 'TABLE_RESIZE_HANDLE'; -// const HANDLE_WIDTH = 6; -// const CONTAINER_HTML = `
`; - const TABLE_MOVER_WIDTH = 20; -const CELL_RESIZER_WIDTH = 4; const INSERTER_COLOR = '#4A4A4A'; -const MOVE_HANDLE_HTML = `
+
`; const INSERTER_SIDE_LENGTH = 12; const INSERTER_BORDER_SIZE = 1; const HORIZONTAL_INSERTER_HTML = `
+
`; const VERTICAL_INSERTER_HTML = `
+
`; +const CELL_RESIZER_WIDTH = 4; const HORITONZAL_RESIZER_HTML = '
'; const VERTICAL_RESIZER_HTML = @@ -52,11 +34,6 @@ const enum ResizeState { */ export default class TableResize implements EditorPlugin { private editor: Editor; - // private onMouseOverDisposer: () => void; - // private td: HTMLTableCellElement; - // private pageX = -1; - // private initialPageX: number; - private onMouseMoveDisposer: () => void; private tableRectMap: { table: HTMLTableElement; rect: Rect }[] = null; private resizerContainer: HTMLDivElement; @@ -64,7 +41,6 @@ export default class TableResize implements EditorPlugin { private currentTd: HTMLTableCellElement; private horizontalResizer: HTMLDivElement; private verticalResizer: HTMLDivElement; - private moveHandle: HTMLDivElement; private resizerStartPos: number = null; private resizingState: ResizeState = ResizeState.None; @@ -86,9 +62,7 @@ export default class TableResize implements EditorPlugin { */ initialize(editor: Editor) { this.editor = editor; - // this.onMouseOverDisposer = this.editor.addDomEventHandler('mouseover', this.onMouseOver); this.setupResizerContainer(); - this.onMouseMoveDisposer = this.editor.addDomEventHandler('mousemove', this.onMouseMove); } @@ -101,8 +75,6 @@ export default class TableResize implements EditorPlugin { this.removeResizerContainer(); this.editor = null; - // this.detachMouseEvents(); - // this.onMouseOverDisposer(); } onPluginEvent(e: PluginEvent) { @@ -266,14 +238,7 @@ export default class TableResize implements EditorPlugin { if (this.currentTable != table) { this.setCurrentTd(null); this.setCurrentInsertTd(null); - if (this.currentTable) { - this.resizerContainer.removeChild(this.moveHandle); - } this.currentTable = table; - if (this.currentTable) { - this.moveHandle = this.createMoveHandle(rect); - this.resizerContainer.appendChild(this.moveHandle); - } } } @@ -343,11 +308,6 @@ export default class TableResize implements EditorPlugin { horizontal ? this.startHorizontalResizeTable : this.startVerticalResizeTable ); - // div.firstChild.addEventListener( - // 'click', - // horizontal ? this.onInsertBelow : this.onInsertRight - // ); - return div; } @@ -427,13 +387,6 @@ export default class TableResize implements EditorPlugin { this.resizingState = ResizeState.None; }; - private createMoveHandle(rect: Rect) { - const div = fromHtml(MOVE_HANDLE_HTML, this.editor.getDocument())[0] as HTMLDivElement; - div.style.left = `${rect.left - TABLE_MOVER_WIDTH}px`; - div.style.top = `${rect.top - TABLE_MOVER_WIDTH}px`; - return div; - } - private destoryRectMap() { this.setCurrentTable(null); this.tableRectMap = null; @@ -452,190 +405,4 @@ export default class TableResize implements EditorPlugin { } }); } - - // private onInsertBelow = () => { - // if (this.currentTd) { - // this.editor.focus(); - // this.editor.select(this.currentTd, PositionType.Begin); - // editTable(this.editor, TableOperation.InsertBelow); - // } - // }; - - // private onInsertRight = () => { - // if (this.currentTd) { - // this.editor.focus(); - // this.editor.select(this.currentTd, PositionType.Begin); - // editTable(this.editor, TableOperation.InsertRight); - // } - // }; - - // /** - // * Handle events triggered from editor - // * @param event PluginEvent object - // */ - // onPluginEvent(event: PluginEvent) { - // if ( - // this.td && - // (event.eventType == PluginEventType.KeyDown || - // event.eventType == PluginEventType.ContentChanged || - // (event.eventType == PluginEventType.MouseDown && !this.clickIntoCurrentTd(event))) - // ) { - // this.td = null; - // this.calcAndShowHandle(); - // } - // } - - // private clickIntoCurrentTd(event: PluginMouseEvent) { - // let mouseEvent = event.rawEvent; - // let target = mouseEvent.target; - // return isNode(target) && contains(this.td, target, true /*treatSameNodeAsContain*/); - // } - - // private onMouseOver = (e: MouseEvent) => { - // let node = (e.srcElement || e.target); - // if ( - // this.pageX < 0 && - // node && - // (node.tagName == 'TD' || node.tagName == 'TH') && - // node != this.td - // ) { - // this.td = node; - // this.calcAndShowHandle(); - // } - // }; - - // private calcAndShowHandle() { - // if (this.td) { - // let tr = this.editor.getElementAtCursor('TR', this.td); - // let table = this.editor.getElementAtCursor('TABLE', tr); - // if (tr && table) { - // let [left, top] = this.getPosition(table); - // let handle = this.getResizeHandle(); - - // left += - // this.td.offsetLeft + (isRtl(table) ? 0 : this.td.offsetWidth - HANDLE_WIDTH); - // handle.style.display = ''; - // handle.style.top = top + 'px'; - // handle.style.height = table.offsetHeight + 'px'; - // handle.style.left = left + 'px'; - // } - // } else { - // this.getResizeHandle().style.display = 'none'; - // } - // } - - // private adjustHandle(pageX: number) { - // let handle = this.getResizeHandle(); - // handle.style.left = handle.offsetLeft + pageX - this.pageX + 'px'; - // this.pageX = pageX; - // } - - // private getPosition(e: HTMLElement): [number, number] { - // let parent = e.offsetParent; - // let [left, top] = parent ? this.getPosition(parent) : [0, 0]; - // return [left + e.offsetLeft - e.scrollLeft, top + e.offsetTop - e.scrollTop]; - // } - - // private getResizeHandle() { - // return this.editor.getCustomData( - // TABLE_RESIZE_HANDLE_KEY, - // () => { - // let document = this.editor.getDocument(); - // let handle = fromHtml(CONTAINER_HTML, document)[0] as HTMLElement; - // this.editor.insertNode(handle, { - // position: ContentPosition.Outside, - // updateCursor: false, - // replaceSelection: false, - // insertOnNewLine: false, - // }); - // handle.addEventListener('mousedown', this.onMouseDown); - // return handle; - // }, - // handle => { - // handle.removeEventListener('mousedown', this.onMouseDown); - // handle.parentNode.removeChild(handle); - // } - // ); - // } - - // private cancelEvent(e: MouseEvent) { - // e.stopPropagation(); - // e.preventDefault(); - // } - - // private onMouseDown = (e: MouseEvent) => { - // if (!this.editor || this.editor.isDisposed()) { - // return; - // } - - // this.pageX = e.pageX; - // this.initialPageX = e.pageX; - // this.attachMouseEvents(); - - // let handle = this.getResizeHandle(); - // handle.style.borderWidth = '0 1px'; - - // this.cancelEvent(e); - // }; - - // private onMouseMove = (e: MouseEvent) => { - // this.adjustHandle(e.pageX); - // this.cancelEvent(e); - // }; - - // private onMouseUp = (e: MouseEvent) => { - // this.detachMouseEvents(); - - // let handle = this.getResizeHandle(); - // handle.style.borderWidth = '0'; - - // let table = this.editor.getElementAtCursor('TABLE', this.td) as HTMLTableElement; - // let cellPadding = parseInt(table.cellPadding); - // cellPadding = isNaN(cellPadding) ? 0 : cellPadding; - - // if (e.pageX != this.initialPageX) { - // let newWidth = - // this.td.clientWidth - - // cellPadding * 2 + - // (e.pageX - this.initialPageX) * (isRtl(table) ? -1 : 1); - // this.editor.addUndoSnapshot((start, end) => { - // this.setTableColumnWidth(newWidth + 'px'); - // this.editor.select(start, end); - // }, ChangeSource.Format); - // } - - // this.pageX = -1; - // this.calcAndShowHandle(); - // this.editor.focus(); - // this.cancelEvent(e); - // }; - - // private attachMouseEvents() { - // if (this.editor && !this.editor.isDisposed()) { - // let document = this.editor.getDocument(); - // document.addEventListener('mousemove', this.onMouseMove, true); - // document.addEventListener('mouseup', this.onMouseUp, true); - // } - // } - - // private detachMouseEvents() { - // if (this.editor && !this.editor.isDisposed()) { - // let document = this.editor.getDocument(); - // document.removeEventListener('mousemove', this.onMouseMove, true); - // document.removeEventListener('mouseup', this.onMouseUp, true); - // } - // } - - // private setTableColumnWidth(width: string) { - // let vtable = new VTable(this.td); - // vtable.table.style.width = ''; - // vtable.table.width = ''; - // vtable.forEachCellOfCurrentColumn(cell => { - // if (cell.td) { - // cell.td.style.width = cell.td == this.td ? width : ''; - // } - // }); - // vtable.writeBack(); - // return this.editor.contains(this.td) ? this.td : vtable.getCurrentTd(); - // } } From 57ae627aa72974f31274f98c49c4fdc8d48b5f80 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Fri, 7 Aug 2020 13:34:53 -0700 Subject: [PATCH 10/20] Fix border placement --- .../roosterjs-editor-plugins/lib/TableResize/TableResize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index c3722620f0f..8684ad533b5 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -201,7 +201,7 @@ export default class TableResize implements EditorPlugin { if (this.insertingState == ResizeState.Horizontal) { inserter.style.left = `${rect.left - - (INSERTER_SIDE_LENGTH + 2 * INSERTER_BORDER_SIZE)}px`; + (INSERTER_SIDE_LENGTH - 1 + 2 * INSERTER_BORDER_SIZE)}px`; inserter.style.top = `${rect.bottom - 8}px`; (inserter.firstChild as HTMLElement).style.width = `${tableRect.right - tableRect.left}px`; From 62fa5f6eec576d1a6b01500ebda034063439ba96 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Fri, 7 Aug 2020 18:26:24 -0700 Subject: [PATCH 11/20] Use background color from editor --- .../lib/TableResize/TableResize.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 8684ad533b5..efec84c4e38 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -11,11 +11,8 @@ import { const TABLE_MOVER_WIDTH = 20; const INSERTER_COLOR = '#4A4A4A'; - const INSERTER_SIDE_LENGTH = 12; const INSERTER_BORDER_SIZE = 1; -const HORIZONTAL_INSERTER_HTML = `
+
`; -const VERTICAL_INSERTER_HTML = `
+
`; const CELL_RESIZER_WIDTH = 4; const HORITONZAL_RESIZER_HTML = @@ -192,6 +189,11 @@ export default class TableResize implements EditorPlugin { private createInserter(tableRect: Rect) { const rect = normalizeRect(this.currentInsertTd.getBoundingClientRect()); + const editorBackgroundColor = this.editor.getDefaultFormat().backgroundColor; + const inserterBackgroundColor = editorBackgroundColor || 'white'; + const HORIZONTAL_INSERTER_HTML = `
+
`; + const VERTICAL_INSERTER_HTML = `
+
`; + const inserter = fromHtml( this.insertingState == ResizeState.Horizontal ? HORIZONTAL_INSERTER_HTML From 681d8043d9f3c283fe9f3ab15536b7a7f132302b Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Sat, 8 Aug 2020 11:22:13 -0700 Subject: [PATCH 12/20] rename horizontal resizer --- .../roosterjs-editor-plugins/lib/TableResize/TableResize.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index efec84c4e38..08b7531fb06 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -15,7 +15,7 @@ const INSERTER_SIDE_LENGTH = 12; const INSERTER_BORDER_SIZE = 1; const CELL_RESIZER_WIDTH = 4; -const HORITONZAL_RESIZER_HTML = +const HORIZONTAL_RESIZER_HTML = '
'; const VERTICAL_RESIZER_HTML = '
'; @@ -297,7 +297,7 @@ export default class TableResize implements EditorPlugin { height: number ) { const div = fromHtml( - horizontal ? HORITONZAL_RESIZER_HTML : VERTICAL_RESIZER_HTML, + horizontal ? HORIZONTAL_RESIZER_HTML : VERTICAL_RESIZER_HTML, this.editor.getDocument() )[0] as HTMLDivElement; div.style.top = `${top}px`; From 6115b168565b26e5b23a970ee5f2497c94e0a718 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Mon, 10 Aug 2020 12:52:39 -0700 Subject: [PATCH 13/20] Optimize resize so that it resizes dynamically --- package.json | 1 + .../lib/TableResize/TableResize.ts | 44 +++++++------------ yarn.lock | 5 +++ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 8b7bfbd479a..29711faa869 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "karma-phantomjs-launcher": "1.0.4", "karma-sourcemap-loader": "0.3.7", "karma-webpack": "4.0.2", + "lodash": "^4.17.10", "ncp": "2.0.0", "prettier": "1.18.2", "pretty-quick": "^1.11.1", diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 08b7531fb06..c8213413093 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -8,6 +8,7 @@ import { TableOperation, ContentPosition, } from 'roosterjs-editor-types'; +const throttle = require('lodash').throttle; const TABLE_MOVER_WIDTH = 20; const INSERTER_COLOR = '#4A4A4A'; @@ -38,8 +39,6 @@ export default class TableResize implements EditorPlugin { private currentTd: HTMLTableCellElement; private horizontalResizer: HTMLDivElement; private verticalResizer: HTMLDivElement; - - private resizerStartPos: number = null; private resizingState: ResizeState = ResizeState.None; private currentInsertTd: HTMLTableCellElement; @@ -324,9 +323,8 @@ export default class TableResize implements EditorPlugin { }; private startResizeTable(e: MouseEvent) { - this.resizerStartPos = this.resizingState == ResizeState.Horizontal ? e.pageY : e.pageX; const doc = this.editor.getDocument(); - doc.addEventListener('mousemove', this.resizeTable, true); + doc.addEventListener('mousemove', this.throttledResizeTable, true); doc.addEventListener('mouseup', this.endResizeTable, true); const resizer = @@ -336,31 +334,13 @@ export default class TableResize implements EditorPlugin { resizer.style.borderStyle = 'solid'; } - private resizeTable = (e: MouseEvent) => { - const rect = normalizeRect(this.currentTd.getBoundingClientRect()); - if (this.resizingState == ResizeState.Horizontal) { - const delta = e.pageY - this.resizerStartPos; - const newPos = rect.bottom + delta - CELL_RESIZER_WIDTH + 1; - this.horizontalResizer.style.top = `${newPos}px`; - } else { - const delta = e.pageX - this.resizerStartPos; - const newPos = rect.right + delta - CELL_RESIZER_WIDTH + 1; - this.verticalResizer.style.left = `${newPos}px`; - } - }; - - private endResizeTable = (e: MouseEvent) => { - const doc = this.editor.getDocument(); - doc.removeEventListener('mousemove', this.resizeTable, true); - doc.removeEventListener('mouseup', this.endResizeTable, true); + private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 200)(e); - const rect = normalizeRect(this.currentTd.getBoundingClientRect()); - const newPos = - (this.resizingState == ResizeState.Horizontal - ? rect.bottom + e.pageY - : rect.right + e.pageX) - this.resizerStartPos; + private resizeTable = (e: MouseEvent) => { + if (this.currentTd) { + const rect = normalizeRect(this.currentTd.getBoundingClientRect()); + const newPos = this.resizingState == ResizeState.Horizontal ? e.pageY : e.pageX; - this.editor.addUndoSnapshot((start, end) => { let vtable = new VTable(this.currentTd); if (this.resizingState == ResizeState.Horizontal) { @@ -382,6 +362,16 @@ export default class TableResize implements EditorPlugin { }); } vtable.writeBack(); + } + }; + + private endResizeTable = (e: MouseEvent) => { + const doc = this.editor.getDocument(); + doc.removeEventListener('mousemove', this.throttledResizeTable, true); + doc.removeEventListener('mouseup', this.endResizeTable, true); + + this.editor.addUndoSnapshot((start, end) => { + this.resizeTable(e); this.editor.select(start, end); }, ChangeSource.Format); diff --git a/yarn.lock b/yarn.lock index 06e0bec8bcd..79e1b7ea483 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3294,6 +3294,11 @@ lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.17.11, lodash@~4.17.10: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +lodash@^4.17.10: + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== + lodash@^4.17.14: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" From 682ce7d082fe46d8297d7c17f1cd7abfb6b0c387 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Mon, 10 Aug 2020 12:59:58 -0700 Subject: [PATCH 14/20] Remove the double line on the vertical and horizontal slider --- .../lib/TableResize/TableResize.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index c8213413093..8842c872f6c 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -17,9 +17,9 @@ const INSERTER_BORDER_SIZE = 1; const CELL_RESIZER_WIDTH = 4; const HORIZONTAL_RESIZER_HTML = - '
'; + '
'; const VERTICAL_RESIZER_HTML = - '
'; + '
'; const enum ResizeState { None, @@ -326,15 +326,9 @@ export default class TableResize implements EditorPlugin { const doc = this.editor.getDocument(); doc.addEventListener('mousemove', this.throttledResizeTable, true); doc.addEventListener('mouseup', this.endResizeTable, true); - - const resizer = - this.resizingState == ResizeState.Horizontal - ? this.horizontalResizer - : this.verticalResizer; - resizer.style.borderStyle = 'solid'; } - private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 200)(e); + private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 300)(e); private resizeTable = (e: MouseEvent) => { if (this.currentTd) { From 46524b48b6ef2dc20ce23baa489eecbfef45b290 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Mon, 10 Aug 2020 18:57:13 -0700 Subject: [PATCH 15/20] Adding more lines and updating the throttling value --- .../lib/utils/normalizeRect.ts | 32 +++++++++---------- .../lib/TableResize/TableResize.ts | 2 +- .../controls/ribbon/renderTableOptions.tsx | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts index 79ce16b8235..78e6e1c305e 100644 --- a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts +++ b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts @@ -1,17 +1,15 @@ -import { Rect } from 'roosterjs-editor-types'; - -/** - * A ClientRect of all 0 is possible. i.e. chrome returns a ClientRect of 0 when the cursor is on an empty p - * We validate that and only return a rect when the passed in ClientRect is valid - */ -export default function normalizeRect(clientRect: ClientRect): Rect { - let { left, right, top, bottom } = clientRect || {}; - return left + right + top + bottom > 0 - ? { - left: Math.round(left), - right: Math.round(right), - top: Math.round(top), - bottom: Math.round(bottom), - } - : null; -} +import { Rect } from 'roosterjs-editor-types'; + +/** + * A ClientRect of all 0 is possible. i.e. chrome returns a ClientRect of 0 when the cursor is on an empty p + * We validate that and only return a rect when the passed in ClientRect is valid + */ +export default function normalizeRect(clientRect: ClientRect): Rect { + let { left, right, top, bottom } = clientRect || {}; + return { + left: Math.round(left), + right: Math.round(right), + top: Math.round(top), + bottom: Math.round(bottom), + }; +} diff --git a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts index 8842c872f6c..5ba1aa811c8 100644 --- a/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/TableResize/TableResize.ts @@ -328,7 +328,7 @@ export default class TableResize implements EditorPlugin { doc.addEventListener('mouseup', this.endResizeTable, true); } - private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 300)(e); + private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 500)(e); private resizeTable = (e: MouseEvent) => { if (this.currentTd) { diff --git a/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx b/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx index 5270c077c85..9bc2df57c41 100644 --- a/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx +++ b/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx @@ -189,7 +189,7 @@ class TableOptions extends React.Component { let cols = parseInt(this.cols.current.value); let rows = parseInt(this.rows.current.value); - if (cols > 0 && cols <= 10 && rows > 0 && rows <= 10) { + if (cols > 0 && cols <= 99 && rows > 0 && rows <= 99) { insertTable(this.props.editor, cols, rows); } }; From 18c96cc9573109186536b7c76790ff6e2d808e7d Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Mon, 10 Aug 2020 19:17:19 -0700 Subject: [PATCH 16/20] Revert changes used for testing --- .../lib/utils/normalizeRect.ts | 14 ++++++++------ .../scripts/controls/ribbon/renderTableOptions.tsx | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts index 78e6e1c305e..aa19f066a09 100644 --- a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts +++ b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts @@ -6,10 +6,12 @@ import { Rect } from 'roosterjs-editor-types'; */ export default function normalizeRect(clientRect: ClientRect): Rect { let { left, right, top, bottom } = clientRect || {}; - return { - left: Math.round(left), - right: Math.round(right), - top: Math.round(top), - bottom: Math.round(bottom), - }; + return left + right + top + bottom > 0 + ? { + left: Math.round(left), + right: Math.round(right), + top: Math.round(top), + bottom: Math.round(bottom), + } + : null; } diff --git a/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx b/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx index 9bc2df57c41..5270c077c85 100644 --- a/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx +++ b/publish/samplesite/scripts/controls/ribbon/renderTableOptions.tsx @@ -189,7 +189,7 @@ class TableOptions extends React.Component { let cols = parseInt(this.cols.current.value); let rows = parseInt(this.rows.current.value); - if (cols > 0 && cols <= 99 && rows > 0 && rows <= 99) { + if (cols > 0 && cols <= 10 && rows > 0 && rows <= 10) { insertTable(this.props.editor, cols, rows); } }; From be193842dfcf568f399f43f0aef6bc251d672bfd Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Tue, 11 Aug 2020 13:34:35 -0700 Subject: [PATCH 17/20] Use the right width for the mouvemove function --- .../lib/plugins/TableResize/TableResize.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts index 5ba1aa811c8..c0b20c010d1 100644 --- a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts @@ -10,7 +10,6 @@ import { } from 'roosterjs-editor-types'; const throttle = require('lodash').throttle; -const TABLE_MOVER_WIDTH = 20; const INSERTER_COLOR = '#4A4A4A'; const INSERTER_SIDE_LENGTH = 12; const INSERTER_BORDER_SIZE = 1; @@ -112,9 +111,9 @@ export default class TableResize implements EditorPlugin { for (; i >= 0; i--) { const { table, rect } = this.tableRectMap[i]; if ( - e.pageX >= rect.left - TABLE_MOVER_WIDTH && + e.pageX >= rect.left - INSERTER_SIDE_LENGTH && e.pageX <= rect.right && - e.pageY >= rect.top - TABLE_MOVER_WIDTH && + e.pageY >= rect.top - INSERTER_SIDE_LENGTH && e.pageY <= rect.bottom ) { this.setCurrentTable(table, rect); From b9d7d9df77481085f9cc77bf8074e2be5a0a7525 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Tue, 11 Aug 2020 15:52:36 -0700 Subject: [PATCH 18/20] Remove formatting --- packages/roosterjs-editor-dom/lib/index.ts | 8 ++------ packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/roosterjs-editor-dom/lib/index.ts b/packages/roosterjs-editor-dom/lib/index.ts index a3cf735d771..d80022a90ba 100644 --- a/packages/roosterjs-editor-dom/lib/index.ts +++ b/packages/roosterjs-editor-dom/lib/index.ts @@ -50,9 +50,7 @@ export { default as VList } from './list/VList'; export { default as createVListFromRegion } from './list/createVListFromRegion'; export { default as getRegionsFromRange } from './region/getRegionsFromRange'; -export { - default as getSelectedBlockElementsInRegion, -} from './region/getSelectedBlockElementsInRegion'; +export { default as getSelectedBlockElementsInRegion } from './region/getSelectedBlockElementsInRegion'; export { default as collapseNodesInRegion } from './region/collapseNodesInRegion'; export { default as isNodeInRegion } from './region/isNodeInRegion'; @@ -73,9 +71,7 @@ export { default as createSnapshots } from './snapshots/createSnapshots'; export { default as HtmlSanitizer } from './htmlSanitizer/HtmlSanitizer'; export { default as htmlToDom, splitWithFragment } from './htmlSanitizer/htmlToDom'; export { default as getInheritableStyles } from './htmlSanitizer/getInheritableStyles'; -export { - default as createDefaultHtmlSanitizerOptions, -} from './htmlSanitizer/createDefaultHtmlSanitizerOptions'; +export { default as createDefaultHtmlSanitizerOptions } from './htmlSanitizer/createDefaultHtmlSanitizerOptions'; export { default as chainSanitizerCallback } from './htmlSanitizer/chainSanitizerCallback'; export { default as isDocumentFragment } from './typeUtils/isDocumentFragment'; diff --git a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts index aa19f066a09..c209b407333 100644 --- a/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts +++ b/packages/roosterjs-editor-dom/lib/utils/normalizeRect.ts @@ -5,7 +5,8 @@ import { Rect } from 'roosterjs-editor-types'; * We validate that and only return a rect when the passed in ClientRect is valid */ export default function normalizeRect(clientRect: ClientRect): Rect { - let { left, right, top, bottom } = clientRect || {}; + let { left, right, top, bottom } = + clientRect || { left: 0, right: 0, top: 0, bottom: 0 }; return left + right + top + bottom > 0 ? { left: Math.round(left), From c9f6d24b8d08f9a95851846edc8b478249011191 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Tue, 11 Aug 2020 17:09:16 -0700 Subject: [PATCH 19/20] Use requestAnimationFrame instead of throttling and remove lodash dependency --- package.json | 3 +-- .../lib/plugins/TableResize/TableResize.ts | 13 ++++++++----- yarn.lock | 5 ----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index d5db981f14b..e272627d033 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "karma-phantomjs-launcher": "1.0.4", "karma-sourcemap-loader": "0.3.7", "karma-webpack": "4.0.2", - "lodash": "^4.17.10", "prettier": "2.0.5", "pretty-quick": "^2.0.1", "progress": "2.0.3", @@ -70,4 +69,4 @@ "pre-commit": "pretty-quick --staged" } } -} +} \ No newline at end of file diff --git a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts index c0b20c010d1..a4dfe3e0eda 100644 --- a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts @@ -8,7 +8,6 @@ import { TableOperation, ContentPosition, } from 'roosterjs-editor-types'; -const throttle = require('lodash').throttle; const INSERTER_COLOR = '#4A4A4A'; const INSERTER_SIDE_LENGTH = 12; @@ -39,6 +38,7 @@ export default class TableResize implements EditorPlugin { private horizontalResizer: HTMLDivElement; private verticalResizer: HTMLDivElement; private resizingState: ResizeState = ResizeState.None; + private resizeTableAnimationFrameID: number; private currentInsertTd: HTMLTableCellElement; private insertingState: ResizeState = ResizeState.None; @@ -323,11 +323,13 @@ export default class TableResize implements EditorPlugin { private startResizeTable(e: MouseEvent) { const doc = this.editor.getDocument(); - doc.addEventListener('mousemove', this.throttledResizeTable, true); + doc.addEventListener('mousemove', this.frameAnimateResizeTable, true); doc.addEventListener('mouseup', this.endResizeTable, true); } - private throttledResizeTable = (e: MouseEvent) => throttle(this.resizeTable, 500)(e); + private frameAnimateResizeTable = (e: MouseEvent) => { + this.resizeTableAnimationFrameID = requestAnimationFrame(() => this.resizeTable(e)); + }; private resizeTable = (e: MouseEvent) => { if (this.currentTd) { @@ -360,11 +362,12 @@ export default class TableResize implements EditorPlugin { private endResizeTable = (e: MouseEvent) => { const doc = this.editor.getDocument(); - doc.removeEventListener('mousemove', this.throttledResizeTable, true); + doc.removeEventListener('mousemove', this.frameAnimateResizeTable, true); doc.removeEventListener('mouseup', this.endResizeTable, true); + cancelAnimationFrame(this.resizeTableAnimationFrameID); this.editor.addUndoSnapshot((start, end) => { - this.resizeTable(e); + this.frameAnimateResizeTable(e); this.editor.select(start, end); }, ChangeSource.Format); diff --git a/yarn.lock b/yarn.lock index 08626a21de6..a60aff566d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3312,11 +3312,6 @@ lodash@^4.0.0, lodash@^4.0.1, lodash@^4.17.11, lodash@~4.17.10: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== -lodash@^4.17.10: - version "4.17.19" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== - lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" From 289614d0182011a506f7c28319a677d140abc224 Mon Sep 17 00:00:00 2001 From: Melina Sparks Date: Wed, 12 Aug 2020 14:43:02 -0700 Subject: [PATCH 20/20] Use the editor.runasync --- .../lib/plugins/TableResize/TableResize.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts index a4dfe3e0eda..1c6d5919c33 100644 --- a/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts +++ b/packages/roosterjs-editor-plugins/lib/plugins/TableResize/TableResize.ts @@ -38,7 +38,6 @@ export default class TableResize implements EditorPlugin { private horizontalResizer: HTMLDivElement; private verticalResizer: HTMLDivElement; private resizingState: ResizeState = ResizeState.None; - private resizeTableAnimationFrameID: number; private currentInsertTd: HTMLTableCellElement; private insertingState: ResizeState = ResizeState.None; @@ -72,6 +71,10 @@ export default class TableResize implements EditorPlugin { this.editor = null; } + /** + * Handle events triggered from editor + * @param event PluginEvent object + */ onPluginEvent(e: PluginEvent) { switch (e.eventType) { case PluginEventType.Input: @@ -328,7 +331,7 @@ export default class TableResize implements EditorPlugin { } private frameAnimateResizeTable = (e: MouseEvent) => { - this.resizeTableAnimationFrameID = requestAnimationFrame(() => this.resizeTable(e)); + this.editor.runAsync(() => this.resizeTable(e)); }; private resizeTable = (e: MouseEvent) => { @@ -364,7 +367,6 @@ export default class TableResize implements EditorPlugin { const doc = this.editor.getDocument(); doc.removeEventListener('mousemove', this.frameAnimateResizeTable, true); doc.removeEventListener('mouseup', this.endResizeTable, true); - cancelAnimationFrame(this.resizeTableAnimationFrameID); this.editor.addUndoSnapshot((start, end) => { this.frameAnimateResizeTable(e);