Skip to content

Commit

Permalink
internal/ui: more precise detection of directory on browsers
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Jan 22, 2023
1 parent e03cb0d commit 84e32c2
Showing 1 changed file with 80 additions and 29 deletions.
109 changes: 80 additions & 29 deletions internal/ui/ui_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ type userInterfaceImpl struct {

keyboardLayoutMap js.Value

m sync.Mutex
m sync.Mutex
dropFileM sync.Mutex
}

func init() {
Expand Down Expand Up @@ -640,14 +641,44 @@ func setCanvasEventHandlers(v js.Value) {
return nil
}

files := data.Get("files")
for i := 0; i < files.Length(); i++ {
theUI.inputState.DroppedFiles = append(theUI.inputState.DroppedFiles, &file{v: files.Index(i)})
}
go theUI.appendDroppedFiles(data)
return nil
}))
}

func (u *userInterfaceImpl) appendDroppedFiles(data js.Value) {
u.dropFileM.Lock()
defer u.dropFileM.Unlock()

chFile := make(chan js.Value, 1)
cbFile := js.FuncOf(func(this js.Value, args []js.Value) any {
chFile <- args[0]
return nil
})
defer cbFile.Release()

items := data.Get("items")
for i := 0; i < items.Length(); i++ {
entry := items.Index(i).Call("webkitGetAsEntry")
var f fs.File
switch {
case entry.Get("isFile").Bool():
entry.Call("file", cbFile)
jsFile := <-chFile
f = &file{
v: jsFile,
}
case entry.Get("isDirectory").Bool():
f = &dir{
entry: entry,
}
default:
continue
}
u.inputState.DroppedFiles = append(u.inputState.DroppedFiles, f)
}
}

func (u *userInterfaceImpl) forceUpdateOnMinimumFPSMode() {
if u.fpsMode != FPSModeVsyncOffMinimum {
return
Expand Down Expand Up @@ -780,9 +811,7 @@ func (f *file) Close() error {
}

type fileInfo struct {
v js.Value
isDir bool
isDirOnce sync.Once
v js.Value
}

func (f *fileInfo) Name() string {
Expand All @@ -802,31 +831,53 @@ func (f *fileInfo) ModTime() time.Time {
}

func (f *fileInfo) IsDir() bool {
f.isDirOnce.Do(func() {
ch := make(chan struct{})
return false
}

cbThen := js.FuncOf(func(this js.Value, args []js.Value) any {
close(ch)
return nil
})
defer cbThen.Release()
func (f *fileInfo) Sys() any {
return nil
}

cbCatch := js.FuncOf(func(this js.Value, args []js.Value) any {
// This is not a reliable way to check whether the file is a directory or not.
// https://developer.mozilla.org/en-US/docs/Web/API/File
// TODO: Should the file system API be used?
f.isDir = true
close(ch)
return nil
})
defer cbCatch.Release()
type dir struct {
entry js.Value
}

f.v.Call("arrayBuffer").Call("then", cbThen).Call("catch", cbCatch)
<-ch
})
return f.isDir
func (d *dir) Stat() (fs.FileInfo, error) {
return &dirInfo{entry: d.entry}, nil
}

func (f *fileInfo) Sys() any {
func (d *dir) Read(buf []byte) (int, error) {
return 0, fmt.Errorf("%s is a directory", d.entry.Get("name").String())
}

func (d *dir) Close() error {
return nil
}

type dirInfo struct {
entry js.Value
}

func (d *dirInfo) Name() string {
return d.entry.Get("name").String()
}

func (d *dirInfo) Size() int64 {
return 0
}

func (d *dirInfo) Mode() fs.FileMode {
return 0400 | fs.ModeDir
}

func (d *dirInfo) ModTime() time.Time {
return time.Time{}
}

func (d *dirInfo) IsDir() bool {
return true
}

func (d *dirInfo) Sys() any {
return nil
}

0 comments on commit 84e32c2

Please sign in to comment.