• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3const {
4  staticPropertyDescriptors,
5  readOperation,
6  fireAProgressEvent
7} = require('./util')
8const {
9  kState,
10  kError,
11  kResult,
12  kEvents,
13  kAborted
14} = require('./symbols')
15const { webidl } = require('../fetch/webidl')
16const { kEnumerableProperty } = require('../core/util')
17
18class FileReader extends EventTarget {
19  constructor () {
20    super()
21
22    this[kState] = 'empty'
23    this[kResult] = null
24    this[kError] = null
25    this[kEvents] = {
26      loadend: null,
27      error: null,
28      abort: null,
29      load: null,
30      progress: null,
31      loadstart: null
32    }
33  }
34
35  /**
36   * @see https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
37   * @param {import('buffer').Blob} blob
38   */
39  readAsArrayBuffer (blob) {
40    webidl.brandCheck(this, FileReader)
41
42    webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' })
43
44    blob = webidl.converters.Blob(blob, { strict: false })
45
46    // The readAsArrayBuffer(blob) method, when invoked,
47    // must initiate a read operation for blob with ArrayBuffer.
48    readOperation(this, blob, 'ArrayBuffer')
49  }
50
51  /**
52   * @see https://w3c.github.io/FileAPI/#readAsBinaryString
53   * @param {import('buffer').Blob} blob
54   */
55  readAsBinaryString (blob) {
56    webidl.brandCheck(this, FileReader)
57
58    webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' })
59
60    blob = webidl.converters.Blob(blob, { strict: false })
61
62    // The readAsBinaryString(blob) method, when invoked,
63    // must initiate a read operation for blob with BinaryString.
64    readOperation(this, blob, 'BinaryString')
65  }
66
67  /**
68   * @see https://w3c.github.io/FileAPI/#readAsDataText
69   * @param {import('buffer').Blob} blob
70   * @param {string?} encoding
71   */
72  readAsText (blob, encoding = undefined) {
73    webidl.brandCheck(this, FileReader)
74
75    webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' })
76
77    blob = webidl.converters.Blob(blob, { strict: false })
78
79    if (encoding !== undefined) {
80      encoding = webidl.converters.DOMString(encoding)
81    }
82
83    // The readAsText(blob, encoding) method, when invoked,
84    // must initiate a read operation for blob with Text and encoding.
85    readOperation(this, blob, 'Text', encoding)
86  }
87
88  /**
89   * @see https://w3c.github.io/FileAPI/#dfn-readAsDataURL
90   * @param {import('buffer').Blob} blob
91   */
92  readAsDataURL (blob) {
93    webidl.brandCheck(this, FileReader)
94
95    webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' })
96
97    blob = webidl.converters.Blob(blob, { strict: false })
98
99    // The readAsDataURL(blob) method, when invoked, must
100    // initiate a read operation for blob with DataURL.
101    readOperation(this, blob, 'DataURL')
102  }
103
104  /**
105   * @see https://w3c.github.io/FileAPI/#dfn-abort
106   */
107  abort () {
108    // 1. If this's state is "empty" or if this's state is
109    //    "done" set this's result to null and terminate
110    //    this algorithm.
111    if (this[kState] === 'empty' || this[kState] === 'done') {
112      this[kResult] = null
113      return
114    }
115
116    // 2. If this's state is "loading" set this's state to
117    //    "done" and set this's result to null.
118    if (this[kState] === 'loading') {
119      this[kState] = 'done'
120      this[kResult] = null
121    }
122
123    // 3. If there are any tasks from this on the file reading
124    //    task source in an affiliated task queue, then remove
125    //    those tasks from that task queue.
126    this[kAborted] = true
127
128    // 4. Terminate the algorithm for the read method being processed.
129    // TODO
130
131    // 5. Fire a progress event called abort at this.
132    fireAProgressEvent('abort', this)
133
134    // 6. If this's state is not "loading", fire a progress
135    //    event called loadend at this.
136    if (this[kState] !== 'loading') {
137      fireAProgressEvent('loadend', this)
138    }
139  }
140
141  /**
142   * @see https://w3c.github.io/FileAPI/#dom-filereader-readystate
143   */
144  get readyState () {
145    webidl.brandCheck(this, FileReader)
146
147    switch (this[kState]) {
148      case 'empty': return this.EMPTY
149      case 'loading': return this.LOADING
150      case 'done': return this.DONE
151    }
152  }
153
154  /**
155   * @see https://w3c.github.io/FileAPI/#dom-filereader-result
156   */
157  get result () {
158    webidl.brandCheck(this, FileReader)
159
160    // The result attribute’s getter, when invoked, must return
161    // this's result.
162    return this[kResult]
163  }
164
165  /**
166   * @see https://w3c.github.io/FileAPI/#dom-filereader-error
167   */
168  get error () {
169    webidl.brandCheck(this, FileReader)
170
171    // The error attribute’s getter, when invoked, must return
172    // this's error.
173    return this[kError]
174  }
175
176  get onloadend () {
177    webidl.brandCheck(this, FileReader)
178
179    return this[kEvents].loadend
180  }
181
182  set onloadend (fn) {
183    webidl.brandCheck(this, FileReader)
184
185    if (this[kEvents].loadend) {
186      this.removeEventListener('loadend', this[kEvents].loadend)
187    }
188
189    if (typeof fn === 'function') {
190      this[kEvents].loadend = fn
191      this.addEventListener('loadend', fn)
192    } else {
193      this[kEvents].loadend = null
194    }
195  }
196
197  get onerror () {
198    webidl.brandCheck(this, FileReader)
199
200    return this[kEvents].error
201  }
202
203  set onerror (fn) {
204    webidl.brandCheck(this, FileReader)
205
206    if (this[kEvents].error) {
207      this.removeEventListener('error', this[kEvents].error)
208    }
209
210    if (typeof fn === 'function') {
211      this[kEvents].error = fn
212      this.addEventListener('error', fn)
213    } else {
214      this[kEvents].error = null
215    }
216  }
217
218  get onloadstart () {
219    webidl.brandCheck(this, FileReader)
220
221    return this[kEvents].loadstart
222  }
223
224  set onloadstart (fn) {
225    webidl.brandCheck(this, FileReader)
226
227    if (this[kEvents].loadstart) {
228      this.removeEventListener('loadstart', this[kEvents].loadstart)
229    }
230
231    if (typeof fn === 'function') {
232      this[kEvents].loadstart = fn
233      this.addEventListener('loadstart', fn)
234    } else {
235      this[kEvents].loadstart = null
236    }
237  }
238
239  get onprogress () {
240    webidl.brandCheck(this, FileReader)
241
242    return this[kEvents].progress
243  }
244
245  set onprogress (fn) {
246    webidl.brandCheck(this, FileReader)
247
248    if (this[kEvents].progress) {
249      this.removeEventListener('progress', this[kEvents].progress)
250    }
251
252    if (typeof fn === 'function') {
253      this[kEvents].progress = fn
254      this.addEventListener('progress', fn)
255    } else {
256      this[kEvents].progress = null
257    }
258  }
259
260  get onload () {
261    webidl.brandCheck(this, FileReader)
262
263    return this[kEvents].load
264  }
265
266  set onload (fn) {
267    webidl.brandCheck(this, FileReader)
268
269    if (this[kEvents].load) {
270      this.removeEventListener('load', this[kEvents].load)
271    }
272
273    if (typeof fn === 'function') {
274      this[kEvents].load = fn
275      this.addEventListener('load', fn)
276    } else {
277      this[kEvents].load = null
278    }
279  }
280
281  get onabort () {
282    webidl.brandCheck(this, FileReader)
283
284    return this[kEvents].abort
285  }
286
287  set onabort (fn) {
288    webidl.brandCheck(this, FileReader)
289
290    if (this[kEvents].abort) {
291      this.removeEventListener('abort', this[kEvents].abort)
292    }
293
294    if (typeof fn === 'function') {
295      this[kEvents].abort = fn
296      this.addEventListener('abort', fn)
297    } else {
298      this[kEvents].abort = null
299    }
300  }
301}
302
303// https://w3c.github.io/FileAPI/#dom-filereader-empty
304FileReader.EMPTY = FileReader.prototype.EMPTY = 0
305// https://w3c.github.io/FileAPI/#dom-filereader-loading
306FileReader.LOADING = FileReader.prototype.LOADING = 1
307// https://w3c.github.io/FileAPI/#dom-filereader-done
308FileReader.DONE = FileReader.prototype.DONE = 2
309
310Object.defineProperties(FileReader.prototype, {
311  EMPTY: staticPropertyDescriptors,
312  LOADING: staticPropertyDescriptors,
313  DONE: staticPropertyDescriptors,
314  readAsArrayBuffer: kEnumerableProperty,
315  readAsBinaryString: kEnumerableProperty,
316  readAsText: kEnumerableProperty,
317  readAsDataURL: kEnumerableProperty,
318  abort: kEnumerableProperty,
319  readyState: kEnumerableProperty,
320  result: kEnumerableProperty,
321  error: kEnumerableProperty,
322  onloadstart: kEnumerableProperty,
323  onprogress: kEnumerableProperty,
324  onload: kEnumerableProperty,
325  onabort: kEnumerableProperty,
326  onerror: kEnumerableProperty,
327  onloadend: kEnumerableProperty,
328  [Symbol.toStringTag]: {
329    value: 'FileReader',
330    writable: false,
331    enumerable: false,
332    configurable: true
333  }
334})
335
336Object.defineProperties(FileReader, {
337  EMPTY: staticPropertyDescriptors,
338  LOADING: staticPropertyDescriptors,
339  DONE: staticPropertyDescriptors
340})
341
342module.exports = {
343  FileReader
344}
345