@atlaskit/editor-plugin-selection-extension
Version:
editor-plugin-selection-extension plugin for @atlaskit/editor-core
212 lines (209 loc) • 8.71 kB
JavaScript
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
};
}