UNPKG

@atlaskit/editor-plugin-selection-extension

Version:

editor-plugin-selection-extension plugin for @atlaskit/editor-core

212 lines (209 loc) 8.71 kB
import { logException } from '@atlaskit/editor-common/monitoring'; import { JSONTransformer } from '@atlaskit/editor-json-transformer'; import { Fragment } from '@atlaskit/editor-prosemirror/model'; import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state'; import { Transform } from '@atlaskit/editor-prosemirror/transform'; import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles'; import { CellSelection, TableMap } from '@atlaskit/editor-tables'; import { fg } from '@atlaskit/platform-feature-flags'; import { getBoundingBoxFromSelection } from '../../ui/getBoundingBoxFromSelection'; import { getSelectionInfo, getSelectionInfoFromSameNode } from './selection-helpers'; const getSelectedRect = selection => { const { $anchorCell, $headCell } = selection; const table = $anchorCell.node(-1); const map = TableMap.get(table); const start = $anchorCell.start(-1); const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start); return rect; }; const getSelectionInfoFromCellSelection = selection => { const selectedNode = selection.$anchorCell.node(-1); const nodePos = selection.$anchorCell.before(-1); const selectionRanges = []; const rect = getSelectedRect(selection); for (let row = rect.top; row < rect.bottom; row++) { selectionRanges.push({ start: { pointer: `/content/${row}/content/${rect.left}` }, end: { pointer: `/content/${row}/content/${rect.right - 1}` } }); } return { selectedNode, selectionRanges, nodePos }; }; /** * @private * @deprecated use getSelectionTextInfoNew instead */ export const getSelectionTextInfo = (view, api) => { var _api$userPreferences, _api$userPreferences$, _api$userPreferences$2, _api$editorViewMode, _api$editorViewMode$s; const { selection: currentSelection } = view.state; const toolbarDocking = api === null || api === void 0 ? void 0 : (_api$userPreferences = api.userPreferences) === null || _api$userPreferences === void 0 ? void 0 : (_api$userPreferences$ = _api$userPreferences.sharedState.currentState()) === null || _api$userPreferences$ === void 0 ? void 0 : (_api$userPreferences$2 = _api$userPreferences$.preferences) === null || _api$userPreferences$2 === void 0 ? void 0 : _api$userPreferences$2.toolbarDockingPosition; const isEditMode = Boolean((api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode) === 'edit'); const shouldOffsetToolbarHeight = toolbarDocking === 'top' && isEditMode; const { from, to } = currentSelection; const text = view.state.doc.textBetween(from, to, '\n'); const coords = getBoundingBoxFromSelection(view, from, to, { top: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0, bottom: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0 }); return { text, from, to, coords }; }; export const getSelectionTextInfoNew = (selection, view, api) => { var _api$userPreferences2, _api$userPreferences3, _api$userPreferences4, _api$selectionToolbar, _api$selectionToolbar2, _api$selectionToolbar3, _api$editorViewMode2, _api$editorViewMode2$; const toolbarDocking = fg('platform_editor_use_preferences_plugin') ? api === null || api === void 0 ? void 0 : (_api$userPreferences2 = api.userPreferences) === null || _api$userPreferences2 === void 0 ? void 0 : (_api$userPreferences3 = _api$userPreferences2.sharedState.currentState()) === null || _api$userPreferences3 === void 0 ? void 0 : (_api$userPreferences4 = _api$userPreferences3.preferences) === null || _api$userPreferences4 === void 0 ? void 0 : _api$userPreferences4.toolbarDockingPosition : api === null || api === void 0 ? void 0 : (_api$selectionToolbar = api.selectionToolbar) === null || _api$selectionToolbar === void 0 ? void 0 : (_api$selectionToolbar2 = _api$selectionToolbar.sharedState) === null || _api$selectionToolbar2 === void 0 ? void 0 : (_api$selectionToolbar3 = _api$selectionToolbar2.currentState()) === null || _api$selectionToolbar3 === void 0 ? void 0 : _api$selectionToolbar3.toolbarDocking; const isEditMode = Boolean((api === null || api === void 0 ? void 0 : (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : (_api$editorViewMode2$ = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2$ === void 0 ? void 0 : _api$editorViewMode2$.mode) === 'edit'); const shouldOffsetToolbarHeight = toolbarDocking === 'top' && isEditMode; const { from, to } = selection; const text = view.state.doc.textBetween(from, to, '\n'); const coords = getBoundingBoxFromSelection(view, from, to, { top: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0, bottom: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0 }); return { text, from, to, coords }; }; /** * @private * @deprecated use getFragmentInfoFromSelectionNew instead */ export const getFragmentInfoFromSelection = state => { const { schema, selection } = state; const slice = selection.content(); let newDoc; try { const { schema } = state; const doc = schema.node('doc', null, [schema.node('paragraph', null, [])]); const transform = new Transform(doc); newDoc = transform.replaceRange(0, 2, slice).doc; } catch (error) { newDoc = schema.nodes.doc.createChecked({}, Fragment.empty); logException(error, { location: 'editor-plugin-selection-extension' }); } const serializer = new JSONTransformer(); const selectedNodeAdf = serializer.encodeNode(newDoc); return { selectedNodeAdf }; }; export const getFragmentInfoFromSelectionNew = selection => { const { schema } = selection.$from.doc.type; const slice = selection.content(); let newDoc; try { const doc = schema.node('doc', null, [schema.node('paragraph', null, [])]); const transform = new Transform(doc); newDoc = transform.replaceRange(0, 2, slice).doc; } catch (error) { newDoc = schema.nodes.doc.createChecked({}, Fragment.empty); logException(error, { location: 'editor-plugin-selection-extension' }); } const serializer = new JSONTransformer(); const selectedNodeAdf = serializer.encodeNode(newDoc); return { selectedNodeAdf }; }; /** * @private * @deprecated use getSelectionAdfInfoNew instead */ export function getSelectionAdfInfo(state) { const selection = state.selection; let selectionInfo = { selectedNode: selection.$from.node(), nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from }; if (selection instanceof TextSelection) { if (fg('platform_editor_selection_extension_improvement')) { // New implementation: unified handler for all text selections selectionInfo = getSelectionInfo(selection, state.schema); } else { const { $from, $to } = selection; if ($from.parent === $to.parent) { selectionInfo = getSelectionInfoFromSameNode(selection); } } } else if (selection instanceof CellSelection) { selectionInfo = getSelectionInfoFromCellSelection(selection); } const serializer = new JSONTransformer(); const selectedNodeAdf = serializer.encodeNode(selectionInfo.selectedNode); return { ...selectionInfo, selectedNodeAdf }; } export function getSelectionAdfInfoNew(selection) { const schema = selection.$from.doc.type.schema; let selectionInfo = { selectedNode: selection.$from.node(), nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from }; if (selection instanceof TextSelection) { if (fg('platform_editor_selection_extension_improvement')) { selectionInfo = getSelectionInfo(selection, schema); } else { const { $from, $to } = selection; if ($from.parent === $to.parent && $from.depth > 0) { selectionInfo = getSelectionInfoFromSameNode(selection); } } } else if (selection instanceof CellSelection) { selectionInfo = getSelectionInfoFromCellSelection(selection); } else if (selection instanceof NodeSelection) { selectionInfo = { selectedNode: selection.node, nodePos: selection.from }; } const serializer = new JSONTransformer(); const selectedNodeAdf = serializer.encodeNode(selectionInfo.selectedNode); return { ...selectionInfo, selectedNodeAdf }; }