Skip to content

Commit 88935ca

Browse files
author
Nurhan Turgut
authored
Support Clipboard.getData and Clipboard.setData for Flutter for web (flutter#15455)
* copy/paste solution for chrome. copy solution for firefox. using clipboardAPI. * addressing PR comments * update licences file
1 parent 2bd4aff commit 88935ca

File tree

4 files changed

+114
-3
lines changed

4 files changed

+114
-3
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/bitmap_canvas.dart
388388
FILE: ../../../flutter/lib/web_ui/lib/src/engine/browser_detection.dart
389389
FILE: ../../../flutter/lib/web_ui/lib/src/engine/browser_location.dart
390390
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvas_pool.dart
391+
FILE: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart
391392
FILE: ../../../flutter/lib/web_ui/lib/src/engine/color_filter.dart
392393
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/canvas.dart
393394
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/canvas_kit_canvas.dart

lib/web_ui/lib/src/engine.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ part 'engine/bitmap_canvas.dart';
2424
part 'engine/browser_detection.dart';
2525
part 'engine/browser_location.dart';
2626
part 'engine/canvas_pool.dart';
27+
part 'engine/clipboard.dart';
2728
part 'engine/color_filter.dart';
2829
part 'engine/compositor/canvas.dart';
2930
part 'engine/compositor/canvas_kit_canvas.dart';
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
part of engine;
6+
7+
/// Handles clipboard related platform messages.
8+
class ClipboardMessageHandler {
9+
/// Helper to handle copy to clipboard functionality.
10+
final CopyToClipboardStrategy _copyToClipboardStrategy =
11+
CopyToClipboardStrategy();
12+
13+
/// Helper to handle copy to clipboard functionality.
14+
final PasteFromClipboardStrategy _pasteFromClipboardStrategy =
15+
PasteFromClipboardStrategy();
16+
17+
/// Handles the platform message which stores the given text to the clipboard.
18+
void setDataMethodCall(MethodCall methodCall) {
19+
_copyToClipboardStrategy.setData(methodCall.arguments['text']);
20+
}
21+
22+
/// Handles the platform message which retrieves text data from the clipboard.
23+
void getDataMethodCall(ui.PlatformMessageResponseCallback callback) {
24+
_pasteFromClipboardStrategy.getData().then((String data) {
25+
const MethodCodec codec = JSONMethodCodec();
26+
final Map<String, dynamic> map = {'text': data};
27+
callback(codec.encodeSuccessEnvelope(map));
28+
}).catchError(
29+
(error) => print('Could not get text from clipboard: $error'));
30+
}
31+
}
32+
33+
/// Provides functionality for writing text to clipboard.
34+
///
35+
/// A concrete implementation is picked at runtime based on the available
36+
/// APIs and the browser.
37+
abstract class CopyToClipboardStrategy {
38+
factory CopyToClipboardStrategy() {
39+
return (html.window.navigator.clipboard.writeText != null)
40+
? ClipboardAPICopyStrategy()
41+
: ExecCommandCopyStrategy();
42+
}
43+
44+
/// Places the text onto the browser Clipboard.
45+
void setData(String text);
46+
}
47+
48+
/// Provides functionality for reading text from clipboard.
49+
///
50+
/// A concrete implementation is picked at runtime based on the available
51+
/// APIs and the browser.
52+
abstract class PasteFromClipboardStrategy {
53+
factory PasteFromClipboardStrategy() {
54+
return (browserEngine == BrowserEngine.firefox ||
55+
html.window.navigator.clipboard.readText == null)
56+
? ExecCommandPasteStrategy()
57+
: ClipboardAPIPasteStrategy();
58+
}
59+
60+
/// Returns text from the system Clipboard.
61+
Future<String> getData();
62+
}
63+
64+
/// Provides copy functionality for browsers which supports ClipboardAPI.
65+
///
66+
/// Works on Chrome and Firefox browsers.
67+
/// See: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
68+
class ClipboardAPICopyStrategy implements CopyToClipboardStrategy {
69+
@override
70+
void setData(String text) {
71+
html.window.navigator.clipboard
72+
.writeText(text)
73+
.catchError((error) => print('Could not copy text: $error'));
74+
}
75+
}
76+
77+
/// Provides paste functionality for browsers which supports `clipboard.readText`.
78+
///
79+
/// Works on Chrome. Firefox only supports `readText` if the target element is
80+
/// in content editable mode.
81+
/// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content
82+
/// See: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
83+
class ClipboardAPIPasteStrategy implements PasteFromClipboardStrategy {
84+
@override
85+
Future<String> getData() async {
86+
return html.window.navigator.clipboard.readText();
87+
}
88+
}
89+
90+
/// Provides a fallback strategy for browsers which does not support ClipboardAPI.
91+
class ExecCommandCopyStrategy implements CopyToClipboardStrategy {
92+
@override
93+
void setData(String text) {
94+
// TODO(nurhan): https://github.com/flutter/flutter/issues/48578
95+
print('Clipboard is only implemented for browsers '
96+
'supporting Clipboard API. Use context menu for text editing.');
97+
}
98+
}
99+
100+
/// Provides a fallback strategy for browsers which does not support ClipboardAPI.
101+
class ExecCommandPasteStrategy implements PasteFromClipboardStrategy {
102+
@override
103+
Future<String> getData() {
104+
// TODO(nurhan): https://github.com/flutter/flutter/issues/48581
105+
// TODO(nurhan): https://github.com/flutter/flutter/issues/48580
106+
print('Paste is not implemented for this browser.');
107+
throw UnimplementedError();
108+
}
109+
}

lib/web_ui/lib/src/engine/window.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ class EngineWindow extends ui.Window {
159159
// There are no default system sounds on web.
160160
return;
161161
case 'Clipboard.setData':
162+
ClipboardMessageHandler().setDataMethodCall(decoded);
163+
return;
162164
case 'Clipboard.getData':
163-
// TODO(nurhan): https://github.com/flutter/flutter/issues/46020
164-
print('WARNING: Clipboard API unimplemented for Flutter for Web. '
165-
'Use context menu for text editing.');
165+
ClipboardMessageHandler().getDataMethodCall(callback);
166166
return;
167167
}
168168
break;

0 commit comments

Comments
 (0)