scala-js/scala-js-dom

Fix up `File` API

armanbilge opened this issue · 7 comments

I'm trying to tackle this issue next, but I'm wondering how to represent the options parameter

I currently have the following code:

@js.native
@JSGlobal
abstract class File(bits: js.Array[js.Any], name: String, options: FileOptions) extends Blob {

  /** Returns the name of the file. For security reasons, the path is excluded from this property. */
  def name: String = js.native

  /** The File.lastModified read-only property provides the last modified date of the file as the number of milliseconds
    * since the Unix epoch (January 1, 1970 at midnight). Files without a known last modified date return the current
    * date.
    */
  val lastModified: Int = js.native

  /** Returns the media type (MIME) of the file represented by a File object. */
  def `type`: String = js.native

  /** The File.webkitRelativePath is a read-only property that contains a string which specifies the file's path
    * relative to the directory selected by the user in an <input> element with its webkitdirectory attribute set.
    *
    * @return
    *   A string containing the path of the file relative to the ancestor directory the user selected.
    */
  def webkitRelativePath: String = js.native
}

Got any ideas or hints on how I can improve this?

@js.native
@JSGlobal
abstract class File(bits: js.Array[js.Any], name: String, options: FileOptions) extends Blob {
  def this(bits: js.Array[js.Any], name: String) = ???

A dummy constructor might work since type facade provides only type and implementation is "erased".

A dummy constructor might work since type facade provides only type and implementation is "erased".

Ah, but how would that work when you want to pass on a certain type in `options? My question was more about what kind of type could FileOptions best be?

The sttp example for example defines the options as:

@js.native
trait FilePropertyBag extends js.Object {
  def `type`: String = js.native

  def lastModified: Int = js.native
}

object FilePropertyBag {
  @inline
  def apply(
      `type`: js.UndefOr[String] = js.undefined,
      lastModified: js.UndefOr[Int] = js.undefined
  ): FilePropertyBag = {
    val result = js.Dynamic.literal()
    `type`.foreach(result.`type` = _)
    lastModified.foreach(result.lastModified = _)
    result.asInstanceOf[FilePropertyBag]
  }
}

But can we improve on this?

My question was more about what kind of type could FileOptions best be?

@zetashift great question! You can model FileOptions after any of the *Init traits in scala-js-dom.

Basically we want a trait FileOptions extends js.Object { with vars as members that default to js.undefined.

trait RequestInit extends js.Object {
var method: js.UndefOr[HttpMethod] = js.undefined

Basically we want a trait FileOptions extends js.Object { with vars as members that default to js.undefined.

Should they really default to js.undefined?
From MDN:

options Optional

An options object containing optional attributes for the file. Available options are as follows:

type

    A string representing the MIME type of the content that will be put into the file. Defaults to a value of "".
lastModified

    A number representing the number of milliseconds between the Unix time epoch and when the file was last modified. Defaults to a value of [Date.now()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now).

both options have a default value, can't I reuse that?

@zetashift Yes, I believe they should :) I think those are the defaults it uses if you pass a value of js.undefined for these options :)

@zetashift Yes, I believe they should :) I think those are the defaults it uses if you pass a value of js.undefined for these options :)

Oh TIL, thank you!