Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for adding external scripts to document. #300

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions dom.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package vecty

import (
"errors"
"reflect"
"sync"
"time"
)

// batch renderer singleton
Expand Down Expand Up @@ -1282,6 +1285,62 @@ func AddStylesheet(url string) {
global().Get("document").Get("head").Call("appendChild", link)
}

var ErrTimeout = errors.New("timeout while obtaining script from URL")
var ErrTimeoutGreaterThan = errors.New("timeout value has to be greater than zero")

// AddScript adds an external script to the document
func AddScript(url string, timeout time.Duration, attributes map[string]interface{}) error {
if timeout <= 0 {
return ErrTimeoutGreaterThan
}
script := global().Get("document").Call("createElement", "script")
script.Set("src", url)
for k, v := range attributes {
script.Set(k, v)
}

quitCh := make(chan struct{})

var f jsFunc
f = funcOf(func(this jsObject, args []jsObject) interface{} {
defer f.Release()
close(quitCh)
script.Call("removeEventListener", "load", f)
return nil
})
script.Call("addEventListener", "load", f)
global().Get("document").Get("head").Call("appendChild", script)

var err error
var wg sync.WaitGroup
wg.Add(1)
go func(t time.Duration, script jsObject, f jsFunc) {

tic := time.NewTicker(10 * time.Millisecond)
start := time.Now()
loop:
for {
select {
// Stop the execution of this goroutine when the script has loaded
case <-quitCh:
wg.Done()
break loop
case <-tic.C:
if time.Since(start) > t {
defer f.Release()
defer wg.Done()
err = ErrTimeout
script.Call("removeEventListener", "load", f)
break loop
}
}
}
}(timeout,script, f)
wg.Wait()

return err
}

type jsFunc interface {
Release()
}
Expand Down
10 changes: 10 additions & 0 deletions dom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vecty
import (
"fmt"
"testing"
"time"
)

type testCore struct{ Core }
Expand Down Expand Up @@ -1124,6 +1125,15 @@ func TestAddStylesheet(t *testing.T) {
AddStylesheet("https://google.com/foobar.css")
}

// TestAddScript tests that the AddScript performs the correct DOM
// operations.
func TestAddScript(t *testing.T) {
ts := testSuite(t)
defer ts.done()

AddScript("https://google.com/foobar.js", time.Millisecond * 100,map[string]interface{}{"crossorigin": "anonymous"})
}

func TestKeyedChild_DifferentType(t *testing.T) {
ts := testSuite(t)
defer ts.done()
Expand Down
9 changes: 9 additions & 0 deletions testdata/TestAddScript.want.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
global.Get("document")
global.Get("document").Call("createElement", "script")
global.Get("document").Call("createElement", "script").Set("src", "https://google.com/foobar.js")
global.Get("document").Call("createElement", "script").Set("crossorigin", "anonymous")
global.Get("document").Call("createElement", "script").Call("addEventListener", "load", func)
global.Get("document")
global.Get("document").Get("head")
global.Get("document").Get("head").Call("appendChild", jsObject(global.Get("document").Call("createElement", "script")))
global.Get("document").Call("createElement", "script").Call("removeEventListener", "load", func)