Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,22 @@ public ProgressEvent(final EventTarget target, final String type) {
super(target, type);
}

/**
* Creates a new event instance.
* @param target the event target
* @param type the event type
* @param lengthComputable whether the total size is known
* @param loaded the number of bytes loaded
* @param total the total number of bytes
*/
public ProgressEvent(final EventTarget target, final String type,
final boolean lengthComputable, final long loaded, final long total) {
super(target, type);
lengthComputable_ = lengthComputable;
loaded_ = loaded;
total_ = total;
}

/**
* Returns the lengthComputable property from the event.
* @return the lengthComputable property from the event.
Expand Down
111 changes: 92 additions & 19 deletions src/main/java/org/htmlunit/javascript/host/file/FileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.htmlunit.javascript.configuration.JsxSetter;
import org.htmlunit.javascript.host.event.Event;
import org.htmlunit.javascript.host.event.EventTarget;
import org.htmlunit.javascript.host.event.ProgressEvent;
import org.htmlunit.protocol.data.DataURLConnection;
import org.htmlunit.util.MimeType;
import org.htmlunit.util.StringUtils;
Expand Down Expand Up @@ -103,21 +104,29 @@ public Object getResult() {
public void readAsDataURL(final Object object) throws IOException {
readyState_ = LOADING;

if (!(object instanceof Blob blob)) {
throw JavaScriptEngine.typeError(
"FileReader.readAsDataURL: Argument 1 does not implement interface Blob.");
}

result_ = DataURLConnection.DATA_PREFIX;

final byte[] bytes = ((Blob) object).getBytes();
final byte[] bytes = blob.getBytes();
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));

final String value = new String(Base64.getEncoder().encode(bytes), StandardCharsets.US_ASCII);

String contentType = ((Blob) object).getType();
String contentType = blob.getType();
if (StringUtils.isEmptyOrNull(contentType)) {
contentType = MimeType.APPLICATION_OCTET_STREAM;
}

result_ += contentType + ";base64," + value;
readyState_ = DONE;

final Event event = new Event(this, Event.TYPE_LOAD);
fireEvent(event);
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
}

/**
Expand All @@ -128,21 +137,25 @@ public void readAsDataURL(final Object object) throws IOException {
public void readAsArrayBuffer(final Object object) {
readyState_ = LOADING;

if (object instanceof Blob blob) {
final byte[] bytes = blob.getBytes();
if (!(object instanceof Blob blob)) {
throw JavaScriptEngine.typeError(
"FileReader.readAsArrayBuffer: Argument 1 does not implement interface Blob.");
}

final NativeArrayBuffer buffer = new NativeArrayBuffer(bytes.length);
System.arraycopy(bytes, 0, buffer.getBuffer(), 0, bytes.length);
buffer.setParentScope(getParentScope());
buffer.setPrototype(ScriptableObject.getClassPrototype(getWindow(), buffer.getClassName()));
final byte[] bytes = blob.getBytes();
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));

result_ = buffer;
}
final NativeArrayBuffer buffer = new NativeArrayBuffer(bytes.length);
System.arraycopy(bytes, 0, buffer.getBuffer(), 0, bytes.length);
buffer.setParentScope(getParentScope());
buffer.setPrototype(ScriptableObject.getClassPrototype(getWindow(), buffer.getClassName()));

result_ = buffer;
readyState_ = DONE;

final Event event = new Event(this, Event.TYPE_LOAD);
fireEvent(event);
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
}

/**
Expand All @@ -157,6 +170,11 @@ public void readAsArrayBuffer(final Object object) {
public void readAsText(final Object object, final Object encoding) {
readyState_ = LOADING;

if (!(object instanceof Blob blob)) {
throw JavaScriptEngine.typeError(
"FileReader.readAsText: Argument 1 does not implement interface Blob.");
}

Charset charset = StandardCharsets.UTF_8;
if (encoding != null && !JavaScriptEngine.isUndefined(encoding)) {
final String encAsString = JavaScriptEngine.toString(encoding);
Expand All @@ -173,14 +191,51 @@ public void readAsText(final Object object, final Object encoding) {
}
}

if (object instanceof Blob blob) {
result_ = new String(blob.getBytes(), charset);
}
final byte[] bytes = blob.getBytes();
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));

result_ = new String(bytes, charset);
readyState_ = DONE;

final Event event = new Event(this, Event.TYPE_LOAD);
fireEvent(event);
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
}

/**
* Returns the {@code onloadstart} event handler for this {@link FileReader}.
* @return the {@code onloadstart} event handler for this {@link FileReader}
*/
@JsxGetter
public Function getOnloadstart() {
return getEventHandler(Event.TYPE_LOAD_START);
}

/**
* Sets the {@code onloadstart} event handler for this {@link FileReader}.
* @param onloadstart the {@code onloadstart} event handler for this {@link FileReader}
*/
@JsxSetter
public void setOnloadstart(final Object onloadstart) {
setEventHandler(Event.TYPE_LOAD_START, onloadstart);
}

/**
* Returns the {@code onprogress} event handler for this {@link FileReader}.
* @return the {@code onprogress} event handler for this {@link FileReader}
*/
@JsxGetter
public Function getOnprogress() {
return getEventHandler(Event.TYPE_PROGRESS);
}

/**
* Sets the {@code onprogress} event handler for this {@link FileReader}.
* @param onprogress the {@code onprogress} event handler for this {@link FileReader}
*/
@JsxSetter
public void setOnprogress(final Object onprogress) {
setEventHandler(Event.TYPE_PROGRESS, onprogress);
}

/**
Expand All @@ -201,6 +256,24 @@ public void setOnload(final Object onload) {
setEventHandler(Event.TYPE_LOAD, onload);
}

/**
* Returns the {@code onloadend} event handler for this {@link FileReader}.
* @return the {@code onloadend} event handler for this {@link FileReader}
*/
@JsxGetter
public Function getOnloadend() {
return getEventHandler(Event.TYPE_LOAD_END);
}

/**
* Sets the {@code onloadend} event handler for this {@link FileReader}.
* @param onloadend the {@code onloadend} event handler for this {@link FileReader}
*/
@JsxSetter
public void setOnloadend(final Object onloadend) {
setEventHandler(Event.TYPE_LOAD_END, onloadend);
}

/**
* Returns the {@code onerror} event handler for this {@link FileReader}.
* @return the {@code onerror} event handler for this {@link FileReader}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,97 @@ public void readAsText_blob() throws Exception {
loadPageVerifyTitle2(html);
}

/**
* @throws Exception if the test fails
*/
@Test
@Alerts({"loadstart", "progress", "load", "loadend"})
public void readAsTextEventLifecycle() throws Exception {
final String html = DOCTYPE_HTML
+ "<html>\n"
+ "<head>\n"
+ " <script>\n"
+ LOG_TITLE_FUNCTION
+ " function test() {\n"
+ " var blob = new Blob(['HtmlUnit'], {type : 'text/plain'});\n"
+ " var reader = new FileReader();\n"
+ " reader.addEventListener('loadstart', function() { log('loadstart'); });\n"
+ " reader.addEventListener('progress', function() { log('progress'); });\n"
+ " reader.addEventListener('load', function() { log('load'); });\n"
+ " reader.addEventListener('loadend', function() { log('loadend'); });\n"
+ " reader.readAsText(blob);\n"
+ " }\n"
+ " </script>\n"
+ "</head>\n"
+ "<body onload='test()'>\n"
+ "</body>\n"
+ "</html>";

loadPageVerifyTitle2(html);
}

/**
* @throws Exception if the test fails
*/
@Test
@Alerts({"true", "8", "8"})
public void readAsDataURLProgressEventProperties() throws Exception {
final String html = DOCTYPE_HTML
+ "<html>\n"
+ "<head>\n"
+ " <script>\n"
+ LOG_TITLE_FUNCTION
+ " function test() {\n"
+ " var blob = new Blob(['HtmlUnit']);\n"
+ " var reader = new FileReader();\n"
+ " reader.addEventListener('load', function(e) {\n"
+ " log(e.lengthComputable);\n"
+ " log(e.loaded);\n"
+ " log(e.total);\n"
+ " });\n"
+ " reader.readAsDataURL(blob);\n"
+ " }\n"
+ " </script>\n"
+ "</head>\n"
+ "<body onload='test()'>\n"
+ "</body>\n"
+ "</html>";

loadPageVerifyTitle2(html);
}

/**
* @throws Exception if the test fails
*/
@Test
@Alerts({"loadstart", "progress", "[object ArrayBuffer]", "8", "loadend"})
public void readAsArrayBufferPropertyHandlers() throws Exception {
final String html = DOCTYPE_HTML
+ "<html>\n"
+ "<head>\n"
+ " <script>\n"
+ LOG_TITLE_FUNCTION
+ " function test() {\n"
+ " var blob = new Blob(['HtmlUnit'], {type : 'text/html'});\n"
+ " var reader = new FileReader();\n"
+ " reader.onloadstart = function() { log('loadstart'); };\n"
+ " reader.onprogress = function() { log('progress'); };\n"
+ " reader.onloadend = function() { log('loadend'); };\n"
+ " reader.onload = function() {\n"
+ " log(reader.result);\n"
+ " log(reader.result.byteLength);\n"
+ " };\n"
+ " reader.readAsArrayBuffer(blob);\n"
+ " }\n"
+ " </script>\n"
+ "</head>\n"
+ "<body onload='test()'>\n"
+ "</body>\n"
+ "</html>";

loadPageVerifyTitle2(html);
}

/**
* @throws Exception if the test fails
*/
Expand Down
Loading