Skip to content

Commit

Permalink
Fixes file upload (#111)
Browse files Browse the repository at this point in the history
Integrate changes from puppeteer: This PR returns to using DOM.setFileInputFiles, but with some additional fixes and checks for events and multiple files.
  • Loading branch information
xvrh committed Apr 21, 2020
1 parent db09349 commit 4d5c3f2
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 25 deletions.
43 changes: 19 additions & 24 deletions lib/src/page/js_handle.dart
@@ -1,8 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:mime/mime.dart';
import 'package:path/path.dart' as p;
import '../../protocol/dom.dart';
import '../../protocol/runtime.dart';
import '../connection.dart';
Expand Down Expand Up @@ -396,28 +393,26 @@ async function _(element, pageJavascriptEnabled) {
'Multiple file uploads only work with <input type=file multiple>');
}

var filesArg = <Map<String, String>>[];
for (var file in files) {
var fileArg = <String, String>{
'name': p.basename(file.path),
'content': base64.encode(await file.readAsBytes()),
'mimeType': lookupMimeType(file.path) ?? 'application/octet-stream',
};
filesArg.add(fileArg);
var objectId = remoteObject.objectId;
var node = await executionContext.domApi.describeNode(objectId: objectId);

// The zero-length array is a special case, it seems that DOM.setFileInputFiles does
// not actually update the files in that case, so the solution is to eval the element
// value to a new FileList directly.
if (files.isEmpty) {
await evaluate('''element => {
element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action.
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
}''');
} else {
await executionContext.domApi.setFileInputFiles(
files.map((file) => file.absolute.path).toList(),
objectId: objectId,
backendNodeId: node.backendNodeId);
}
await evaluateHandle(
//language=js
r'''async (element, files) => {
const dt = new DataTransfer();
for (const item of files) {
const response = await fetch(`data:${item.mimeType};base64,${item.content}`);
const file = new File([await response.blob()], item.name, {type: item.mimeType});
dt.items.add(file);
}
element.files = dt.files;
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
}''', args: [filesArg]);
}

/// This method scrolls element into view if needed, and then uses [touchscreen.tap]
Expand Down
1 change: 0 additions & 1 deletion pubspec.yaml
Expand Up @@ -13,7 +13,6 @@ dependencies:
http: '>=0.9.0 <0.13.0'
logging: ^0.11.3
meta: ^1.1.1
mime: ^0.9.0
path: '>=1.0.0 <2.0.0'
petitparser: '>=2.2.0 <4.0.0'
pool: ^1.4.0
Expand Down

0 comments on commit 4d5c3f2

Please sign in to comment.