diff options
Diffstat (limited to 'ext/web/10_filereader.js')
-rw-r--r-- | ext/web/10_filereader.js | 845 |
1 files changed, 420 insertions, 425 deletions
diff --git a/ext/web/10_filereader.js b/ext/web/10_filereader.js index fb119f43e..7a46dfa9a 100644 --- a/ext/web/10_filereader.js +++ b/ext/web/10_filereader.js @@ -10,487 +10,482 @@ /// <reference path="./internal.d.ts" /> /// <reference lib="esnext" /> -"use strict"; - -((window) => { - const core = window.Deno.core; - const webidl = window.__bootstrap.webidl; - const { forgivingBase64Encode } = window.__bootstrap.infra; - const { ProgressEvent } = window.__bootstrap.event; - const { EventTarget } = window.__bootstrap.eventTarget; - const { decode, TextDecoder } = window.__bootstrap.encoding; - const { parseMimeType } = window.__bootstrap.mimesniff; - const { DOMException } = window.__bootstrap.domException; - const { - ArrayPrototypePush, - ArrayPrototypeReduce, - FunctionPrototypeCall, - Map, - MapPrototypeGet, - MapPrototypeSet, - ObjectDefineProperty, - ObjectPrototypeIsPrototypeOf, - queueMicrotask, - SafeArrayIterator, - Symbol, - TypedArrayPrototypeSet, - TypeError, - Uint8Array, - Uint8ArrayPrototype, - } = window.__bootstrap.primordials; - - const state = Symbol("[[state]]"); - const result = Symbol("[[result]]"); - const error = Symbol("[[error]]"); - const aborted = Symbol("[[aborted]]"); - const handlerSymbol = Symbol("eventHandlers"); - - class FileReader extends EventTarget { - /** @type {"empty" | "loading" | "done"} */ - [state] = "empty"; - /** @type {null | string | ArrayBuffer} */ - [result] = null; - /** @type {null | DOMException} */ - [error] = null; - /** @type {null | {aborted: boolean}} */ - [aborted] = null; - - /** - * @param {Blob} blob - * @param {{kind: "ArrayBuffer" | "Text" | "DataUrl" | "BinaryString", encoding?: string}} readtype - */ - #readOperation(blob, readtype) { - // 1. If fr’s state is "loading", throw an InvalidStateError DOMException. - if (this[state] === "loading") { - throw new DOMException( - "Invalid FileReader state.", - "InvalidStateError", - ); - } - // 2. Set fr’s state to "loading". - this[state] = "loading"; - // 3. Set fr’s result to null. - this[result] = null; - // 4. Set fr’s error to null. - this[error] = null; - - // We set this[aborted] to a new object, and keep track of it in a - // separate variable, so if a new read operation starts while there are - // remaining tasks from a previous aborted operation, the new operation - // will run while the tasks from the previous one are still aborted. - const abortedState = this[aborted] = { aborted: false }; - - // 5. Let stream be the result of calling get stream on blob. - const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream(); - - // 6. Let reader be the result of getting a reader from stream. - const reader = stream.getReader(); - - // 7. Let bytes be an empty byte sequence. - /** @type {Uint8Array[]} */ - const chunks = []; - - // 8. Let chunkPromise be the result of reading a chunk from stream with reader. - let chunkPromise = reader.read(); - - // 9. Let isFirstChunk be true. - let isFirstChunk = true; - - // 10 in parallel while true - (async () => { - while (!abortedState.aborted) { - // 1. Wait for chunkPromise to be fulfilled or rejected. - try { - const chunk = await chunkPromise; - if (abortedState.aborted) return; - - // 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr. - if (isFirstChunk) { +const core = globalThis.Deno.core; +const ops = core.ops; +import * as webidl from "internal:ext/webidl/00_webidl.js"; +const primordials = globalThis.__bootstrap.primordials; +import { forgivingBase64Encode } from "internal:ext/web/00_infra.js"; +import { EventTarget, ProgressEvent } from "internal:ext/web/02_event.js"; +import { decode, TextDecoder } from "internal:ext/web/08_text_encoding.js"; +import { parseMimeType } from "internal:ext/web/01_mimesniff.js"; +import DOMException from "internal:ext/web/01_dom_exception.js"; +const { + ArrayPrototypePush, + ArrayPrototypeReduce, + FunctionPrototypeCall, + Map, + MapPrototypeGet, + MapPrototypeSet, + ObjectDefineProperty, + ObjectPrototypeIsPrototypeOf, + queueMicrotask, + SafeArrayIterator, + Symbol, + TypedArrayPrototypeSet, + TypeError, + Uint8Array, + Uint8ArrayPrototype, +} = primordials; + +const state = Symbol("[[state]]"); +const result = Symbol("[[result]]"); +const error = Symbol("[[error]]"); +const aborted = Symbol("[[aborted]]"); +const handlerSymbol = Symbol("eventHandlers"); + +class FileReader extends EventTarget { + /** @type {"empty" | "loading" | "done"} */ + [state] = "empty"; + /** @type {null | string | ArrayBuffer} */ + [result] = null; + /** @type {null | DOMException} */ + [error] = null; + /** @type {null | {aborted: boolean}} */ + [aborted] = null; + + /** + * @param {Blob} blob + * @param {{kind: "ArrayBuffer" | "Text" | "DataUrl" | "BinaryString", encoding?: string}} readtype + */ + #readOperation(blob, readtype) { + // 1. If fr’s state is "loading", throw an InvalidStateError DOMException. + if (this[state] === "loading") { + throw new DOMException( + "Invalid FileReader state.", + "InvalidStateError", + ); + } + // 2. Set fr’s state to "loading". + this[state] = "loading"; + // 3. Set fr’s result to null. + this[result] = null; + // 4. Set fr’s error to null. + this[error] = null; + + // We set this[aborted] to a new object, and keep track of it in a + // separate variable, so if a new read operation starts while there are + // remaining tasks from a previous aborted operation, the new operation + // will run while the tasks from the previous one are still aborted. + const abortedState = this[aborted] = { aborted: false }; + + // 5. Let stream be the result of calling get stream on blob. + const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream(); + + // 6. Let reader be the result of getting a reader from stream. + const reader = stream.getReader(); + + // 7. Let bytes be an empty byte sequence. + /** @type {Uint8Array[]} */ + const chunks = []; + + // 8. Let chunkPromise be the result of reading a chunk from stream with reader. + let chunkPromise = reader.read(); + + // 9. Let isFirstChunk be true. + let isFirstChunk = true; + + // 10 in parallel while true + (async () => { + while (!abortedState.aborted) { + // 1. Wait for chunkPromise to be fulfilled or rejected. + try { + const chunk = await chunkPromise; + if (abortedState.aborted) return; + + // 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr. + if (isFirstChunk) { + // TODO(lucacasonato): this is wrong, should be HTML "queue a task" + queueMicrotask(() => { + if (abortedState.aborted) return; + // fire a progress event for loadstart + const ev = new ProgressEvent("loadstart", {}); + this.dispatchEvent(ev); + }); + } + // 3. Set isFirstChunk to false. + isFirstChunk = false; + + // 4. If chunkPromise is fulfilled with an object whose done property is false + // and whose value property is a Uint8Array object, run these steps: + if ( + !chunk.done && + ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk.value) + ) { + ArrayPrototypePush(chunks, chunk.value); + + // TODO(bartlomieju): (only) If roughly 50ms have passed since last progress + { + const size = ArrayPrototypeReduce( + chunks, + (p, i) => p + i.byteLength, + 0, + ); + const ev = new ProgressEvent("progress", { + loaded: size, + }); // TODO(lucacasonato): this is wrong, should be HTML "queue a task" queueMicrotask(() => { if (abortedState.aborted) return; - // fire a progress event for loadstart - const ev = new ProgressEvent("loadstart", {}); this.dispatchEvent(ev); }); } - // 3. Set isFirstChunk to false. - isFirstChunk = false; - - // 4. If chunkPromise is fulfilled with an object whose done property is false - // and whose value property is a Uint8Array object, run these steps: - if ( - !chunk.done && - ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk.value) - ) { - ArrayPrototypePush(chunks, chunk.value); - - // TODO(bartlomieju): (only) If roughly 50ms have passed since last progress - { - const size = ArrayPrototypeReduce( - chunks, - (p, i) => p + i.byteLength, - 0, - ); - const ev = new ProgressEvent("progress", { - loaded: size, - }); - // TODO(lucacasonato): this is wrong, should be HTML "queue a task" - queueMicrotask(() => { - if (abortedState.aborted) return; - this.dispatchEvent(ev); - }); - } - chunkPromise = reader.read(); - } // 5 Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm: - else if (chunk.done === true) { - // TODO(lucacasonato): this is wrong, should be HTML "queue a task" - queueMicrotask(() => { - if (abortedState.aborted) return; - // 1. Set fr’s state to "done". - this[state] = "done"; - // 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName. - const size = ArrayPrototypeReduce( - chunks, - (p, i) => p + i.byteLength, - 0, - ); - const bytes = new Uint8Array(size); - let offs = 0; - for (let i = 0; i < chunks.length; ++i) { - const chunk = chunks[i]; - TypedArrayPrototypeSet(bytes, chunk, offs); - offs += chunk.byteLength; + chunkPromise = reader.read(); + } // 5 Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm: + else if (chunk.done === true) { + // TODO(lucacasonato): this is wrong, should be HTML "queue a task" + queueMicrotask(() => { + if (abortedState.aborted) return; + // 1. Set fr’s state to "done". + this[state] = "done"; + // 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName. + const size = ArrayPrototypeReduce( + chunks, + (p, i) => p + i.byteLength, + 0, + ); + const bytes = new Uint8Array(size); + let offs = 0; + for (let i = 0; i < chunks.length; ++i) { + const chunk = chunks[i]; + TypedArrayPrototypeSet(bytes, chunk, offs); + offs += chunk.byteLength; + } + switch (readtype.kind) { + case "ArrayBuffer": { + this[result] = bytes.buffer; + break; } - switch (readtype.kind) { - case "ArrayBuffer": { - this[result] = bytes.buffer; - break; - } - case "BinaryString": - this[result] = core.ops.op_encode_binary_string(bytes); - break; - case "Text": { - let decoder = undefined; - if (readtype.encoding) { - try { - decoder = new TextDecoder(readtype.encoding); - } catch { - // don't care about the error - } + case "BinaryString": + this[result] = ops.op_encode_binary_string(bytes); + break; + case "Text": { + let decoder = undefined; + if (readtype.encoding) { + try { + decoder = new TextDecoder(readtype.encoding); + } catch { + // don't care about the error } - if (decoder === undefined) { - const mimeType = parseMimeType(blob.type); - if (mimeType) { - const charset = MapPrototypeGet( - mimeType.parameters, - "charset", - ); - if (charset) { - try { - decoder = new TextDecoder(charset); - } catch { - // don't care about the error - } + } + if (decoder === undefined) { + const mimeType = parseMimeType(blob.type); + if (mimeType) { + const charset = MapPrototypeGet( + mimeType.parameters, + "charset", + ); + if (charset) { + try { + decoder = new TextDecoder(charset); + } catch { + // don't care about the error } } } - if (decoder === undefined) { - decoder = new TextDecoder(); - } - this[result] = decode(bytes, decoder.encoding); - break; } - case "DataUrl": { - const mediaType = blob.type || "application/octet-stream"; - this[result] = `data:${mediaType};base64,${ - forgivingBase64Encode(bytes) - }`; - break; + if (decoder === undefined) { + decoder = new TextDecoder(); } + this[result] = decode(bytes, decoder.encoding); + break; } - // 4.2 Fire a progress event called load at the fr. - { - const ev = new ProgressEvent("load", { - lengthComputable: true, - loaded: size, - total: size, - }); - this.dispatchEvent(ev); - } - - // 5. If fr’s state is not "loading", fire a progress event called loadend at the fr. - //Note: Event handler for the load or error events could have started another load, if that happens the loadend event for this load is not fired. - if (this[state] !== "loading") { - const ev = new ProgressEvent("loadend", { - lengthComputable: true, - loaded: size, - total: size, - }); - this.dispatchEvent(ev); + case "DataUrl": { + const mediaType = blob.type || "application/octet-stream"; + this[result] = `data:${mediaType};base64,${ + forgivingBase64Encode(bytes) + }`; + break; } - }); - break; - } - } catch (err) { - // TODO(lucacasonato): this is wrong, should be HTML "queue a task" - queueMicrotask(() => { - if (abortedState.aborted) return; - - // chunkPromise rejected - this[state] = "done"; - this[error] = err; - + } + // 4.2 Fire a progress event called load at the fr. { - const ev = new ProgressEvent("error", {}); + const ev = new ProgressEvent("load", { + lengthComputable: true, + loaded: size, + total: size, + }); this.dispatchEvent(ev); } - //If fr’s state is not "loading", fire a progress event called loadend at fr. - //Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired. + // 5. If fr’s state is not "loading", fire a progress event called loadend at the fr. + //Note: Event handler for the load or error events could have started another load, if that happens the loadend event for this load is not fired. if (this[state] !== "loading") { - const ev = new ProgressEvent("loadend", {}); + const ev = new ProgressEvent("loadend", { + lengthComputable: true, + loaded: size, + total: size, + }); this.dispatchEvent(ev); } }); break; } - } - })(); - } + } catch (err) { + // TODO(lucacasonato): this is wrong, should be HTML "queue a task" + queueMicrotask(() => { + if (abortedState.aborted) return; - #getEventHandlerFor(name) { - webidl.assertBranded(this, FileReaderPrototype); + // chunkPromise rejected + this[state] = "done"; + this[error] = err; - const maybeMap = this[handlerSymbol]; - if (!maybeMap) return null; + { + const ev = new ProgressEvent("error", {}); + this.dispatchEvent(ev); + } - return MapPrototypeGet(maybeMap, name)?.handler ?? null; - } + //If fr’s state is not "loading", fire a progress event called loadend at fr. + //Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired. + if (this[state] !== "loading") { + const ev = new ProgressEvent("loadend", {}); + this.dispatchEvent(ev); + } + }); + break; + } + } + })(); + } - #setEventHandlerFor(name, value) { - webidl.assertBranded(this, FileReaderPrototype); + #getEventHandlerFor(name) { + webidl.assertBranded(this, FileReaderPrototype); - if (!this[handlerSymbol]) { - this[handlerSymbol] = new Map(); - } - let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name); - if (handlerWrapper) { - handlerWrapper.handler = value; - } else { - handlerWrapper = makeWrappedHandler(value); - this.addEventListener(name, handlerWrapper); - } + const maybeMap = this[handlerSymbol]; + if (!maybeMap) return null; - MapPrototypeSet(this[handlerSymbol], name, handlerWrapper); - } + return MapPrototypeGet(maybeMap, name)?.handler ?? null; + } - constructor() { - super(); - this[webidl.brand] = webidl.brand; - } + #setEventHandlerFor(name, value) { + webidl.assertBranded(this, FileReaderPrototype); - /** @returns {number} */ - get readyState() { - webidl.assertBranded(this, FileReaderPrototype); - switch (this[state]) { - case "empty": - return FileReader.EMPTY; - case "loading": - return FileReader.LOADING; - case "done": - return FileReader.DONE; - default: - throw new TypeError("Invalid state"); - } + if (!this[handlerSymbol]) { + this[handlerSymbol] = new Map(); } - - get result() { - webidl.assertBranded(this, FileReaderPrototype); - return this[result]; + let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name); + if (handlerWrapper) { + handlerWrapper.handler = value; + } else { + handlerWrapper = makeWrappedHandler(value); + this.addEventListener(name, handlerWrapper); } - get error() { - webidl.assertBranded(this, FileReaderPrototype); - return this[error]; + MapPrototypeSet(this[handlerSymbol], name, handlerWrapper); + } + + constructor() { + super(); + this[webidl.brand] = webidl.brand; + } + + /** @returns {number} */ + get readyState() { + webidl.assertBranded(this, FileReaderPrototype); + switch (this[state]) { + case "empty": + return FileReader.EMPTY; + case "loading": + return FileReader.LOADING; + case "done": + return FileReader.DONE; + default: + throw new TypeError("Invalid state"); } + } - abort() { - webidl.assertBranded(this, FileReaderPrototype); - // If context object's state is "empty" or if context object's state is "done" set context object's result to null and terminate this algorithm. - if ( - this[state] === "empty" || - this[state] === "done" - ) { - this[result] = null; - return; - } - // If context object's state is "loading" set context object's state to "done" and set context object's result to null. - if (this[state] === "loading") { - this[state] = "done"; - this[result] = null; - } - // If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue. - // Terminate the algorithm for the read method being processed. - if (this[aborted] !== null) { - this[aborted].aborted = true; - } + get result() { + webidl.assertBranded(this, FileReaderPrototype); + return this[result]; + } - // Fire a progress event called abort at the context object. - const ev = new ProgressEvent("abort", {}); - this.dispatchEvent(ev); + get error() { + webidl.assertBranded(this, FileReaderPrototype); + return this[error]; + } - // If context object's state is not "loading", fire a progress event called loadend at the context object. - if (this[state] !== "loading") { - const ev = new ProgressEvent("loadend", {}); - this.dispatchEvent(ev); - } + abort() { + webidl.assertBranded(this, FileReaderPrototype); + // If context object's state is "empty" or if context object's state is "done" set context object's result to null and terminate this algorithm. + if ( + this[state] === "empty" || + this[state] === "done" + ) { + this[result] = null; + return; } - - /** @param {Blob} blob */ - readAsArrayBuffer(blob) { - webidl.assertBranded(this, FileReaderPrototype); - const prefix = "Failed to execute 'readAsArrayBuffer' on 'FileReader'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - this.#readOperation(blob, { kind: "ArrayBuffer" }); + // If context object's state is "loading" set context object's state to "done" and set context object's result to null. + if (this[state] === "loading") { + this[state] = "done"; + this[result] = null; } - - /** @param {Blob} blob */ - readAsBinaryString(blob) { - webidl.assertBranded(this, FileReaderPrototype); - const prefix = "Failed to execute 'readAsBinaryString' on 'FileReader'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - // alias for readAsArrayBuffer - this.#readOperation(blob, { kind: "BinaryString" }); + // If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue. + // Terminate the algorithm for the read method being processed. + if (this[aborted] !== null) { + this[aborted].aborted = true; } - /** @param {Blob} blob */ - readAsDataURL(blob) { - webidl.assertBranded(this, FileReaderPrototype); - const prefix = "Failed to execute 'readAsDataURL' on 'FileReader'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - // alias for readAsArrayBuffer - this.#readOperation(blob, { kind: "DataUrl" }); - } + // Fire a progress event called abort at the context object. + const ev = new ProgressEvent("abort", {}); + this.dispatchEvent(ev); - /** - * @param {Blob} blob - * @param {string} [encoding] - */ - readAsText(blob, encoding = undefined) { - webidl.assertBranded(this, FileReaderPrototype); - const prefix = "Failed to execute 'readAsText' on 'FileReader'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - if (encoding !== undefined) { - encoding = webidl.converters["DOMString"](encoding, { - prefix, - context: "Argument 2", - }); - } - // alias for readAsArrayBuffer - this.#readOperation(blob, { kind: "Text", encoding }); + // If context object's state is not "loading", fire a progress event called loadend at the context object. + if (this[state] !== "loading") { + const ev = new ProgressEvent("loadend", {}); + this.dispatchEvent(ev); } + } - get onerror() { - return this.#getEventHandlerFor("error"); - } - set onerror(value) { - this.#setEventHandlerFor("error", value); - } + /** @param {Blob} blob */ + readAsArrayBuffer(blob) { + webidl.assertBranded(this, FileReaderPrototype); + const prefix = "Failed to execute 'readAsArrayBuffer' on 'FileReader'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); + this.#readOperation(blob, { kind: "ArrayBuffer" }); + } - get onloadstart() { - return this.#getEventHandlerFor("loadstart"); - } - set onloadstart(value) { - this.#setEventHandlerFor("loadstart", value); - } + /** @param {Blob} blob */ + readAsBinaryString(blob) { + webidl.assertBranded(this, FileReaderPrototype); + const prefix = "Failed to execute 'readAsBinaryString' on 'FileReader'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); + // alias for readAsArrayBuffer + this.#readOperation(blob, { kind: "BinaryString" }); + } - get onload() { - return this.#getEventHandlerFor("load"); - } - set onload(value) { - this.#setEventHandlerFor("load", value); - } + /** @param {Blob} blob */ + readAsDataURL(blob) { + webidl.assertBranded(this, FileReaderPrototype); + const prefix = "Failed to execute 'readAsDataURL' on 'FileReader'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); + // alias for readAsArrayBuffer + this.#readOperation(blob, { kind: "DataUrl" }); + } - get onloadend() { - return this.#getEventHandlerFor("loadend"); - } - set onloadend(value) { - this.#setEventHandlerFor("loadend", value); + /** + * @param {Blob} blob + * @param {string} [encoding] + */ + readAsText(blob, encoding = undefined) { + webidl.assertBranded(this, FileReaderPrototype); + const prefix = "Failed to execute 'readAsText' on 'FileReader'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); + if (encoding !== undefined) { + encoding = webidl.converters["DOMString"](encoding, { + prefix, + context: "Argument 2", + }); } + // alias for readAsArrayBuffer + this.#readOperation(blob, { kind: "Text", encoding }); + } - get onprogress() { - return this.#getEventHandlerFor("progress"); - } - set onprogress(value) { - this.#setEventHandlerFor("progress", value); - } + get onerror() { + return this.#getEventHandlerFor("error"); + } + set onerror(value) { + this.#setEventHandlerFor("error", value); + } - get onabort() { - return this.#getEventHandlerFor("abort"); - } - set onabort(value) { - this.#setEventHandlerFor("abort", value); - } + get onloadstart() { + return this.#getEventHandlerFor("loadstart"); + } + set onloadstart(value) { + this.#setEventHandlerFor("loadstart", value); } - webidl.configurePrototype(FileReader); - const FileReaderPrototype = FileReader.prototype; - - ObjectDefineProperty(FileReader, "EMPTY", { - writable: false, - enumerable: true, - configurable: false, - value: 0, - }); - ObjectDefineProperty(FileReader, "LOADING", { - writable: false, - enumerable: true, - configurable: false, - value: 1, - }); - ObjectDefineProperty(FileReader, "DONE", { - writable: false, - enumerable: true, - configurable: false, - value: 2, - }); - ObjectDefineProperty(FileReader.prototype, "EMPTY", { - writable: false, - enumerable: true, - configurable: false, - value: 0, - }); - ObjectDefineProperty(FileReader.prototype, "LOADING", { - writable: false, - enumerable: true, - configurable: false, - value: 1, - }); - ObjectDefineProperty(FileReader.prototype, "DONE", { - writable: false, - enumerable: true, - configurable: false, - value: 2, - }); - - function makeWrappedHandler(handler) { - function wrappedHandler(...args) { - if (typeof wrappedHandler.handler !== "function") { - return; - } - return FunctionPrototypeCall( - wrappedHandler.handler, - this, - ...new SafeArrayIterator(args), - ); + get onload() { + return this.#getEventHandlerFor("load"); + } + set onload(value) { + this.#setEventHandlerFor("load", value); + } + + get onloadend() { + return this.#getEventHandlerFor("loadend"); + } + set onloadend(value) { + this.#setEventHandlerFor("loadend", value); + } + + get onprogress() { + return this.#getEventHandlerFor("progress"); + } + set onprogress(value) { + this.#setEventHandlerFor("progress", value); + } + + get onabort() { + return this.#getEventHandlerFor("abort"); + } + set onabort(value) { + this.#setEventHandlerFor("abort", value); + } +} + +webidl.configurePrototype(FileReader); +const FileReaderPrototype = FileReader.prototype; + +ObjectDefineProperty(FileReader, "EMPTY", { + writable: false, + enumerable: true, + configurable: false, + value: 0, +}); +ObjectDefineProperty(FileReader, "LOADING", { + writable: false, + enumerable: true, + configurable: false, + value: 1, +}); +ObjectDefineProperty(FileReader, "DONE", { + writable: false, + enumerable: true, + configurable: false, + value: 2, +}); +ObjectDefineProperty(FileReader.prototype, "EMPTY", { + writable: false, + enumerable: true, + configurable: false, + value: 0, +}); +ObjectDefineProperty(FileReader.prototype, "LOADING", { + writable: false, + enumerable: true, + configurable: false, + value: 1, +}); +ObjectDefineProperty(FileReader.prototype, "DONE", { + writable: false, + enumerable: true, + configurable: false, + value: 2, +}); + +function makeWrappedHandler(handler) { + function wrappedHandler(...args) { + if (typeof wrappedHandler.handler !== "function") { + return; } - wrappedHandler.handler = handler; - return wrappedHandler; + return FunctionPrototypeCall( + wrappedHandler.handler, + this, + ...new SafeArrayIterator(args), + ); } + wrappedHandler.handler = handler; + return wrappedHandler; +} - window.__bootstrap.fileReader = { - FileReader, - }; -})(this); +export { FileReader }; |