-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Standalone Editor step 2 * Standalone Editor step 3 * improve * Standalone Editor step 4 * Standalone Editor: Remove compatible enums from standalone editor * improve * Standalone Editor: Create new event types * Port to new event system * Revert "Port to new event system" This reverts commit 60cf041. * Port to new event system * Improve * fix build * fix demo * Fix buttons * fix build * fix build * fix build * plugin added to cm demo site * pluginUtils imported * IStandaloneEditor changes * editTable can skip undo snapshot * TableEditPlugin port start * move D&D to folder * add plugin to Standalone demo and remove old plugin * demo fix * rename D&D and fix import * demo site changes * rename selector to mover * new plugin utils, organisation * isMobileOrTablet * cleanup * normalise width too * remove onShowHelperElement, fix containment, instancing, others * implement cell resizer * fix type import * fix selection * fix imports * fix instanceof, use formatTableWithContentModel, getDOMHelper * fix merge * small fix * fix table resize functionality * fix merge * fix import * fix dependency * fix exports * merge fix * export MIN_WIDTH * fix resizers * add check * fix color * fix instanceof * change IStandaloneEditor to IEditor * fix export const * rename const * fix cell resizer, add ids * add tests * fix build issues --------- Co-authored-by: Jiuqing Song <jisong@microsoft.com>
- Loading branch information
1 parent
78b498a
commit c950e5b
Showing
27 changed files
with
3,475 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages-content-model/roosterjs-content-model-plugins/lib/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { TableEditPlugin } from './tableEdit/TableEditPlugin'; | ||
export { PastePlugin } from './paste/PastePlugin'; | ||
export { EditPlugin } from './edit/EditPlugin'; | ||
export { AutoFormatPlugin, AutoFormatOptions } from './autoFormat/AutoFormatPlugin'; |
175 changes: 175 additions & 0 deletions
175
packages-content-model/roosterjs-content-model-plugins/lib/tableEdit/TableEditPlugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import normalizeRect from '../pluginUtils/Rect/normalizeRect'; | ||
import TableEditor from './editors/TableEditor'; | ||
import { isNodeOfType } from 'roosterjs-content-model-dom'; | ||
import type { EditorPlugin, IEditor, PluginEvent, Rect } from 'roosterjs-content-model-types'; | ||
|
||
const TABLE_RESIZER_LENGTH = 12; | ||
|
||
/** | ||
* TableEdit plugin, provides the ability to resize a table by drag-and-drop | ||
*/ | ||
export class TableEditPlugin implements EditorPlugin { | ||
private editor: IEditor | null = null; | ||
private onMouseMoveDisposer: (() => void) | null = null; | ||
private tableRectMap: { table: HTMLTableElement; rect: Rect }[] | null = null; | ||
private tableEditor: TableEditor | null = null; | ||
|
||
/** | ||
* Construct a new instance of TableResize plugin | ||
* @param anchorContainerSelector An optional selector string to specify the container to host the plugin. | ||
* The container must not be affected by transform: scale(), otherwise the position calculation will be wrong. | ||
* If not specified, the plugin will be inserted in document.body | ||
*/ | ||
constructor(private anchorContainerSelector?: string) {} | ||
|
||
/** | ||
* Get a friendly name of this plugin | ||
*/ | ||
getName() { | ||
return 'TableEdit'; | ||
} | ||
|
||
/** | ||
* Initialize this plugin. This should only be called from Editor | ||
* @param editor Editor instance | ||
*/ | ||
initialize(editor: IEditor) { | ||
this.editor = editor; | ||
this.onMouseMoveDisposer = this.editor.attachDomEvent({ | ||
mousemove: { beforeDispatch: this.onMouseMove }, | ||
}); | ||
const scrollContainer = this.editor.getScrollContainer(); | ||
scrollContainer.addEventListener('mouseout', this.onMouseOut); | ||
} | ||
|
||
private onMouseOut = ({ relatedTarget, currentTarget }: MouseEvent) => { | ||
const relatedTargetNode = relatedTarget as Node; | ||
const currentTargetNode = currentTarget as Node; | ||
if ( | ||
isNodeOfType(relatedTargetNode, 'ELEMENT_NODE') && | ||
isNodeOfType(currentTargetNode, 'ELEMENT_NODE') && | ||
this.tableEditor && | ||
!this.tableEditor.isOwnedElement(relatedTargetNode) && | ||
!currentTargetNode.contains(relatedTargetNode) | ||
) { | ||
this.setTableEditor(null); | ||
} | ||
}; | ||
|
||
/** | ||
* Dispose this plugin | ||
*/ | ||
dispose() { | ||
const scrollContainer = this.editor?.getScrollContainer(); | ||
scrollContainer?.removeEventListener('mouseout', this.onMouseOut); | ||
this.onMouseMoveDisposer?.(); | ||
this.invalidateTableRects(); | ||
this.disposeTableEditor(); | ||
this.editor = null; | ||
this.onMouseMoveDisposer = null; | ||
} | ||
|
||
/** | ||
* Handle events triggered from editor | ||
* @param event PluginEvent object | ||
*/ | ||
onPluginEvent(e: PluginEvent) { | ||
switch (e.eventType) { | ||
case 'input': | ||
case 'contentChanged': | ||
case 'scroll': | ||
case 'zoomChanged': | ||
this.setTableEditor(null); | ||
this.invalidateTableRects(); | ||
break; | ||
} | ||
} | ||
|
||
private onMouseMove = (event: Event) => { | ||
const e = event as MouseEvent; | ||
|
||
if (e.buttons > 0 || !this.editor) { | ||
return; | ||
} | ||
|
||
this.ensureTableRects(); | ||
|
||
const editorWindow = this.editor.getDocument().defaultView || window; | ||
const x = e.pageX - editorWindow.scrollX; | ||
const y = e.pageY - editorWindow.scrollY; | ||
let currentTable: HTMLTableElement | null = null; | ||
|
||
//Find table in range of mouse | ||
if (this.tableRectMap) { | ||
for (let i = this.tableRectMap.length - 1; i >= 0; i--) { | ||
const { table, rect } = this.tableRectMap[i]; | ||
|
||
if ( | ||
x >= rect.left - TABLE_RESIZER_LENGTH && | ||
x <= rect.right + TABLE_RESIZER_LENGTH && | ||
y >= rect.top - TABLE_RESIZER_LENGTH && | ||
y <= rect.bottom + TABLE_RESIZER_LENGTH | ||
) { | ||
currentTable = table; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
this.setTableEditor(currentTable, e); | ||
this.tableEditor?.onMouseMove(x, y); | ||
}; | ||
|
||
/** | ||
* @internal Public only for unit test | ||
* @param table Table to use when setting the Editors | ||
* @param event (Optional) Mouse event | ||
*/ | ||
public setTableEditor(table: HTMLTableElement | null, event?: MouseEvent) { | ||
if (this.tableEditor && !this.tableEditor.isEditing() && table != this.tableEditor.table) { | ||
this.disposeTableEditor(); | ||
} | ||
|
||
if (!this.tableEditor && table && this.editor && table.rows.length > 0) { | ||
const container = this.anchorContainerSelector | ||
? this.editor.getDOMHelper().queryElements(this.anchorContainerSelector)[0] | ||
: undefined; | ||
|
||
this.tableEditor = new TableEditor( | ||
this.editor, | ||
table, | ||
this.invalidateTableRects, | ||
isNodeOfType(container as Node, 'ELEMENT_NODE') ? container : undefined, | ||
event?.currentTarget | ||
); | ||
} | ||
} | ||
|
||
private invalidateTableRects = () => { | ||
this.tableRectMap = null; | ||
}; | ||
|
||
private disposeTableEditor() { | ||
this.tableEditor?.dispose(); | ||
this.tableEditor = null; | ||
} | ||
|
||
private ensureTableRects() { | ||
if (!this.tableRectMap && this.editor) { | ||
this.tableRectMap = []; | ||
|
||
const tables = this.editor.getDOMHelper().queryElements('table'); | ||
tables.forEach(table => { | ||
if (table.isContentEditable) { | ||
const rect = normalizeRect(table.getBoundingClientRect()); | ||
if (rect && this.tableRectMap) { | ||
this.tableRectMap.push({ | ||
table, | ||
rect, | ||
}); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
} |
Oops, something went wrong.