mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
internal/ui: bug fix: dropping multiple files didn't work on Firefox and Safari
Closes #3045
This commit is contained in:
parent
95ad1b158c
commit
1843f6acc1
@ -24,13 +24,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FileEntryFS struct {
|
type FileEntryFS struct {
|
||||||
rootEntry js.Value
|
rootEntries []js.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileEntryFS(root js.Value) *FileEntryFS {
|
func NewFileEntryFS(rootEntries []js.Value) (*FileEntryFS, error) {
|
||||||
return &FileEntryFS{
|
// Check all the full paths are the same.
|
||||||
rootEntry: root,
|
var fullpath string
|
||||||
|
for _, ent := range rootEntries {
|
||||||
|
if fullpath == "" {
|
||||||
|
fullpath = ent.Get("fullPath").String()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fullpath != ent.Get("fullPath").String() {
|
||||||
|
return nil, errors.New("file: all the full paths must be the same")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return &FileEntryFS{
|
||||||
|
rootEntries: rootEntries,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileEntryFS) Open(name string) (fs.File, error) {
|
func (f *FileEntryFS) Open(name string) (fs.File, error) {
|
||||||
@ -43,33 +54,55 @@ func (f *FileEntryFS) Open(name string) (fs.File, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if name == "." {
|
if name == "." {
|
||||||
return &dir{dirEntry: f.rootEntry}, nil
|
var dirName string
|
||||||
|
for _, ent := range f.rootEntries {
|
||||||
|
if dirName == "" {
|
||||||
|
dirName = ent.Get("name").String()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dirName != ent.Get("name").String() {
|
||||||
|
return nil, &fs.PathError{
|
||||||
|
Op: "open",
|
||||||
|
Path: name,
|
||||||
|
Err: errors.New("invalid directory"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &dir{
|
||||||
|
name: dirName,
|
||||||
|
dirEntries: f.rootEntries,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var chEntry chan js.Value
|
for _, ent := range f.rootEntries {
|
||||||
cbSuccess := js.FuncOf(func(this js.Value, args []js.Value) any {
|
var chEntry chan js.Value
|
||||||
chEntry <- args[0]
|
cbSuccess := js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
close(chEntry)
|
chEntry <- args[0]
|
||||||
return nil
|
close(chEntry)
|
||||||
})
|
return nil
|
||||||
defer cbSuccess.Release()
|
})
|
||||||
|
defer cbSuccess.Release()
|
||||||
|
|
||||||
cbFailure := js.FuncOf(func(this js.Value, args []js.Value) any {
|
cbFailure := js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
close(chEntry)
|
close(chEntry)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
defer cbFailure.Release()
|
defer cbFailure.Release()
|
||||||
|
|
||||||
chEntry = make(chan js.Value)
|
chEntry = make(chan js.Value)
|
||||||
f.rootEntry.Call("getFile", name, nil, cbSuccess, cbFailure)
|
ent.Call("getFile", name, nil, cbSuccess, cbFailure)
|
||||||
if entry := <-chEntry; entry.Truthy() {
|
if entry := <-chEntry; entry.Truthy() {
|
||||||
return &file{entry: entry}, nil
|
return &file{entry: entry}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chEntry = make(chan js.Value)
|
chEntry = make(chan js.Value)
|
||||||
f.rootEntry.Call("getDirectory", name, nil, cbSuccess, cbFailure)
|
ent.Call("getDirectory", name, nil, cbSuccess, cbFailure)
|
||||||
if entry := <-chEntry; entry.Truthy() {
|
if entry := <-chEntry; entry.Truthy() {
|
||||||
return &dir{dirEntry: entry}, nil
|
return &dir{
|
||||||
|
name: entry.Get("name").String(),
|
||||||
|
dirEntries: []js.Value{entry},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &fs.PathError{
|
return nil, &fs.PathError{
|
||||||
@ -163,21 +196,22 @@ func (f *file) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type dir struct {
|
type dir struct {
|
||||||
dirEntry js.Value
|
name string
|
||||||
|
dirEntries []js.Value
|
||||||
fileEntries []js.Value
|
fileEntries []js.Value
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dir) Stat() (fs.FileInfo, error) {
|
func (d *dir) Stat() (fs.FileInfo, error) {
|
||||||
return &fileInfo{
|
return &fileInfo{
|
||||||
name: d.dirEntry.Get("name").String(),
|
name: d.name,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dir) Read(buf []byte) (int, error) {
|
func (d *dir) Read(buf []byte) (int, error) {
|
||||||
return 0, &fs.PathError{
|
return 0, &fs.PathError{
|
||||||
Op: "read",
|
Op: "read",
|
||||||
Path: d.dirEntry.Get("name").String(),
|
Path: d.name,
|
||||||
Err: errors.New("is a directory"),
|
Err: errors.New("is a directory"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,39 +222,48 @@ func (d *dir) Close() error {
|
|||||||
|
|
||||||
func (d *dir) ReadDir(count int) ([]fs.DirEntry, error) {
|
func (d *dir) ReadDir(count int) ([]fs.DirEntry, error) {
|
||||||
if d.fileEntries == nil {
|
if d.fileEntries == nil {
|
||||||
ch := make(chan struct{})
|
names := map[string]struct{}{}
|
||||||
var rec js.Func
|
for _, dirEntry := range d.dirEntries {
|
||||||
cb := js.FuncOf(func(this js.Value, args []js.Value) any {
|
ch := make(chan struct{})
|
||||||
entries := args[0]
|
var rec js.Func
|
||||||
if entries.Length() == 0 {
|
cb := js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
close(ch)
|
entries := args[0]
|
||||||
|
if entries.Length() == 0 {
|
||||||
|
close(ch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := 0; i < entries.Length(); i++ {
|
||||||
|
ent := entries.Index(i)
|
||||||
|
name := ent.Get("name").String()
|
||||||
|
// A name can be empty when this directory is a root directory.
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Avoid entry duplications. Entry duplications happen when multiple files are dropped on Chrome.
|
||||||
|
if _, ok := names[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !ent.Get("isFile").Bool() && !ent.Get("isDirectory").Bool() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d.fileEntries = append(d.fileEntries, ent)
|
||||||
|
names[name] = struct{}{}
|
||||||
|
}
|
||||||
|
rec.Value.Call("call")
|
||||||
return nil
|
return nil
|
||||||
}
|
})
|
||||||
for i := 0; i < entries.Length(); i++ {
|
defer cb.Release()
|
||||||
ent := entries.Index(i)
|
|
||||||
// A name can be empty when this directory is a root directory.
|
reader := dirEntry.Call("createReader")
|
||||||
if ent.Get("name").String() == "" {
|
rec = js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
continue
|
reader.Call("readEntries", cb)
|
||||||
}
|
return nil
|
||||||
if !ent.Get("isFile").Bool() && !ent.Get("isDirectory").Bool() {
|
})
|
||||||
continue
|
defer rec.Release()
|
||||||
}
|
|
||||||
d.fileEntries = append(d.fileEntries, ent)
|
|
||||||
}
|
|
||||||
rec.Value.Call("call")
|
rec.Value.Call("call")
|
||||||
return nil
|
<-ch
|
||||||
})
|
}
|
||||||
defer cb.Release()
|
|
||||||
|
|
||||||
reader := d.dirEntry.Call("createReader")
|
|
||||||
rec = js.FuncOf(func(this js.Value, args []js.Value) any {
|
|
||||||
reader.Call("readEntries", cb)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
defer rec.Release()
|
|
||||||
|
|
||||||
rec.Value.Call("call")
|
|
||||||
<-ch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n := len(d.fileEntries) - d.offset
|
n := len(d.fileEntries) - d.offset
|
||||||
|
@ -707,14 +707,21 @@ func (u *UserInterface) appendDroppedFiles(data js.Value) {
|
|||||||
defer u.dropFileM.Unlock()
|
defer u.dropFileM.Unlock()
|
||||||
items := data.Get("items")
|
items := data.Get("items")
|
||||||
|
|
||||||
|
var entries []js.Value
|
||||||
for i := 0; i < items.Length(); i++ {
|
for i := 0; i < items.Length(); i++ {
|
||||||
kind := items.Index(i).Get("kind").String()
|
kind := items.Index(i).Get("kind").String()
|
||||||
switch kind {
|
switch kind {
|
||||||
case "file":
|
case "file":
|
||||||
fs := items.Index(i).Call("webkitGetAsEntry").Get("filesystem").Get("root")
|
entries = append(entries, items.Index(i).Call("webkitGetAsEntry").Get("filesystem").Get("root"))
|
||||||
u.inputState.DroppedFiles = file.NewFileEntryFS(fs)
|
}
|
||||||
|
}
|
||||||
|
if len(entries) > 0 {
|
||||||
|
fs, err := file.NewFileEntryFS(entries)
|
||||||
|
if err != nil {
|
||||||
|
u.setError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
u.inputState.DroppedFiles = fs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user