File tree 5 files changed +130
-34
lines changed
packages/frontend/core/src
blocksuite/block-suite-editor/specs/custom
5 files changed +130
-34
lines changed Original file line number Diff line number Diff line change 5
5
} from '@affine/core/components/hooks/affine/use-share-url' ;
6
6
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch' ;
7
7
import { EditorService } from '@affine/core/modules/editor' ;
8
+ import { copyLinkToBlockStdScopeClipboard } from '@affine/core/utils/clipboard' ;
8
9
import { I18n } from '@affine/i18n' ;
9
10
import { track } from '@affine/track' ;
10
11
import type {
@@ -63,18 +64,15 @@ function createCopyLinkToBlockMenuItem(
63
64
const type = model . flavour ;
64
65
const page = editor . editorContainer$ . value ;
65
66
66
- page ?. host ?. std . clipboard
67
- . writeToClipboard ( items => {
68
- items [ 'text/plain' ] = str ;
69
- // wrap a link
70
- items [ 'text/html' ] = `<a href="${ str } ">${ str } </a>` ;
71
- return items ;
72
- } )
73
- . then ( ( ) => {
74
- track . doc . editor . toolbar . copyBlockToLink ( { type } ) ;
67
+ copyLinkToBlockStdScopeClipboard ( str , page ?. host ?. std . clipboard )
68
+ . then ( success => {
69
+ if ( ! success ) return ;
70
+
75
71
notify . success ( { title : I18n [ 'Copied link to clipboard' ] ( ) } ) ;
76
72
} )
77
73
. catch ( console . error ) ;
74
+
75
+ track . doc . editor . toolbar . copyBlockToLink ( { type } ) ;
78
76
} ,
79
77
} ) ;
80
78
}
Original file line number Diff line number Diff line change 5
5
} from '@affine/core/components/hooks/affine/use-share-url' ;
6
6
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch' ;
7
7
import { EditorService } from '@affine/core/modules/editor' ;
8
+ import { copyLinkToBlockStdScopeClipboard } from '@affine/core/utils/clipboard' ;
8
9
import { I18n } from '@affine/i18n' ;
9
10
import { track } from '@affine/track' ;
10
11
import type {
@@ -77,7 +78,7 @@ function createCopyLinkToBlockMenuItem(
77
78
) {
78
79
return {
79
80
...item ,
80
- action : ( ctx : MenuContext ) => {
81
+ action : async ( ctx : MenuContext ) => {
81
82
const baseUrl = getAffineCloudBaseUrl ( ) ;
82
83
if ( ! baseUrl ) {
83
84
ctx . close ( ) ;
@@ -114,18 +115,16 @@ function createCopyLinkToBlockMenuItem(
114
115
return ;
115
116
}
116
117
117
- ctx . std . clipboard
118
- . writeToClipboard ( items => {
119
- items [ 'text/plain' ] = str ;
120
- // wrap a link
121
- items [ 'text/html' ] = `<a href="${ str } ">${ str } </a>` ;
122
- return items ;
123
- } )
124
- . then ( ( ) => {
125
- track . doc . editor . toolbar . copyBlockToLink ( { type } ) ;
126
- notify . success ( { title : I18n [ 'Copied link to clipboard' ] ( ) } ) ;
127
- } )
128
- . catch ( console . error ) ;
118
+ const success = await copyLinkToBlockStdScopeClipboard (
119
+ str ,
120
+ ctx . std . clipboard
121
+ ) ;
122
+
123
+ if ( success ) {
124
+ notify . success ( { title : I18n [ 'Copied link to clipboard' ] ( ) } ) ;
125
+ }
126
+
127
+ track . doc . editor . toolbar . copyBlockToLink ( { type } ) ;
129
128
130
129
ctx . close ( ) ;
131
130
} ,
Original file line number Diff line number Diff line change 1
1
import { notify } from '@affine/component' ;
2
2
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch' ;
3
3
import { toURLSearchParams } from '@affine/core/modules/navigation' ;
4
+ import { copyTextToClipboard } from '@affine/core/utils/clipboard' ;
4
5
import { useI18n } from '@affine/i18n' ;
5
6
import { track } from '@affine/track' ;
6
7
import { type EditorHost } from '@blocksuite/affine/block-std' ;
@@ -145,23 +146,18 @@ export const useSharingUrl = ({ workspaceId, pageId }: UseSharingUrl) => {
145
146
elementIds,
146
147
} ) ;
147
148
if ( sharingUrl ) {
148
- navigator . clipboard
149
- . writeText ( sharingUrl )
150
- . then ( ( ) => {
151
- notify . success ( {
152
- title : t [ 'Copied link to clipboard' ] ( ) ,
153
- } ) ;
149
+ copyTextToClipboard ( sharingUrl )
150
+ . then ( success => {
151
+ if ( success ) {
152
+ notify . success ( { title : t [ 'Copied link to clipboard' ] ( ) } ) ;
153
+ }
154
154
} )
155
155
. catch ( err => {
156
156
console . error ( err ) ;
157
157
} ) ;
158
- track . $ . sharePanel . $ . copyShareLink ( {
159
- type,
160
- } ) ;
158
+ track . $ . sharePanel . $ . copyShareLink ( { type } ) ;
161
159
} else {
162
- notify . error ( {
163
- title : 'Network not available' ,
164
- } ) ;
160
+ notify . error ( { title : 'Network not available' } ) ;
165
161
}
166
162
} ,
167
163
[ pageId , t , workspaceId ]
Original file line number Diff line number Diff line change
1
+ const createFakeElement = ( text : string ) => {
2
+ const isRTL = document . documentElement . getAttribute ( 'dir' ) === 'rtl' ;
3
+ const fakeElement = document . createElement ( 'textarea' ) ;
4
+ // Prevent zooming on iOS
5
+ fakeElement . style . fontSize = '12pt' ;
6
+ // Reset box model
7
+ fakeElement . style . border = '0' ;
8
+ fakeElement . style . padding = '0' ;
9
+ fakeElement . style . margin = '0' ;
10
+ // Move element out of screen horizontally
11
+ fakeElement . style . position = 'absolute' ;
12
+ fakeElement . style [ isRTL ? 'right' : 'left' ] = '-9999px' ;
13
+ // Move element to the same position vertically
14
+ const yPosition = window . pageYOffset || document . documentElement . scrollTop ;
15
+ fakeElement . style . top = `${ yPosition } px` ;
16
+
17
+ fakeElement . setAttribute ( 'readonly' , '' ) ;
18
+ fakeElement . value = text ;
19
+
20
+ return fakeElement ;
21
+ } ;
22
+
23
+ function command ( type : string ) {
24
+ try {
25
+ return document . execCommand ( type ) ;
26
+ } catch ( err ) {
27
+ console . error ( err ) ;
28
+ return false ;
29
+ }
30
+ }
31
+
32
+ export const fakeCopyAction = ( text : string , container = document . body ) => {
33
+ let success = false ;
34
+
35
+ const fakeElement = createFakeElement ( text ) ;
36
+ container . append ( fakeElement ) ;
37
+
38
+ try {
39
+ fakeElement . select ( ) ;
40
+ fakeElement . setSelectionRange ( 0 , fakeElement . value . length ) ;
41
+ success = command ( 'copy' ) ;
42
+ } catch ( err ) {
43
+ console . error ( err ) ;
44
+ }
45
+
46
+ fakeElement . remove ( ) ;
47
+
48
+ return success ;
49
+ } ;
Original file line number Diff line number Diff line change
1
+ import { type Clipboard as BlockStdScopeClipboard } from '@blocksuite/affine/block-std' ;
2
+
3
+ import { fakeCopyAction } from './fake' ;
4
+
5
+ const clipboardWriteIsSupported =
6
+ 'clipboard' in navigator && 'write' in navigator . clipboard ;
7
+
8
+ const clipboardWriteTextIsSupported =
9
+ 'clipboard' in navigator && 'writeText' in navigator . clipboard ;
10
+
11
+ export const copyTextToClipboard = async ( text : string ) => {
12
+ // 1. try using Async API first, works on HTTPS domain
13
+ if ( clipboardWriteTextIsSupported ) {
14
+ try {
15
+ await navigator . clipboard . writeText ( text ) ;
16
+ return true ;
17
+ } catch ( err ) {
18
+ console . error ( err ) ;
19
+ }
20
+ }
21
+
22
+ // 2. try using `document.execCommand`
23
+ // https://github.com/zenorocha/clipboard.js/blob/master/src/actions/copy.js
24
+ return fakeCopyAction ( text ) ;
25
+ } ;
26
+
27
+ export const copyLinkToBlockStdScopeClipboard = async (
28
+ text : string ,
29
+ clipboard ?: BlockStdScopeClipboard
30
+ ) => {
31
+ let success = false ;
32
+
33
+ if ( ! clipboard ) return success ;
34
+
35
+ if ( clipboardWriteIsSupported ) {
36
+ try {
37
+ await clipboard . writeToClipboard ( items => {
38
+ items [ 'text/plain' ] = text ;
39
+ // wrap a link
40
+ items [ 'text/html' ] = `<a href="${ text } ">${ text } </a>` ;
41
+ return items ;
42
+ } ) ;
43
+ success = true ;
44
+ } catch ( error ) {
45
+ console . error ( error ) ;
46
+ }
47
+ }
48
+
49
+ if ( ! success ) {
50
+ success = await copyTextToClipboard ( text ) ;
51
+ }
52
+
53
+ return success ;
54
+ } ;
You can’t perform that action at this time.
0 commit comments