|
@@ -13,75 +13,147 @@ import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
|
|
|
import { findAncestor } from '../commands/utils';
|
|
import { findAncestor } from '../commands/utils';
|
|
|
import MouseEventsObserver from './mouseeventsobserver';
|
|
import MouseEventsObserver from './mouseeventsobserver';
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * A mouse selection handler for table selection.
|
|
|
|
|
+ *
|
|
|
|
|
+ * It observes view document mouse events and invokes proper {@link module:table/tableselection~TableSelection} actions.
|
|
|
|
|
+ */
|
|
|
export default class MouseSelectionHandler {
|
|
export default class MouseSelectionHandler {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Creates instance of `MouseSelectionHandler`.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {module:table/tableselection~TableSelection} tableSelection
|
|
|
|
|
+ * @param {module:engine/controller/editingcontroller~EditingController} editing
|
|
|
|
|
+ */
|
|
|
constructor( tableSelection, editing ) {
|
|
constructor( tableSelection, editing ) {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Table selection.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @readonly
|
|
|
|
|
+ * @member {module:table/tableselection~TableSelection}
|
|
|
|
|
+ */
|
|
|
|
|
+ this._tableSelection = tableSelection;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Editing mapper.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @readonly
|
|
|
|
|
+ * @member {module:engine/conversion/mapper~Mapper}
|
|
|
|
|
+ */
|
|
|
|
|
+ this._mapper = editing.mapper;
|
|
|
|
|
+
|
|
|
const view = editing.view;
|
|
const view = editing.view;
|
|
|
- const viewDocument = view.document;
|
|
|
|
|
- const mapper = editing.mapper;
|
|
|
|
|
|
|
|
|
|
|
|
+ // Currently the MouseObserver only handles `mouseup` events.
|
|
|
view.addObserver( MouseEventsObserver );
|
|
view.addObserver( MouseEventsObserver );
|
|
|
|
|
|
|
|
- this.listenTo( viewDocument, 'mousedown', ( eventInfo, domEventData ) => {
|
|
|
|
|
- const tableCell = getModelTableCellFromViewEvent( domEventData, mapper );
|
|
|
|
|
-
|
|
|
|
|
- if ( !tableCell ) {
|
|
|
|
|
- tableSelection.stopSelection();
|
|
|
|
|
- tableSelection.clearSelection();
|
|
|
|
|
-
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- tableSelection.startSelectingFrom( tableCell );
|
|
|
|
|
- } );
|
|
|
|
|
-
|
|
|
|
|
- this.listenTo( viewDocument, 'mousemove', ( eventInfo, domEventData ) => {
|
|
|
|
|
- if ( !tableSelection._isSelecting ) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const tableCell = getModelTableCellFromViewEvent( domEventData, mapper );
|
|
|
|
|
-
|
|
|
|
|
- if ( !tableCell ) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- tableSelection.setSelectingTo( tableCell );
|
|
|
|
|
- } );
|
|
|
|
|
-
|
|
|
|
|
- this.listenTo( viewDocument, 'mouseup', ( eventInfo, domEventData ) => {
|
|
|
|
|
- if ( !tableSelection._isSelecting ) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const tableCell = getModelTableCellFromViewEvent( domEventData, mapper );
|
|
|
|
|
-
|
|
|
|
|
- tableSelection.stopSelection( tableCell );
|
|
|
|
|
- } );
|
|
|
|
|
-
|
|
|
|
|
- this.listenTo( viewDocument, 'mouseleave', () => {
|
|
|
|
|
- if ( !tableSelection._isSelecting ) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- tableSelection.stopSelection();
|
|
|
|
|
- } );
|
|
|
|
|
|
|
+ this.listenTo( view.document, 'mousedown', ( eventInfo, domEventData ) => this._handleMouseDown( domEventData ) );
|
|
|
|
|
+ this.listenTo( view.document, 'mousemove', ( eventInfo, domEventData ) => this._handleMouseMove( domEventData ) );
|
|
|
|
|
+ this.listenTo( view.document, 'mouseup', ( eventInfo, domEventData ) => this._handleMouseUp( domEventData ) );
|
|
|
|
|
+ this.listenTo( view.document, 'mouseleave', () => this._handleMouseLeave() );
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-mix( MouseSelectionHandler, ObservableMixin );
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handles starting a selection when "mousedown" event has table cell target.
|
|
|
|
|
+ *
|
|
|
|
|
+ * If no table cell in event target it will clear previous selection.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
|
|
|
+ * @private
|
|
|
|
|
+ */
|
|
|
|
|
+ _handleMouseDown( domEventData ) {
|
|
|
|
|
+ const tableCell = this._getModelTableCellFromDomEvent( domEventData );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !tableCell ) {
|
|
|
|
|
+ this._tableSelection.stopSelection();
|
|
|
|
|
+ this._tableSelection.clearSelection();
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this._tableSelection.startSelectingFrom( tableCell );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-// Finds model table cell for given DOM event - ie. for 'mousedown'.
|
|
|
|
|
-function getModelTableCellFromViewEvent( domEventData, mapper ) {
|
|
|
|
|
- const viewTargetElement = domEventData.target;
|
|
|
|
|
- const modelElement = mapper.toModelElement( viewTargetElement );
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handles updating table selection when "mousemove" event has a table cell target.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Does nothing if no table cell in event target or selection is not started.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
|
|
|
+ * @private
|
|
|
|
|
+ */
|
|
|
|
|
+ _handleMouseMove( domEventData ) {
|
|
|
|
|
+ if ( !this._tableSelection._isSelecting ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const tableCell = this._getModelTableCellFromDomEvent( domEventData );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !tableCell ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this._tableSelection.setSelectingTo( tableCell );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if ( !modelElement ) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handles ending (not clearing) table selection on "mouseup" event.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Does nothing if selection is not started.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
|
|
|
+ * @private
|
|
|
|
|
+ */
|
|
|
|
|
+ _handleMouseUp( domEventData ) {
|
|
|
|
|
+ if ( !this._tableSelection._isSelecting ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const tableCell = this._getModelTableCellFromDomEvent( domEventData );
|
|
|
|
|
+
|
|
|
|
|
+ // Selection can be stopped if table cell is undefined.
|
|
|
|
|
+ this._tableSelection.stopSelection( tableCell );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ( modelElement.is( 'tableCell' ) ) {
|
|
|
|
|
- return modelElement;
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handles stopping a selection on "mouseleave" event.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Does nothing if selection is not started.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ */
|
|
|
|
|
+ _handleMouseLeave() {
|
|
|
|
|
+ if ( !this._tableSelection._isSelecting ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this._tableSelection.stopSelection();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return findAncestor( 'tableCell', modelElement );
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Finds model table cell for given DOM event.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
|
|
|
+ * @returns {module:engine/model/element~Element|undefined} Returns model table cell or undefined event target is not
|
|
|
|
|
+ * a mapped table cell.
|
|
|
|
|
+ */
|
|
|
|
|
+ _getModelTableCellFromDomEvent( domEventData ) {
|
|
|
|
|
+ const viewTargetElement = domEventData.target;
|
|
|
|
|
+ const modelElement = this._mapper.toModelElement( viewTargetElement );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !modelElement ) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( modelElement.is( 'tableCell' ) ) {
|
|
|
|
|
+ return modelElement;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return findAncestor( 'tableCell', modelElement );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+mix( MouseSelectionHandler, ObservableMixin );
|