|
@@ -9,9 +9,11 @@
|
|
|
|
|
|
|
|
import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
|
|
import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
|
|
|
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
|
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
|
|
|
|
+import Position from '@ckeditor/ckeditor5-engine/src/model/position';
|
|
|
|
|
|
|
|
import TableWalker from './tablewalker';
|
|
import TableWalker from './tablewalker';
|
|
|
import TableUtils from './tableutils';
|
|
import TableUtils from './tableutils';
|
|
|
|
|
+import { findAncestor } from './commands/utils';
|
|
|
|
|
|
|
|
export default class TableSelection extends Plugin {
|
|
export default class TableSelection extends Plugin {
|
|
|
/**
|
|
/**
|
|
@@ -38,24 +40,101 @@ export default class TableSelection extends Plugin {
|
|
|
this.tableUtils = editor.plugins.get( TableUtils );
|
|
this.tableUtils = editor.plugins.get( TableUtils );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ init() {
|
|
|
|
|
+ const editor = this.editor;
|
|
|
|
|
+ const viewDocument = editor.editing.view.document;
|
|
|
|
|
+
|
|
|
|
|
+ this.listenTo( viewDocument, 'mousedown', ( eventInfo, domEventData ) => {
|
|
|
|
|
+ const tableCell = getTableCell( domEventData, this.editor );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !tableCell ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.startSelection( tableCell );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ this.listenTo( viewDocument, 'mousemove', ( eventInfo, domEventData ) => {
|
|
|
|
|
+ if ( !this.isSelecting ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const tableCell = getTableCell( domEventData, this.editor );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !tableCell ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const wasOne = this.size === 1;
|
|
|
|
|
+
|
|
|
|
|
+ this.updateSelection( tableCell );
|
|
|
|
|
+
|
|
|
|
|
+ if ( this.size > 1 ) {
|
|
|
|
|
+ domEventData.preventDefault();
|
|
|
|
|
+
|
|
|
|
|
+ if ( wasOne ) {
|
|
|
|
|
+ editor.editing.view.change( writer => {
|
|
|
|
|
+ const viewElement = editor.editing.mapper.toViewElement( this._startElement );
|
|
|
|
|
+
|
|
|
|
|
+ writer.setSelection( ViewRange.createIn( viewElement ), {
|
|
|
|
|
+ fake: true,
|
|
|
|
|
+ label: 'fake selection over table cell'
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.redrawSelection();
|
|
|
|
|
+ }
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ this.listenTo( viewDocument, 'mouseup', ( eventInfo, domEventData ) => {
|
|
|
|
|
+ if ( !this.isSelecting ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const tableCell = getTableCell( domEventData, this.editor );
|
|
|
|
|
+
|
|
|
|
|
+ this.stopSelection( tableCell );
|
|
|
|
|
+ } );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
get isSelecting() {
|
|
get isSelecting() {
|
|
|
return this._isSelecting;
|
|
return this._isSelecting;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ get size() {
|
|
|
|
|
+ return [ ...this.getSelection() ].length;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
startSelection( tableCell ) {
|
|
startSelection( tableCell ) {
|
|
|
this.clearSelection();
|
|
this.clearSelection();
|
|
|
this._isSelecting = true;
|
|
this._isSelecting = true;
|
|
|
this._startElement = tableCell;
|
|
this._startElement = tableCell;
|
|
|
this._endElement = tableCell;
|
|
this._endElement = tableCell;
|
|
|
- this._redrawSelection();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
updateSelection( tableCell ) {
|
|
updateSelection( tableCell ) {
|
|
|
- if ( this.isSelecting && tableCell && tableCell.parent.parent === this._startElement.parent.parent ) {
|
|
|
|
|
- this._endElement = tableCell;
|
|
|
|
|
|
|
+ // Do not update if not in selection mode or no table cell passed.
|
|
|
|
|
+ if ( !this.isSelecting || !tableCell ) {
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- this._redrawSelection();
|
|
|
|
|
|
|
+ const table = this._startElement.parent.parent;
|
|
|
|
|
+
|
|
|
|
|
+ // Do not add tableCell to selection if it is from other table or is already set as end element.
|
|
|
|
|
+ if ( table !== tableCell.parent.parent || this._endElement === tableCell ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );
|
|
|
|
|
+ const startInHeading = this._startElement.parent.index < headingRows;
|
|
|
|
|
+ const updateCellInHeading = tableCell.parent.index < headingRows;
|
|
|
|
|
+
|
|
|
|
|
+ // Only add cell to selection if they are in the same table section.
|
|
|
|
|
+ if ( startInHeading === updateCellInHeading ) {
|
|
|
|
|
+ this._endElement = tableCell;
|
|
|
|
|
+ this.redrawSelection();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
stopSelection( tableCell ) {
|
|
stopSelection( tableCell ) {
|
|
@@ -64,14 +143,13 @@ export default class TableSelection extends Plugin {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this._isSelecting = false;
|
|
this._isSelecting = false;
|
|
|
- this._redrawSelection();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
clearSelection() {
|
|
clearSelection() {
|
|
|
this._startElement = undefined;
|
|
this._startElement = undefined;
|
|
|
this._endElement = undefined;
|
|
this._endElement = undefined;
|
|
|
this._isSelecting = false;
|
|
this._isSelecting = false;
|
|
|
- this.updateSelection();
|
|
|
|
|
|
|
+ this.clearPreviousSelection();
|
|
|
this._highlighted.clear();
|
|
this._highlighted.clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -100,7 +178,7 @@ export default class TableSelection extends Plugin {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _redrawSelection() {
|
|
|
|
|
|
|
+ redrawSelection() {
|
|
|
const viewRanges = [];
|
|
const viewRanges = [];
|
|
|
|
|
|
|
|
const selected = [ ...this.getSelection() ];
|
|
const selected = [ ...this.getSelection() ];
|
|
@@ -118,12 +196,37 @@ export default class TableSelection extends Plugin {
|
|
|
this.editor.editing.view.change( writer => {
|
|
this.editor.editing.view.change( writer => {
|
|
|
for ( const previouslyHighlighted of previous ) {
|
|
for ( const previouslyHighlighted of previous ) {
|
|
|
if ( !selected.includes( previouslyHighlighted ) ) {
|
|
if ( !selected.includes( previouslyHighlighted ) ) {
|
|
|
- // TODO: unify somewhere...
|
|
|
|
|
writer.removeClass( 'selected', previouslyHighlighted );
|
|
writer.removeClass( 'selected', previouslyHighlighted );
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ for ( const currently of this._highlighted ) {
|
|
|
|
|
+ writer.addClass( 'selected', currently );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // TODO works on FF ony... :|
|
|
|
writer.setSelection( viewRanges, { fake: true, label: 'fake selection over table cell' } );
|
|
writer.setSelection( viewRanges, { fake: true, label: 'fake selection over table cell' } );
|
|
|
} );
|
|
} );
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ clearPreviousSelection() {
|
|
|
|
|
+ const previous = [ ...this._highlighted.values() ];
|
|
|
|
|
+
|
|
|
|
|
+ this.editor.editing.view.change( writer => {
|
|
|
|
|
+ for ( const previouslyHighlighted of previous ) {
|
|
|
|
|
+ writer.removeClass( 'selected', previouslyHighlighted );
|
|
|
|
|
+ }
|
|
|
|
|
+ } );
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getTableCell( domEventData, editor ) {
|
|
|
|
|
+ const element = domEventData.target;
|
|
|
|
|
+ const modelElement = editor.editing.mapper.toModelElement( element );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !modelElement ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return findAncestor( 'tableCell', Position.createAt( modelElement ) );
|
|
|
}
|
|
}
|