mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-12 15:46:29 +08:00
205cd7a86d
Closes: BS-2946
136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
import type { BaseTextAttributes, DeltaInsert } from '@blocksuite/store';
|
|
|
|
import type { InlineEditor } from '../inline-editor.js';
|
|
import type { InlineRange } from '../types.js';
|
|
import { intersectInlineRange } from '../utils/inline-range.js';
|
|
|
|
export class InlineTextService<TextAttributes extends BaseTextAttributes> {
|
|
deleteText = (inlineRange: InlineRange): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
this.transact(() => {
|
|
this.yText.delete(inlineRange.index, inlineRange.length);
|
|
});
|
|
};
|
|
|
|
formatText = (
|
|
inlineRange: InlineRange,
|
|
attributes: TextAttributes,
|
|
options: {
|
|
match?: (delta: DeltaInsert, deltaInlineRange: InlineRange) => boolean;
|
|
mode?: 'replace' | 'merge';
|
|
} = {}
|
|
): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
const { match = () => true, mode = 'merge' } = options;
|
|
const deltas = this.editor.deltaService.getDeltasByInlineRange(inlineRange);
|
|
|
|
deltas
|
|
.filter(([delta, deltaInlineRange]) => match(delta, deltaInlineRange))
|
|
.forEach(([_delta, deltaInlineRange]) => {
|
|
const normalizedAttributes =
|
|
this.editor.attributeService.normalizeAttributes(attributes);
|
|
if (!normalizedAttributes) return;
|
|
|
|
const targetInlineRange = intersectInlineRange(
|
|
inlineRange,
|
|
deltaInlineRange
|
|
);
|
|
if (!targetInlineRange) return;
|
|
|
|
if (mode === 'replace') {
|
|
this.resetText(targetInlineRange);
|
|
}
|
|
|
|
this.transact(() => {
|
|
this.yText.format(
|
|
targetInlineRange.index,
|
|
targetInlineRange.length,
|
|
normalizedAttributes
|
|
);
|
|
});
|
|
});
|
|
};
|
|
|
|
insertLineBreak = (inlineRange: InlineRange): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
this.transact(() => {
|
|
this.yText.delete(inlineRange.index, inlineRange.length);
|
|
this.yText.insert(inlineRange.index, '\n');
|
|
});
|
|
};
|
|
|
|
insertText = (
|
|
inlineRange: InlineRange,
|
|
text: string,
|
|
attributes: TextAttributes = {} as TextAttributes
|
|
): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
if (!text || !text.length) return;
|
|
|
|
if (this.editor.attributeService.marks) {
|
|
attributes = { ...attributes, ...this.editor.attributeService.marks };
|
|
}
|
|
const normalizedAttributes =
|
|
this.editor.attributeService.normalizeAttributes(attributes);
|
|
|
|
this.transact(() => {
|
|
this.yText.delete(inlineRange.index, inlineRange.length);
|
|
this.yText.insert(inlineRange.index, text, normalizedAttributes);
|
|
});
|
|
};
|
|
|
|
resetText = (inlineRange: InlineRange): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
const coverDeltas: DeltaInsert[] = [];
|
|
for (
|
|
let i = inlineRange.index;
|
|
i <= inlineRange.index + inlineRange.length;
|
|
i++
|
|
) {
|
|
const delta = this.editor.getDeltaByRangeIndex(i);
|
|
if (delta) {
|
|
coverDeltas.push(delta);
|
|
}
|
|
}
|
|
|
|
const unset = Object.fromEntries(
|
|
coverDeltas.flatMap(delta =>
|
|
delta.attributes
|
|
? Object.keys(delta.attributes).map(key => [key, null])
|
|
: []
|
|
)
|
|
);
|
|
|
|
this.transact(() => {
|
|
this.yText.format(inlineRange.index, inlineRange.length, {
|
|
...unset,
|
|
});
|
|
});
|
|
};
|
|
|
|
setText = (
|
|
text: string,
|
|
attributes: TextAttributes = {} as TextAttributes
|
|
): void => {
|
|
if (this.editor.isReadonly) return;
|
|
|
|
this.transact(() => {
|
|
this.yText.delete(0, this.yText.length);
|
|
this.yText.insert(0, text, attributes);
|
|
});
|
|
};
|
|
|
|
readonly transact = this.editor.transact;
|
|
|
|
get yText() {
|
|
return this.editor.yText;
|
|
}
|
|
|
|
constructor(readonly editor: InlineEditor<TextAttributes>) {}
|
|
}
|