Skip to content

Commit 10aa7e6

Browse files
duonglaiquangrbri
authored andcommitted
FileReader: fire ProgressEvent and add missing event handlers
1 parent 96c6eb8 commit 10aa7e6

3 files changed

Lines changed: 199 additions & 19 deletions

File tree

src/main/java/org/htmlunit/javascript/host/event/ProgressEvent.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ public ProgressEvent(final EventTarget target, final String type) {
101101
super(target, type);
102102
}
103103

104+
/**
105+
* Creates a new event instance.
106+
* @param target the event target
107+
* @param type the event type
108+
* @param lengthComputable whether the total size is known
109+
* @param loaded the number of bytes loaded
110+
* @param total the total number of bytes
111+
*/
112+
public ProgressEvent(final EventTarget target, final String type,
113+
final boolean lengthComputable, final long loaded, final long total) {
114+
super(target, type);
115+
lengthComputable_ = lengthComputable;
116+
loaded_ = loaded;
117+
total_ = total;
118+
}
119+
104120
/**
105121
* Returns the lengthComputable property from the event.
106122
* @return the lengthComputable property from the event.

src/main/java/org/htmlunit/javascript/host/file/FileReader.java

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.htmlunit.javascript.configuration.JsxSetter;
3737
import org.htmlunit.javascript.host.event.Event;
3838
import org.htmlunit.javascript.host.event.EventTarget;
39+
import org.htmlunit.javascript.host.event.ProgressEvent;
3940
import org.htmlunit.protocol.data.DataURLConnection;
4041
import org.htmlunit.util.MimeType;
4142
import org.htmlunit.util.StringUtils;
@@ -103,21 +104,29 @@ public Object getResult() {
103104
public void readAsDataURL(final Object object) throws IOException {
104105
readyState_ = LOADING;
105106

107+
if (!(object instanceof Blob blob)) {
108+
throw JavaScriptEngine.typeError(
109+
"FileReader.readAsDataURL: Argument 1 does not implement interface Blob.");
110+
}
111+
106112
result_ = DataURLConnection.DATA_PREFIX;
107113

108-
final byte[] bytes = ((Blob) object).getBytes();
114+
final byte[] bytes = blob.getBytes();
115+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
116+
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));
117+
109118
final String value = new String(Base64.getEncoder().encode(bytes), StandardCharsets.US_ASCII);
110119

111-
String contentType = ((Blob) object).getType();
120+
String contentType = blob.getType();
112121
if (StringUtils.isEmptyOrNull(contentType)) {
113122
contentType = MimeType.APPLICATION_OCTET_STREAM;
114123
}
115124

116125
result_ += contentType + ";base64," + value;
117126
readyState_ = DONE;
118127

119-
final Event event = new Event(this, Event.TYPE_LOAD);
120-
fireEvent(event);
128+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
129+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
121130
}
122131

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

131-
if (object instanceof Blob blob) {
132-
final byte[] bytes = blob.getBytes();
140+
if (!(object instanceof Blob blob)) {
141+
throw JavaScriptEngine.typeError(
142+
"FileReader.readAsArrayBuffer: Argument 1 does not implement interface Blob.");
143+
}
133144

134-
final NativeArrayBuffer buffer = new NativeArrayBuffer(bytes.length);
135-
System.arraycopy(bytes, 0, buffer.getBuffer(), 0, bytes.length);
136-
buffer.setParentScope(getParentScope());
137-
buffer.setPrototype(ScriptableObject.getClassPrototype(getWindow(), buffer.getClassName()));
145+
final byte[] bytes = blob.getBytes();
146+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
147+
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));
138148

139-
result_ = buffer;
140-
}
149+
final NativeArrayBuffer buffer = new NativeArrayBuffer(bytes.length);
150+
System.arraycopy(bytes, 0, buffer.getBuffer(), 0, bytes.length);
151+
buffer.setParentScope(getParentScope());
152+
buffer.setPrototype(ScriptableObject.getClassPrototype(getWindow(), buffer.getClassName()));
141153

154+
result_ = buffer;
142155
readyState_ = DONE;
143156

144-
final Event event = new Event(this, Event.TYPE_LOAD);
145-
fireEvent(event);
157+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
158+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
146159
}
147160

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

173+
if (!(object instanceof Blob blob)) {
174+
throw JavaScriptEngine.typeError(
175+
"FileReader.readAsText: Argument 1 does not implement interface Blob.");
176+
}
177+
160178
Charset charset = StandardCharsets.UTF_8;
161179
if (encoding != null && !JavaScriptEngine.isUndefined(encoding)) {
162180
final String encAsString = JavaScriptEngine.toString(encoding);
@@ -173,14 +191,51 @@ public void readAsText(final Object object, final Object encoding) {
173191
}
174192
}
175193

176-
if (object instanceof Blob blob) {
177-
result_ = new String(blob.getBytes(), charset);
178-
}
194+
final byte[] bytes = blob.getBytes();
195+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_START, true, 0, bytes.length));
196+
fireEvent(new ProgressEvent(this, Event.TYPE_PROGRESS, true, bytes.length, bytes.length));
179197

198+
result_ = new String(bytes, charset);
180199
readyState_ = DONE;
181200

182-
final Event event = new Event(this, Event.TYPE_LOAD);
183-
fireEvent(event);
201+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD, true, bytes.length, bytes.length));
202+
fireEvent(new ProgressEvent(this, Event.TYPE_LOAD_END, true, bytes.length, bytes.length));
203+
}
204+
205+
/**
206+
* Returns the {@code onloadstart} event handler for this {@link FileReader}.
207+
* @return the {@code onloadstart} event handler for this {@link FileReader}
208+
*/
209+
@JsxGetter
210+
public Function getOnloadstart() {
211+
return getEventHandler(Event.TYPE_LOAD_START);
212+
}
213+
214+
/**
215+
* Sets the {@code onloadstart} event handler for this {@link FileReader}.
216+
* @param onloadstart the {@code onloadstart} event handler for this {@link FileReader}
217+
*/
218+
@JsxSetter
219+
public void setOnloadstart(final Object onloadstart) {
220+
setEventHandler(Event.TYPE_LOAD_START, onloadstart);
221+
}
222+
223+
/**
224+
* Returns the {@code onprogress} event handler for this {@link FileReader}.
225+
* @return the {@code onprogress} event handler for this {@link FileReader}
226+
*/
227+
@JsxGetter
228+
public Function getOnprogress() {
229+
return getEventHandler(Event.TYPE_PROGRESS);
230+
}
231+
232+
/**
233+
* Sets the {@code onprogress} event handler for this {@link FileReader}.
234+
* @param onprogress the {@code onprogress} event handler for this {@link FileReader}
235+
*/
236+
@JsxSetter
237+
public void setOnprogress(final Object onprogress) {
238+
setEventHandler(Event.TYPE_PROGRESS, onprogress);
184239
}
185240

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

259+
/**
260+
* Returns the {@code onloadend} event handler for this {@link FileReader}.
261+
* @return the {@code onloadend} event handler for this {@link FileReader}
262+
*/
263+
@JsxGetter
264+
public Function getOnloadend() {
265+
return getEventHandler(Event.TYPE_LOAD_END);
266+
}
267+
268+
/**
269+
* Sets the {@code onloadend} event handler for this {@link FileReader}.
270+
* @param onloadend the {@code onloadend} event handler for this {@link FileReader}
271+
*/
272+
@JsxSetter
273+
public void setOnloadend(final Object onloadend) {
274+
setEventHandler(Event.TYPE_LOAD_END, onloadend);
275+
}
276+
204277
/**
205278
* Returns the {@code onerror} event handler for this {@link FileReader}.
206279
* @return the {@code onerror} event handler for this {@link FileReader}

src/test/java/org/htmlunit/javascript/host/file/FileReaderTest.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,97 @@ public void readAsText_blob() throws Exception {
798798
loadPageVerifyTitle2(html);
799799
}
800800

801+
/**
802+
* @throws Exception if the test fails
803+
*/
804+
@Test
805+
@Alerts({"loadstart", "progress", "load", "loadend"})
806+
public void readAsTextEventLifecycle() throws Exception {
807+
final String html = DOCTYPE_HTML
808+
+ "<html>\n"
809+
+ "<head>\n"
810+
+ " <script>\n"
811+
+ LOG_TITLE_FUNCTION
812+
+ " function test() {\n"
813+
+ " var blob = new Blob(['HtmlUnit'], {type : 'text/plain'});\n"
814+
+ " var reader = new FileReader();\n"
815+
+ " reader.addEventListener('loadstart', function() { log('loadstart'); });\n"
816+
+ " reader.addEventListener('progress', function() { log('progress'); });\n"
817+
+ " reader.addEventListener('load', function() { log('load'); });\n"
818+
+ " reader.addEventListener('loadend', function() { log('loadend'); });\n"
819+
+ " reader.readAsText(blob);\n"
820+
+ " }\n"
821+
+ " </script>\n"
822+
+ "</head>\n"
823+
+ "<body onload='test()'>\n"
824+
+ "</body>\n"
825+
+ "</html>";
826+
827+
loadPageVerifyTitle2(html);
828+
}
829+
830+
/**
831+
* @throws Exception if the test fails
832+
*/
833+
@Test
834+
@Alerts({"true", "8", "8"})
835+
public void readAsDataURLProgressEventProperties() throws Exception {
836+
final String html = DOCTYPE_HTML
837+
+ "<html>\n"
838+
+ "<head>\n"
839+
+ " <script>\n"
840+
+ LOG_TITLE_FUNCTION
841+
+ " function test() {\n"
842+
+ " var blob = new Blob(['HtmlUnit']);\n"
843+
+ " var reader = new FileReader();\n"
844+
+ " reader.addEventListener('load', function(e) {\n"
845+
+ " log(e.lengthComputable);\n"
846+
+ " log(e.loaded);\n"
847+
+ " log(e.total);\n"
848+
+ " });\n"
849+
+ " reader.readAsDataURL(blob);\n"
850+
+ " }\n"
851+
+ " </script>\n"
852+
+ "</head>\n"
853+
+ "<body onload='test()'>\n"
854+
+ "</body>\n"
855+
+ "</html>";
856+
857+
loadPageVerifyTitle2(html);
858+
}
859+
860+
/**
861+
* @throws Exception if the test fails
862+
*/
863+
@Test
864+
@Alerts({"loadstart", "progress", "[object ArrayBuffer]", "8", "loadend"})
865+
public void readAsArrayBufferPropertyHandlers() throws Exception {
866+
final String html = DOCTYPE_HTML
867+
+ "<html>\n"
868+
+ "<head>\n"
869+
+ " <script>\n"
870+
+ LOG_TITLE_FUNCTION
871+
+ " function test() {\n"
872+
+ " var blob = new Blob(['HtmlUnit'], {type : 'text/html'});\n"
873+
+ " var reader = new FileReader();\n"
874+
+ " reader.onloadstart = function() { log('loadstart'); };\n"
875+
+ " reader.onprogress = function() { log('progress'); };\n"
876+
+ " reader.onloadend = function() { log('loadend'); };\n"
877+
+ " reader.onload = function() {\n"
878+
+ " log(reader.result);\n"
879+
+ " log(reader.result.byteLength);\n"
880+
+ " };\n"
881+
+ " reader.readAsArrayBuffer(blob);\n"
882+
+ " }\n"
883+
+ " </script>\n"
884+
+ "</head>\n"
885+
+ "<body onload='test()'>\n"
886+
+ "</body>\n"
887+
+ "</html>";
888+
889+
loadPageVerifyTitle2(html);
890+
}
891+
801892
/**
802893
* @throws Exception if the test fails
803894
*/

0 commit comments

Comments
 (0)