Skip to content

Commit

Permalink
feat(blocks): supports pasting a URL from clipboard to automatically …
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Dec 17, 2024
1 parent d406ee2 commit a675ff4
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 7 deletions.
2 changes: 1 addition & 1 deletion packages/blocks/src/root-block/clipboard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class PageClipboard {
this._std.command
.chain()
.try(cmd => [
cmd.getTextSelection().deleteText(),
cmd.getTextSelection(),
cmd
.getSelectedModels()
.clearAndSelectFirstModel()
Expand Down
30 changes: 24 additions & 6 deletions packages/blocks/src/root-block/clipboard/middlewares/paste.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';

import { REFERENCE_NODE } from '@blocksuite/affine-components/rich-text';
import {
ParseDocUrlProvider,
type ParseDocUrlService,
Expand Down Expand Up @@ -154,10 +156,19 @@ class PasteTr {
private _mergeSingle = () => {
this._updateFlavour();
const { firstDelta } = this._getDeltas();
this.pointState.text.applyDelta([
{ retain: this.pointState.point.index },
...firstDelta,
]);
const { index, length } = this.pointState.point;

// Pastes a link
if (length && firstDelta.length === 1 && firstDelta[0].attributes?.link) {
this.pointState.text.format(index, length, firstDelta[0].attributes);
} else {
const ops: DeltaOperation[] = [{ retain: index }];
if (length) ops.push({ delete: length });
ops.push(...firstDelta);

this.pointState.text.applyDelta(ops);
}

this.snapshot.content.splice(0, 1);
this._updateSnapshot();
};
Expand Down Expand Up @@ -424,7 +435,14 @@ class PasteTr {
return { ...op };
}

const reference = { pageId, type: 'LinkedPage' };
const reference: AffineTextAttributes['reference'] = {
pageId,
type: 'LinkedPage',
};
// Title alias
if (op.insert && op.insert !== REFERENCE_NODE && op.insert !== link) {
reference.title = op.insert;
}

const extractedParams = extractSearchParams(link);
const isLinkedBlock = extractedParams
Expand All @@ -446,7 +464,7 @@ class PasteTr {
return {
...op,
attributes: { reference },
insert: ' ',
insert: REFERENCE_NODE,
};
});
return [newDelta, transformed];
Expand Down
42 changes: 42 additions & 0 deletions tests/clipboard/clipboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,48 @@ test(scoped`pasting internal url with params`, async ({ page }) => {
await expect(page.locator('affine-reference')).toContainText('test page');
});

test(
scoped`pasting an external URL from clipboard to automatically creating a link from selection`,
async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await focusTitle(page);
await type(page, 'test page');

await focusRichText(page);
await type(page, 'title alias');
await setSelection(page, 1, 6, 1, 11);

await pasteContent(page, {
'text/plain': 'https://affine.pro/',
});
await expect(page.locator('affine-link')).toContainText('alias');
}
);

test(
scoped`pasting an internal URL from clipboard to automatically creating a link from selection`,
async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await focusTitle(page);
await type(page, 'test page');

await focusRichText(page);
await type(page, 'title alias');
await setSelection(page, 1, 6, 1, 11);

const docId = await getCurrentEditorDocId(page);
await mockParseDocUrlService(page, {
'http://workspace/doc-id': docId,
});
await pasteContent(page, {
'text/plain': 'http://workspace/doc-id',
});
await expect(page.locator('affine-reference')).toContainText('alias');
}
);

test(scoped`paste parent block`, async ({ page }) => {
test.info().annotations.push({
type: 'issue',
Expand Down

0 comments on commit a675ff4

Please sign in to comment.