Skip to content

Commit 2a508cb

Browse files
[file_selector_web] Listens to file input cancel event. (flutter#3683)
While using package ``file_selector`` making for multiple file request in web platform we are not able to get any data if user clicks cancel button on file selection window. This PR fixes it by watching the ``focus event`` and if ``onChange`` is not fired then return empty array, Empty array will only return if multiple selection is enabled with ``openFiles()``. *List which issues are fixed by this PR. You must list at least one issue.* [Issue flutter#121328](flutter#121328)
1 parent 31973f7 commit 2a508cb

File tree

10 files changed

+71
-8
lines changed

10 files changed

+71
-8
lines changed

.ci/scripts/dart_unit_tests_pathified.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ set -e
1212
# re-checked.
1313
dart ./script/tool/bin/flutter_plugin_tools.dart dart-test --run-on-dirty-packages \
1414
--log-timing --exclude=script/configs/dart_unit_tests_exceptions.yaml \
15-
$PACKAGE_SHARDING
15+
"$@" $PACKAGE_SHARDING
1616
# Restore the tree to a clean state, to avoid accidental issues if
1717
# other script steps are added to the enclosing task.
1818
git checkout .

.ci/targets/dart_unit_tests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ tasks:
99
# that depend on it.
1010
- name: Dart unit tests - pathified
1111
script: .ci/scripts/dart_unit_tests_pathified.sh
12+
args: ["--platform=vm"]

packages/file_selector/file_selector_web/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.9.2
2+
3+
* Adds and propagates `cancel` event on file selection.
4+
* Changes `openFile` to return `null` when no files are selected/selection is canceled,
5+
as in other platforms.
6+
17
## 0.9.1
28

39
* Adds `getSaveLocation` and deprecates `getSavePath`.

packages/file_selector/file_selector_web/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,15 @@ should add it to your `pubspec.yaml` as usual.
1313

1414
[1]: https://pub.dev/packages/file_selector
1515
[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin
16+
17+
## Limitations on the Web platform
18+
19+
### `cancel` event
20+
21+
The `cancel` event used by the web plugin to detect when users close the file
22+
selector without picking a file is relatively new, and will only work in
23+
recent browsers.
24+
25+
See:
26+
27+
* https://caniuse.com/mdn-api_htmlinputelement_cancel_event

packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,17 @@ void main() {
2121
return dataTransfer.files as FileList?;
2222
}
2323

24-
void setFilesAndTriggerChange(List<File> files) {
24+
void setFilesAndTriggerEvent(List<File> files, Event event) {
2525
input.files = createFileList(files);
26-
input.dispatchEvent(Event('change'));
26+
input.dispatchEvent(event);
27+
}
28+
29+
void setFilesAndTriggerChange(List<File> files) {
30+
setFilesAndTriggerEvent(files, Event('change'));
31+
}
32+
33+
void setFilesAndTriggerCancel(List<File> files) {
34+
setFilesAndTriggerEvent(files, Event('cancel'));
2735
}
2836

2937
setUp(() {
@@ -57,6 +65,18 @@ void main() {
5765
expect(await files[1].lastModified(), isNotNull);
5866
});
5967

68+
testWidgets('"cancel" returns an empty selection', (_) async {
69+
final Future<List<XFile>> futureFiles = domHelper.getFiles(
70+
input: input,
71+
);
72+
73+
setFilesAndTriggerCancel(<File>[mockFile1, mockFile2]);
74+
75+
final List<XFile> files = await futureFiles;
76+
77+
expect(files.length, 0);
78+
});
79+
6080
testWidgets('works multiple times', (_) async {
6181
Future<List<XFile>> futureFiles;
6282
List<XFile> files;

packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,30 @@ void main() {
3333
webWildCards: <String>['image/*'],
3434
);
3535

36-
final XFile file =
36+
final XFile? file =
3737
await plugin.openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
3838

39-
expect(file.name, mockFile.name);
39+
expect(file, isNotNull);
40+
expect(file!.name, mockFile.name);
4041
expect(await file.length(), 4);
4142
expect(await file.readAsString(), '1001');
4243
expect(await file.lastModified(), isNotNull);
4344
});
45+
46+
testWidgets('returns null when getFiles returns an empty list',
47+
(WidgetTester _) async {
48+
// Simulate returning an empty list of files from the DomHelper...
49+
final MockDomHelper mockDomHelper = MockDomHelper(
50+
files: <XFile>[],
51+
);
52+
53+
final FileSelectorWeb plugin =
54+
FileSelectorWeb(domHelper: mockDomHelper);
55+
56+
final XFile? file = await plugin.openFile();
57+
58+
expect(file, isNull);
59+
});
4460
});
4561

4662
group('openFiles', () {

packages/file_selector/file_selector_web/lib/file_selector_web.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ class FileSelectorWeb extends FileSelectorPlatform {
2929
}
3030

3131
@override
32-
Future<XFile> openFile({
32+
Future<XFile?> openFile({
3333
List<XTypeGroup>? acceptedTypeGroups,
3434
String? initialDirectory,
3535
String? confirmButtonText,
3636
}) async {
3737
final List<XFile> files =
3838
await _openFiles(acceptedTypeGroups: acceptedTypeGroups);
39-
return files.first;
39+
return files.isNotEmpty ? files.first : null;
4040
}
4141

4242
@override

packages/file_selector/file_selector_web/lib/src/dom_helper.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ class DomHelper {
5252
completer.completeError(platformException);
5353
});
5454

55+
inputElement.addEventListener('cancel', (Event event) {
56+
inputElement.remove();
57+
completer.complete(<XFile>[]);
58+
});
59+
60+
// TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365
5561
inputElement.click();
5662

5763
return completer.future;

packages/file_selector/file_selector_web/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: file_selector_web
22
description: Web platform implementation of file_selector
33
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
5-
version: 0.9.1
5+
version: 0.9.2
66

77
environment:
88
sdk: ">=2.18.0 <4.0.0"

packages/file_selector/file_selector_web/test/utils_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
@TestOn('chrome') // web-only package.
6+
57
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
68
import 'package:file_selector_web/src/utils.dart';
79
import 'package:flutter_test/flutter_test.dart';

0 commit comments

Comments
 (0)