filereader.js 8.3 KB

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