mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-29 00:06:09 +08:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
import { matchFlavours } from '@blocksuite/affine-shared/utils';
|
||||
import type { BlockComponent, BlockSelection } from '@blocksuite/block-std';
|
||||
import { IS_MAC, IS_WINDOWS } from '@blocksuite/global/env';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
|
||||
import {
|
||||
convertSelectedBlocksToLinkedDoc,
|
||||
getTitleFromSelectedModels,
|
||||
notifyDocCreated,
|
||||
promptDocTitle,
|
||||
} from '../../_common/utils/render-linked-doc.js';
|
||||
|
||||
export class PageKeyboardManager {
|
||||
private _handleDelete = () => {
|
||||
const blockSelections = this._currentSelection.filter(sel =>
|
||||
sel.is('block')
|
||||
);
|
||||
if (blockSelections.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._doc.transact(() => {
|
||||
const selection = this._replaceBlocksBySelection(
|
||||
blockSelections,
|
||||
'affine:paragraph',
|
||||
{}
|
||||
);
|
||||
|
||||
if (selection) {
|
||||
this._selection.setGroup('note', [
|
||||
this._selection.create('text', {
|
||||
from: {
|
||||
index: 0,
|
||||
length: 0,
|
||||
blockId: selection.blockId,
|
||||
},
|
||||
to: null,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
private get _currentSelection() {
|
||||
return this._selection.value;
|
||||
}
|
||||
|
||||
private get _doc() {
|
||||
return this.rootComponent.doc;
|
||||
}
|
||||
|
||||
private get _selection() {
|
||||
return this.rootComponent.host.selection;
|
||||
}
|
||||
|
||||
constructor(public rootComponent: BlockComponent) {
|
||||
this.rootComponent.bindHotKey(
|
||||
{
|
||||
'Mod-z': ctx => {
|
||||
ctx.get('defaultState').event.preventDefault();
|
||||
|
||||
if (this._doc.canUndo) {
|
||||
this._doc.undo();
|
||||
}
|
||||
},
|
||||
'Shift-Mod-z': ctx => {
|
||||
ctx.get('defaultState').event.preventDefault();
|
||||
if (this._doc.canRedo) {
|
||||
this._doc.redo();
|
||||
}
|
||||
},
|
||||
'Control-y': ctx => {
|
||||
if (!IS_WINDOWS) return;
|
||||
|
||||
ctx.get('defaultState').event.preventDefault();
|
||||
if (this._doc.canRedo) {
|
||||
this._doc.redo();
|
||||
}
|
||||
},
|
||||
'Mod-Backspace': () => true,
|
||||
Backspace: this._handleDelete,
|
||||
Delete: this._handleDelete,
|
||||
'Control-d': () => {
|
||||
if (!IS_MAC) return;
|
||||
this._handleDelete();
|
||||
},
|
||||
'Mod-Shift-l': () => {
|
||||
this._createEmbedBlock();
|
||||
},
|
||||
},
|
||||
{
|
||||
global: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _createEmbedBlock() {
|
||||
const rootComponent = this.rootComponent;
|
||||
const [_, ctx] = this.rootComponent.std.command
|
||||
.chain()
|
||||
.getSelectedModels({
|
||||
types: ['block'],
|
||||
mode: 'highest',
|
||||
})
|
||||
.draftSelectedModels()
|
||||
.run();
|
||||
const selectedModels = ctx.selectedModels?.filter(
|
||||
block =>
|
||||
!block.flavour.startsWith('affine:embed-') &&
|
||||
matchFlavours(doc.getParent(block), ['affine:note'])
|
||||
);
|
||||
|
||||
const draftedModels = ctx.draftedModels;
|
||||
if (!selectedModels?.length || !draftedModels) {
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = rootComponent.host.doc;
|
||||
const autofill = getTitleFromSelectedModels(selectedModels);
|
||||
void promptDocTitle(rootComponent.host, autofill).then(title => {
|
||||
if (title === null) return;
|
||||
convertSelectedBlocksToLinkedDoc(
|
||||
this.rootComponent.std,
|
||||
doc,
|
||||
draftedModels,
|
||||
title
|
||||
).catch(console.error);
|
||||
notifyDocCreated(rootComponent.host, doc);
|
||||
});
|
||||
}
|
||||
|
||||
private _deleteBlocksBySelection(selections: BlockSelection[]) {
|
||||
selections.forEach(selection => {
|
||||
const block = this._doc.getBlockById(selection.blockId);
|
||||
if (block) {
|
||||
this._doc.deleteBlock(block);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _replaceBlocksBySelection(
|
||||
selections: BlockSelection[],
|
||||
flavour: string,
|
||||
props: Record<string, unknown>
|
||||
) {
|
||||
const current = selections[0];
|
||||
const first = this._doc.getBlockById(current.blockId);
|
||||
const firstElement = this.rootComponent.host.view.getBlock(current.blockId);
|
||||
|
||||
assertExists(first, `Cannot find block ${current.blockId}`);
|
||||
assertExists(firstElement, `Cannot find block view ${current.blockId}`);
|
||||
|
||||
const parent = this._doc.getParent(first);
|
||||
const index = parent?.children.indexOf(first);
|
||||
|
||||
this._deleteBlocksBySelection(selections);
|
||||
|
||||
try {
|
||||
this._doc.schema.validate(flavour, parent?.flavour);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blockId = this._doc.addBlock(flavour as never, props, parent, index);
|
||||
|
||||
return {
|
||||
blockId,
|
||||
path: blockId,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user