├── example ├── video.mp4 ├── html │ ├── video.mp4 │ ├── wasm.wasm │ ├── index.html │ ├── wasm.js │ └── wasm_exec.js ├── index.html ├── wasm.js ├── wasm-server │ └── main.go ├── wasm.go └── wasm_exec.js ├── elements ├── form │ ├── errors.go │ ├── methods.go │ ├── output.go │ ├── fieldset.go │ └── form.go ├── input │ ├── errors.go │ ├── datalist.go │ ├── types.go │ └── input.go ├── href │ └── href.go ├── li │ └── li.go ├── label │ └── label.go ├── media │ ├── track.go │ └── video.go ├── a │ ├── rel.go │ └── a.go ├── nav │ └── nav.go ├── table │ └── table.go ├── img │ └── img.go └── picture │ ├── source.go │ └── picture.go ├── targets.go ├── navigator.go ├── Makefile ├── .gitignore ├── tokenlist.go ├── xslt.go ├── history.go ├── event.go ├── location.go ├── storage.go ├── document.go ├── window.go ├── xmlhttprequest.go ├── README.md ├── element.go ├── LICENSE └── css.go /example/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nerzal/tinydom/HEAD/example/video.mp4 -------------------------------------------------------------------------------- /example/html/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nerzal/tinydom/HEAD/example/html/video.mp4 -------------------------------------------------------------------------------- /example/html/wasm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nerzal/tinydom/HEAD/example/html/wasm.wasm -------------------------------------------------------------------------------- /elements/form/errors.go: -------------------------------------------------------------------------------- 1 | package form 2 | 3 | import "errors" 4 | 5 | var ErrInvalidTagAppended = errors.New("invalid tag appended") 6 | -------------------------------------------------------------------------------- /elements/input/errors.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | import "errors" 4 | 5 | var ErrInvalidAttribute = errors.New("invalid attribute provided for input type") 6 | -------------------------------------------------------------------------------- /elements/form/methods.go: -------------------------------------------------------------------------------- 1 | package form 2 | 3 | type Method string 4 | 5 | const ( 6 | GET Method = "get" 7 | POST Method = "post" 8 | ) 9 | 10 | func (m Method) String() string { 11 | return string(m) 12 | } 13 | -------------------------------------------------------------------------------- /targets.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | type Target string 4 | 5 | const ( 6 | Blank Target = "_blank" 7 | Self Target = "_self" 8 | Parent Target = "_parent" 9 | Top Target = "_top" 10 | ) 11 | 12 | func (t Target) String() string { 13 | return string(t) 14 | } 15 | -------------------------------------------------------------------------------- /navigator.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type Navigator struct { 6 | js.Value 7 | } 8 | 9 | func (n *Navigator) Language() string { 10 | return n.Get("language").String() 11 | } 12 | 13 | func (n *Navigator) Languages() string { 14 | return n.Get("languages").String() 15 | } 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | example-app: 2 | rm -rf example/html 3 | mkdir example/html 4 | tinygo build -o example/html/wasm.wasm -target wasm -no-debug example/wasm.go 5 | cp example/wasm_exec.js example/html/ 6 | cp example/wasm.js example/html/ 7 | cp example/index.html example/html/ 8 | cp example/video.mp4 example/html/ 9 | go run example/wasm-server/main.go -------------------------------------------------------------------------------- /elements/href/href.go: -------------------------------------------------------------------------------- 1 | package href 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type Href struct { 6 | *tinydom.Element 7 | } 8 | 9 | func New(link, innerHTML string) *Href { 10 | a := tinydom.GetDocument().CreateElement("a") 11 | a.Set("href", link) 12 | a.Set("target", "_blank") 13 | a.SetInnerHTML(innerHTML) 14 | return &Href{a} 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .vscode 18 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TinyDom 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /elements/li/li.go: -------------------------------------------------------------------------------- 1 | package li 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | // Li is a li element 6 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li for reference 7 | type Li struct { 8 | *tinydom.Element 9 | } 10 | 11 | func New() *Li { 12 | doc := tinydom.GetDocument() 13 | element := doc.CreateElement("li") 14 | 15 | return &Li{ 16 | Element: element, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TinyDom 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /elements/label/label.go: -------------------------------------------------------------------------------- 1 | package label 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type Label struct { 6 | *tinydom.Element 7 | } 8 | 9 | func New() *Label { 10 | return &Label{tinydom.GetDocument().CreateElement("label")} 11 | } 12 | 13 | func (l *Label) SetFor(value string) *Label { 14 | l.SetAttribute("for", value) 15 | return l 16 | } 17 | 18 | func (l *Label) For() string { 19 | return l.Get("for").String() 20 | } 21 | -------------------------------------------------------------------------------- /elements/media/track.go: -------------------------------------------------------------------------------- 1 | package media 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | // 6 | 7 | type Track struct { 8 | *tinydom.Element 9 | } 10 | 11 | func NewTrack(src, kind, srcLang, label string) *Track { 12 | trackElem := tinydom.GetDocument().CreateElement("track") 13 | trackElem.Set("src", src) 14 | trackElem.Set("kind", kind) 15 | trackElem.Set("srcLang", srcLang) 16 | trackElem.Set("label", label) 17 | 18 | return &Track{trackElem} 19 | } 20 | -------------------------------------------------------------------------------- /elements/form/output.go: -------------------------------------------------------------------------------- 1 | package form 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type Output struct { 6 | *tinydom.Element 7 | } 8 | 9 | func NewOutput(name string, forValue ...string) *Output { 10 | output := tinydom.GetDocument().CreateElement("output") 11 | output.Set("name", name) 12 | 13 | if forValue != nil { 14 | forAttribute := "" 15 | 16 | for i, value := range forValue { 17 | forAttribute += value 18 | if i != len(forValue) { 19 | forAttribute += " " 20 | } 21 | } 22 | } 23 | 24 | return &Output{output} 25 | } 26 | -------------------------------------------------------------------------------- /elements/input/datalist.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type DataList struct { 6 | *tinydom.Element 7 | } 8 | 9 | func NewDataList(id string, options []string) *DataList { 10 | doc := tinydom.GetDocument() 11 | 12 | result := doc.CreateElement("datalist") 13 | result.SetId(id) 14 | 15 | for i := range options { 16 | option := options[i] 17 | 18 | optElem := doc.CreateElement("option") 19 | optElem.Set("value", option) 20 | result.AppendChild(optElem) 21 | } 22 | 23 | return &DataList{result} 24 | } 25 | -------------------------------------------------------------------------------- /tokenlist.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type DOMTokenList struct { 6 | js.Value 7 | } 8 | 9 | func (t *DOMTokenList) Length() int { 10 | return t.Get("length").Int() 11 | } 12 | 13 | func (t *DOMTokenList) Contains(s string) bool { 14 | return t.Call("contains", s).Bool() 15 | } 16 | 17 | func (t *DOMTokenList) Add(s string) { 18 | t.Call("add", s) 19 | } 20 | 21 | func (t *DOMTokenList) Remove(s string) { 22 | t.Call("remove", s) 23 | } 24 | 25 | func (t *DOMTokenList) Toggle(s string) { 26 | t.Call("toggle", s) 27 | } 28 | -------------------------------------------------------------------------------- /elements/a/rel.go: -------------------------------------------------------------------------------- 1 | package a 2 | 3 | type Rel string 4 | 5 | // See https://www.w3schools.com/tags/att_a_rel.asp for reference 6 | const ( 7 | Alternate Rel = "alternate" 8 | Author Rel = "author" 9 | Bookmark Rel = "bookmark" 10 | External Rel = "external" 11 | Help Rel = "help" 12 | License Rel = "license" 13 | Next Rel = "next" 14 | Nofollow Rel = "nofollow" 15 | Noreferrer Rel = "noreferrer" 16 | Noopener Rel = "noopener" 17 | Prev Rel = "prev" 18 | Search Rel = "search" 19 | Tag Rel = "tag" 20 | ) 21 | -------------------------------------------------------------------------------- /xslt.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type XSLTProcessor struct { 6 | js.Value 7 | } 8 | 9 | func NewXSLTProcessor() *XSLTProcessor { 10 | return &XSLTProcessor{GetWindow().Get("XSLTProcessor").New()} 11 | } 12 | 13 | func (x *XSLTProcessor) ImportStylesheet(node *Element) { 14 | x.Call("importStylesheet", node) 15 | } 16 | 17 | func (x *XSLTProcessor) TransformToFragment(node, document *Element) *Element { 18 | return &Element{x.Call("transformToFragment", node, document)} 19 | } 20 | 21 | func (x *XSLTProcessor) TransformToDocument(node *Element) *Element { 22 | return &Element{x.Call("transformToDocument", node)} 23 | } 24 | -------------------------------------------------------------------------------- /history.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import ( 4 | "syscall/js" 5 | ) 6 | 7 | type History struct { 8 | js.Value 9 | } 10 | 11 | func (h *History) Length() int { 12 | return h.Get("length").Int() 13 | } 14 | 15 | func (h *History) Back() { 16 | h.Call("back") 17 | } 18 | 19 | func (h *History) Forward() { 20 | h.Call("forward") 21 | } 22 | 23 | func (h *History) Go(p int) { 24 | h.Call("go", p) 25 | } 26 | 27 | func (h *History) PushState(state interface{}, title, url string) { 28 | h.Call("pushState", state, title, url) 29 | } 30 | 31 | func (h *History) ReplaceState(state interface{}, title, url string) { 32 | h.Call("replaceState", state, title, url) 33 | } 34 | -------------------------------------------------------------------------------- /event.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type Event struct { 6 | js.Value 7 | } 8 | 9 | func (e *Event) Target() *Element { 10 | return &Element{e.Get("target")} 11 | } 12 | 13 | func (e *Event) PreventDefault() { 14 | e.Call("preventDefault") 15 | } 16 | 17 | func (e *Event) StopImmediatePropagation() { 18 | e.Call("stopImmediatePropagation") 19 | } 20 | 21 | func (e *Event) StopPropagation() { 22 | e.Call("stopPropagation") 23 | } 24 | 25 | func (e *Event) Code() string { 26 | return e.Get("code").String() 27 | } 28 | 29 | func (e *Event) Key() string { 30 | return e.Get("key").String() 31 | } 32 | 33 | func (e *Event) KeyCode() int { 34 | return e.Get("keyCode").Int() 35 | } 36 | -------------------------------------------------------------------------------- /example/wasm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WASM_URL = 'wasm.wasm'; 4 | var wasm; 5 | 6 | function init() { 7 | const go = new Go(); 8 | if ('instantiateStreaming' in WebAssembly) { 9 | WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function(obj) { 10 | wasm = obj.instance; 11 | go.run(wasm); 12 | }) 13 | } else { 14 | fetch(WASM_URL).then(resp => 15 | resp.arrayBuffer() 16 | ).then(bytes => 17 | WebAssembly.instantiate(bytes, go.importObject).then(function(obj) { 18 | wasm = obj.instance; 19 | go.run(wasm); 20 | }) 21 | ) 22 | } 23 | } 24 | 25 | init(); -------------------------------------------------------------------------------- /example/html/wasm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WASM_URL = 'wasm.wasm'; 4 | var wasm; 5 | 6 | function init() { 7 | const go = new Go(); 8 | if ('instantiateStreaming' in WebAssembly) { 9 | WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function(obj) { 10 | wasm = obj.instance; 11 | go.run(wasm); 12 | }) 13 | } else { 14 | fetch(WASM_URL).then(resp => 15 | resp.arrayBuffer() 16 | ).then(bytes => 17 | WebAssembly.instantiate(bytes, go.importObject).then(function(obj) { 18 | wasm = obj.instance; 19 | go.run(wasm); 20 | }) 21 | ) 22 | } 23 | } 24 | 25 | init(); -------------------------------------------------------------------------------- /elements/nav/nav.go: -------------------------------------------------------------------------------- 1 | package nav 2 | 3 | import ( 4 | "github.com/Nerzal/tinydom" 5 | "github.com/Nerzal/tinydom/elements/li" 6 | ) 7 | 8 | // Nav is a nav element 9 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav for reference 10 | type Nav struct { 11 | *tinydom.Element 12 | ulElement *tinydom.Element 13 | } 14 | 15 | // New creates a new instance of Nav 16 | func New() *Nav { 17 | doc := tinydom.GetDocument() 18 | element := doc.CreateElement("nav") 19 | ulElement := doc.CreateElement("ul") 20 | 21 | element.AppendChild(ulElement) 22 | 23 | return &Nav{ 24 | Element: element, 25 | ulElement: ulElement, 26 | } 27 | } 28 | 29 | func (n *Nav) AppendListItem(item *li.Li) *Nav { 30 | n.ulElement.AppendChild(item.Element) 31 | return n 32 | } 33 | -------------------------------------------------------------------------------- /location.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type Location struct { 6 | js.Value 7 | } 8 | 9 | func (l *Location) Host() string { 10 | return l.Get("host").String() 11 | } 12 | 13 | func (l *Location) Hostname() string { 14 | return l.Get("hostname").String() 15 | } 16 | 17 | func (l *Location) Href() string { 18 | return l.Get("href").String() 19 | } 20 | 21 | func (l *Location) Origin() string { 22 | return l.Get("origin").String() 23 | } 24 | 25 | func (l *Location) Pathname() string { 26 | return l.Get("pathname").String() 27 | } 28 | 29 | func (l *Location) Port() string { 30 | return l.Get("port").String() 31 | } 32 | 33 | func (l *Location) Protocol() string { 34 | return l.Get("protocol").String() 35 | } 36 | 37 | func (l *Location) Search() string { 38 | return l.Get("search").String() 39 | } 40 | -------------------------------------------------------------------------------- /elements/table/table.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type Table struct { 6 | *tinydom.Element 7 | } 8 | 9 | func New() *Table { 10 | element := tinydom.GetDocument().CreateElement("table") 11 | return &Table{element} 12 | } 13 | 14 | func (t *Table) SetHeader(header ...string) *Table { 15 | doc := tinydom.GetDocument() 16 | head := doc.CreateElement("thead") 17 | 18 | tr := doc.CreateElement("tr") 19 | head.AppendChild(tr) 20 | 21 | for _, thead := range header { 22 | headElement := doc.CreateElement("th").SetInnerHTML(thead) 23 | tr.AppendChild(headElement) 24 | } 25 | 26 | t.AppendChild(head) 27 | return t 28 | } 29 | 30 | func (t *Table) SetBody(element *tinydom.Element) *Table { 31 | t.AppendChild(element) 32 | return t 33 | } 34 | 35 | func (t *Table) Body() *tinydom.Element { 36 | return t.FindChildNode("tbody") 37 | } 38 | -------------------------------------------------------------------------------- /storage.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type Storage struct { 6 | js.Value 7 | } 8 | 9 | var LocalStorage = &Storage{GetWindow().Get("localStorage")} 10 | var SessionStorage = &Storage{GetWindow().Get("sessionStorage")} 11 | 12 | func (s *Storage) Length() int { 13 | return s.Get("length").Int() 14 | } 15 | 16 | func (s *Storage) Key(index int) string { 17 | return s.Call("key", index).String() 18 | } 19 | 20 | func (s *Storage) GetItem(key string) string { 21 | return s.Call("getItem", key).String() 22 | } 23 | 24 | func (s *Storage) SetItem(key, value string) { 25 | s.Call("setItem", key, value) 26 | } 27 | 28 | func (s *Storage) RemoveItem(key string) { 29 | s.Call("removeItem", key) 30 | } 31 | 32 | func (s *Storage) Clear() { 33 | s.Call("clear") 34 | } 35 | 36 | func (s *Storage) KeyExists(key string) bool { 37 | return !s.Call("getItem", key).IsNull() 38 | } 39 | -------------------------------------------------------------------------------- /elements/form/fieldset.go: -------------------------------------------------------------------------------- 1 | package form 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | type FieldSet struct { 6 | *tinydom.Element 7 | } 8 | 9 | // NewFieldSet creates a new fieldset element. 10 | // Optionally a legend can be passed. the string is being used as innerHTML 11 | func NewFieldSet(legendArgs ...string) *FieldSet { 12 | doc := tinydom.GetDocument() 13 | result := doc.CreateElement("fieldset") 14 | 15 | for _, legend := range legendArgs { 16 | legendElem := doc.CreateElement("legend") 17 | legendElem.Set("value", legend) 18 | result.AppendChild(legendElem) 19 | } 20 | 21 | return &FieldSet{result} 22 | } 23 | 24 | // Check https://www.w3schools.com/html/html_form_elements.asp for valid tags 25 | func (f *FieldSet) Append(elements ...*tinydom.Element) error { 26 | for i := range elements { 27 | element := elements[i] 28 | f.AppendChild(element) 29 | } 30 | 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /elements/img/img.go: -------------------------------------------------------------------------------- 1 | package img 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | // Img is the html5 element img 6 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img for reference 7 | type Img struct { 8 | *tinydom.Element 9 | } 10 | 11 | func New(src, alt string) *Img { 12 | imgElement := tinydom.GetDocument().CreateElement("img"). 13 | SetAttribute("src", src). 14 | SetAttribute("alt", alt) 15 | 16 | return &Img{ 17 | Element: imgElement, 18 | } 19 | } 20 | 21 | func (i *Img) SetSrc(value string) *Img { 22 | i.SetAttribute("src", value) 23 | return i 24 | } 25 | 26 | func (i *Img) Src() (bool, string) { 27 | return i.GetAttribute("src") 28 | } 29 | 30 | func (i *Img) SetAlt(value string) *Img { 31 | i.SetAttribute("alt", value) 32 | return i 33 | } 34 | 35 | func (i *Img) Alt() (bool, string) { 36 | return i.GetAttribute("alt") 37 | } 38 | -------------------------------------------------------------------------------- /elements/input/types.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | type InputType string 4 | 5 | const ( 6 | ButtonInput InputType = "button" 7 | CheckboxInput InputType = "checkbox" 8 | ColorInput InputType = "color" 9 | DateInput InputType = "date" 10 | LocalInput InputType = "datetime-local" 11 | EmailInput InputType = "email" 12 | FileInput InputType = "file" 13 | HiddenInput InputType = "hidden" 14 | ImageInput InputType = "image" 15 | MonthInput InputType = "month" 16 | NumberInput InputType = "number" 17 | PasswordInput InputType = "password" 18 | RadioInput InputType = "radio" 19 | RangeInput InputType = "range" 20 | ResetInput InputType = "reset" 21 | SearchInput InputType = "search" 22 | SubmitInput InputType = "submit" 23 | TelInput InputType = "tel" 24 | TextInput InputType = "text" 25 | TimeInput InputType = "time" 26 | UrlInput InputType = "url" 27 | WeekInput InputType = "week" 28 | ) 29 | -------------------------------------------------------------------------------- /example/wasm-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | const dir = "example/html" 10 | 11 | func main() { 12 | fs := http.FileServer(http.Dir(dir)) 13 | log.Print("Serving " + dir + " on http://localhost:8080") 14 | http.ListenAndServe(":8080", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { 15 | resp.Header().Add("Cache-Control", "no-cache") 16 | if strings.HasSuffix(req.URL.Path, ".wasm") { 17 | resp.Header().Set("content-type", "application/wasm") 18 | } 19 | 20 | if strings.HasSuffix(req.URL.Path, ".css") { 21 | resp.Header().Set("content-type", "text/css") 22 | } 23 | 24 | if strings.HasSuffix(req.URL.Path, ".jpg") { 25 | resp.Header().Set("content-type", "image/jpeg") 26 | } 27 | 28 | if strings.HasSuffix(req.URL.Path, ".mp4") { 29 | resp.Header().Set("content-type", "video/mp4") 30 | } 31 | 32 | fs.ServeHTTP(resp, req) 33 | })) 34 | } 35 | -------------------------------------------------------------------------------- /elements/a/a.go: -------------------------------------------------------------------------------- 1 | package a 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | // A is an a element 6 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a for reference 7 | type A struct { 8 | *tinydom.Element 9 | } 10 | 11 | // New creates a new instance of A 12 | func New(href, description string) *A { 13 | aElement := tinydom.GetDocument(). 14 | CreateElement("a"). 15 | SetAttribute("href", href). 16 | SetInnerHTML(description) 17 | 18 | return &A{ 19 | Element: aElement, 20 | } 21 | } 22 | 23 | func (a *A) SetTarget(value string) *A { 24 | a.SetAttribute("target", value) 25 | return a 26 | } 27 | 28 | func (a *A) Target() (bool, string) { 29 | return a.GetAttribute("target") 30 | } 31 | 32 | func (a *A) SetRel(values ...Rel) *A { 33 | var value Rel 34 | 35 | valueCount := len(values) 36 | 37 | for i, rel := range values { 38 | value += rel 39 | 40 | if i < valueCount { 41 | value += " " 42 | } 43 | } 44 | 45 | a.SetAttribute("rel", string(value)) 46 | return a 47 | } 48 | 49 | func (a *A) Rel() (bool, string) { 50 | return a.GetAttribute("rel") 51 | } 52 | -------------------------------------------------------------------------------- /document.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | // Document wraps the JavaScript document element, which is usually fetched by js.Global().Get("document") 6 | type Document struct { 7 | js.Value 8 | } 9 | 10 | var doc = js.Global().Get("document") 11 | 12 | func GetDocument() *Document { 13 | return &Document{doc} 14 | } 15 | 16 | func (e *Document) ActiveElement() *Element { 17 | return &Element{e.Get("activeElement")} 18 | } 19 | 20 | func (e *Document) DocumentElement() *Element { 21 | return &Element{e.Get("documentElement")} 22 | } 23 | 24 | func (d *Document) CreateElement(tag string) *Element { 25 | return &Element{d.Call("createElement", tag)} 26 | } 27 | 28 | func (d *Document) CreateTextNode(textContent string) *Element { 29 | return &Element{d.Call("createTextNode", textContent)} 30 | } 31 | 32 | func (d *Document) CreateDocumentFragment() *Element { 33 | return &Element{d.Call("createDocumentFragment")} 34 | } 35 | 36 | func (d *Document) GetElementById(id string) *Element { 37 | return &Element{d.Call("getElementById", id)} 38 | } 39 | 40 | func (d *Document) Write(markup string) { 41 | d.Call("write", markup) 42 | } 43 | -------------------------------------------------------------------------------- /elements/form/form.go: -------------------------------------------------------------------------------- 1 | package form 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/Nerzal/tinydom" 7 | ) 8 | 9 | type Form struct { 10 | *tinydom.Element 11 | } 12 | 13 | func New() *Form { 14 | result := tinydom.GetDocument().CreateElement("form") 15 | return &Form{result} 16 | } 17 | 18 | // Check https://www.w3schools.com/html/html_form_elements.asp for valid tags 19 | func (f *Form) Append(elements ...*tinydom.Element) error { 20 | for i := range elements { 21 | element := elements[i] 22 | 23 | switch strings.ToLower(element.TagName()) { 24 | case "input", "label", "select", "textarea", "div", "button", "fieldset", "legend", "datalist", "output", "option", "optgroup": 25 | // println("appending:", element.TagName()) 26 | f.AppendChildBr(element) 27 | default: 28 | println(element.TagName()) 29 | return ErrInvalidTagAppended 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | 36 | func (f *Form) SetMethod(method Method) *Form { 37 | f.SetAttribute("method", method.String()) 38 | return f 39 | } 40 | 41 | func (f *Form) SetAction(action string) *Form { 42 | f.SetAttribute("action", action) 43 | return f 44 | } 45 | 46 | func (f *Form) SetNoValidate() *Form { 47 | f.Set("novalidate", false) 48 | return f 49 | } 50 | -------------------------------------------------------------------------------- /window.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type Window struct { 6 | js.Value 7 | } 8 | 9 | var win = js.Global().Get("window") 10 | 11 | func GetWindow() *Window { 12 | return &Window{win} 13 | } 14 | 15 | func (w *Window) Location() *Location { 16 | return &Location{w.Get("location")} 17 | } 18 | 19 | func (w *Window) Navigator() *Navigator { 20 | return &Navigator{w.Get("navigator")} 21 | } 22 | 23 | func (w *Window) History() *History { 24 | return &History{w.Get("history")} 25 | } 26 | 27 | func (w *Window) Alert(message string) { 28 | w.Call("alert", message) 29 | } 30 | 31 | func (w *Window) PushState(state interface{}, title, URL string) { 32 | w.Get("history").Call("pushState", state, title, URL) 33 | } 34 | 35 | func (w *Window) ReplaceState(state interface{}, title, URL string) { 36 | w.Get("history").Call("replaceState", state, title, URL) 37 | } 38 | 39 | func (w *Window) PageXOffset() float64 { 40 | return w.Get("pageXOffset").Float() 41 | } 42 | 43 | func (w *Window) PageYOffset() float64 { 44 | return w.Get("pageYOffset").Float() 45 | } 46 | 47 | func (w *Window) ScrollX() float64 { 48 | return w.Get("scrollX").Float() 49 | } 50 | 51 | func (w *Window) ScrollY() float64 { 52 | return w.Get("scrollY").Float() 53 | } 54 | -------------------------------------------------------------------------------- /xmlhttprequest.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type XMLHttpRequest struct { 6 | js.Value 7 | } 8 | 9 | func NewXMLHttpRequest() *XMLHttpRequest { 10 | return &XMLHttpRequest{GetWindow().Get("XMLHttpRequest").New()} 11 | } 12 | 13 | func (x *XMLHttpRequest) ResponseText() string { 14 | return x.Get("responseText").String() 15 | } 16 | 17 | func (x *XMLHttpRequest) ResponseURL() string { 18 | return x.Get("responseURL").String() 19 | } 20 | 21 | func (x *XMLHttpRequest) ResponseXML() *Element { 22 | return &Element{x.Get("responseXML")} 23 | } 24 | 25 | func (x *XMLHttpRequest) StatusText() string { 26 | return x.Get("statusText").String() 27 | } 28 | 29 | func (x *XMLHttpRequest) WithCredentials() bool { 30 | return x.Get("withCredentials").Bool() 31 | } 32 | 33 | func (x *XMLHttpRequest) SetWithCredentials(c bool) { 34 | x.Set("withCredentials", c) 35 | } 36 | 37 | func (x *XMLHttpRequest) Abort() { 38 | x.Call("abort") 39 | } 40 | 41 | func (x *XMLHttpRequest) Open(method, url string, args ...interface{}) { 42 | if len(args) == 1 { 43 | // args[0] should be bool async 44 | x.Call("open", method, url, args[0]) 45 | } else { 46 | x.Call("open", method, url) 47 | } 48 | } 49 | 50 | func (x *XMLHttpRequest) OverrideMimeType(mimeType string) { 51 | x.Call("overrideMimeType", mimeType) 52 | } 53 | 54 | func (x *XMLHttpRequest) Send(args ...interface{}) { 55 | if len(args) == 1 { 56 | x.Call("send", args[0]) 57 | } else { 58 | x.Call("send") 59 | } 60 | } 61 | 62 | func (x *XMLHttpRequest) SetRequestHeader(header, value string) { 63 | x.Call("setRequestHeader", header, value) 64 | } 65 | -------------------------------------------------------------------------------- /elements/picture/source.go: -------------------------------------------------------------------------------- 1 | package picture 2 | 3 | import "github.com/Nerzal/tinydom" 4 | 5 | // 6 | 7 | // Source is a html5 source element 8 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source for reference 9 | type Source struct { 10 | *tinydom.Element 11 | } 12 | 13 | // New creates a new instance of Source 14 | func NewSource() *Source { 15 | sourceElement := tinydom.GetDocument().CreateElement("source") 16 | 17 | return &Source{ 18 | Element: sourceElement, 19 | } 20 | } 21 | 22 | // FromSourceElement creates a new Source based on the given element 23 | func FromSourceElement(element *tinydom.Element) *Source { 24 | return &Source{ 25 | Element: element, 26 | } 27 | } 28 | 29 | func (s *Source) SetType(mimetype string) *Source { 30 | s.SetAttribute("type", mimetype) 31 | return s 32 | } 33 | 34 | func (s *Source) Type() (bool, string) { 35 | return s.GetAttribute("type") 36 | } 37 | 38 | func (s *Source) SetSrcSet(value string) *Source { 39 | s.SetAttribute("srcset", value) 40 | return s 41 | } 42 | 43 | func (s *Source) SrcSet() (bool, string) { 44 | return s.GetAttribute("srcset") 45 | } 46 | 47 | func (s *Source) SetSizes(value ...string) *Source { 48 | s.SetMultiValueAttribute("sizes", value...) 49 | return s 50 | } 51 | 52 | func (s *Source) Sizes() (bool, string) { 53 | return s.GetAttribute("sizes") 54 | } 55 | 56 | func (s *Source) SetMedia(value string) *Source { 57 | s.SetAttribute("media", value) 58 | return s 59 | } 60 | 61 | func (s *Source) Media() (bool, string) { 62 | return s.GetAttribute("media") 63 | } 64 | -------------------------------------------------------------------------------- /elements/picture/picture.go: -------------------------------------------------------------------------------- 1 | package picture 2 | 3 | import ( 4 | "github.com/Nerzal/tinydom" 5 | "github.com/Nerzal/tinydom/elements/img" 6 | ) 7 | 8 | // 9 | // 11 | // 13 | // 15 | // 16 | // 17 | 18 | // Picture is the html5 picture element 19 | // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture for reference 20 | type Picture struct { 21 | *tinydom.Element 22 | img *img.Img 23 | sources []*Source 24 | } 25 | 26 | // New creates a new instance of Picture 27 | // image is the path to the image 28 | // sources are the different image type sources 29 | func New(image *img.Img, sources ...*Source) *Picture { 30 | doc := tinydom.GetDocument() 31 | pictureElement := doc.CreateElement("picture") 32 | 33 | result := &Picture{ 34 | Element: pictureElement, 35 | sources: sources, 36 | img: image, 37 | } 38 | 39 | result.AppendSources(sources...) 40 | 41 | result.AppendChild(image.Element) 42 | 43 | return result 44 | } 45 | 46 | func (p *Picture) AppendSources(sources ...*Source) *Picture { 47 | if sources == nil { 48 | return p 49 | } 50 | 51 | for _, source := range sources { 52 | p.AppendChild(source.Element) 53 | } 54 | 55 | return p 56 | } 57 | 58 | func (p *Picture) Sources() []*Source { 59 | elements := p.GetElementsByTagName("source") 60 | 61 | result := make([]*Source, len(elements)) 62 | 63 | for i, element := range elements { 64 | result[i] = FromSourceElement(element) 65 | } 66 | 67 | return result 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyDom 2 | 3 | TinyGo compatible DOM manipulation library. For use in WASM 4 | 5 | This library is heavily based on [godom](https://github.com/siongui/godom). It was changed to be usable in [TinyGo](https://tinygo.org) projects. 6 | 7 | TinyDom wraps nearly every function of `syscall/js`. 8 | 9 | Also TimyDom provides some wrapper around html elements, like the following: 10 | 11 | * form 12 | * input 13 | * label 14 | * output 15 | * fieldset 16 | * video 17 | 18 | ## Example Usage 19 | 20 | ```go 21 | package main 22 | 23 | import ( 24 | package main 25 | 26 | import ( 27 | "github.com/Nerzal/tinydom" 28 | "github.com/Nerzal/tinydom/elements/form" 29 | "github.com/Nerzal/tinydom/elements/input" 30 | ) 31 | 32 | func main() { 33 | document := tinydom.GetDocument() 34 | 35 | body := document.GetElementById("body-component") 36 | 37 | h1 := document.CreateElement("h1") 38 | h1.SetInnerHTML("Welcome to tinydom - Hello TinyWorld <3") 39 | body.AppendChild(h1) 40 | 41 | h2 := document.CreateElement("h1") 42 | h2.SetInnerHTML("Yes! I do compile with TinyGo!") 43 | body.AppendChild(h2) 44 | 45 | br := document.CreateElement("br") 46 | body.AppendChild(br) 47 | 48 | body.AppendChild(br) 49 | 50 | myForm := form.New() 51 | label := document.CreateElement("label") 52 | label.SetInnerHTML("Name:") 53 | textInput := input.NewTextInput() 54 | 55 | passwordLabel := document.CreateElement("label") 56 | passwordLabel.SetInnerHTML("Password:") 57 | passwordInput := input.New(input.PasswordInput) 58 | 59 | submitInput := input.New(input.SubmitInput) 60 | 61 | err := myForm.Append(label, textInput.Element, passwordLabel, passwordInput.Element, submitInput.Element) 62 | if err != nil { 63 | println(err.Error()) 64 | } 65 | 66 | body.AppendChild(myForm.Element) 67 | 68 | wait := make(chan struct{}, 0) 69 | <-wait 70 | } 71 | 72 | } 73 | ``` 74 | 75 | ## Run the example 76 | 77 | Simply use the makefile :) 78 | 79 | > make example-app 80 | 81 | Note: The example uses a wasm_exec.js from tinygo 1.17 :) 82 | 83 | ## Example Result 84 | 85 | ![grafik](https://user-images.githubusercontent.com/9110370/110029225-7931a480-7d34-11eb-9202-d3af100bdf98.png) 86 | 87 | Example Video is Big Buck Bunny from [blender](https://peach.blender.org/about/) 88 | 89 | Example Video License: https://creativecommons.org/licenses/by/3.0/ 90 | -------------------------------------------------------------------------------- /elements/media/video.go: -------------------------------------------------------------------------------- 1 | package media 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/Nerzal/tinydom" 7 | ) 8 | 9 | const videoAlt = "Your browser does not support the video tag." 10 | 11 | const ( 12 | MP4 = "video/mp4" 13 | OGG = "video/ogg" 14 | WEBM = "video/webm" 15 | ) 16 | 17 | type Video struct { 18 | *tinydom.Element 19 | } 20 | 21 | type VideoSource struct { 22 | Source string 23 | Type string 24 | } 25 | 26 | func NewVideo() *Video { 27 | videoElem := tinydom.GetDocument().CreateElement("video") 28 | return &Video{videoElem} 29 | } 30 | 31 | func NewVideoParams( 32 | width, height int, 33 | autoplay, muted, controls bool, 34 | sources ...*VideoSource, 35 | ) *Video { 36 | result := NewVideo() 37 | result.SetHeight(height) 38 | result.SetWidth(width) 39 | 40 | if autoplay { 41 | result.SetAutoplay() 42 | } 43 | 44 | if muted { 45 | result.SetMuted() 46 | } 47 | 48 | if controls { 49 | result.SetControl() 50 | } 51 | 52 | for i := range sources { 53 | source := sources[i] 54 | result.SetSource(source) 55 | } 56 | 57 | return result 58 | } 59 | 60 | func (v *Video) SetAutoplay() *Video { 61 | v.Set("autoplay", true) 62 | return v 63 | } 64 | 65 | func (v *Video) SetMuted() *Video { 66 | v.Set("muted", true) 67 | return v 68 | } 69 | 70 | func (v *Video) SetControl() *Video { 71 | v.Set("controls", "controls") 72 | return v 73 | } 74 | 75 | func (v *Video) SetAltText() *Video { 76 | v.SetInnerHTML(videoAlt) 77 | return v 78 | } 79 | 80 | func (v *Video) Reload() *Video { 81 | v.Call("load") 82 | return v 83 | } 84 | 85 | func (v *Video) SetSource(source *VideoSource) *Video { 86 | src := tinydom.GetDocument().CreateElement("source") 87 | src.Set("src", source.Source) 88 | src.Set("type", source.Type) 89 | 90 | v.AppendChild(src) 91 | return v 92 | } 93 | 94 | func (v *Video) SetWidth(width int) *Video { 95 | v.Set("width", strconv.Itoa(width)) 96 | return v 97 | } 98 | 99 | func (v *Video) Width() (int, error) { 100 | width := v.Get("width").String() 101 | result, err := strconv.Atoi(width) 102 | if err != nil { 103 | return -1, err 104 | } 105 | 106 | return result, nil 107 | } 108 | 109 | func (v *Video) SetHeight(height int) *Video { 110 | v.Set("height", strconv.Itoa(height)) 111 | return v 112 | } 113 | 114 | func (v *Video) Height() (int, error) { 115 | height := v.Get("height").String() 116 | result, err := strconv.Atoi(height) 117 | if err != nil { 118 | return -1, err 119 | } 120 | 121 | return result, nil 122 | } 123 | -------------------------------------------------------------------------------- /example/wasm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "syscall/js" 5 | 6 | "github.com/Nerzal/tinydom" 7 | "github.com/Nerzal/tinydom/elements/a" 8 | "github.com/Nerzal/tinydom/elements/form" 9 | "github.com/Nerzal/tinydom/elements/href" 10 | "github.com/Nerzal/tinydom/elements/input" 11 | "github.com/Nerzal/tinydom/elements/label" 12 | "github.com/Nerzal/tinydom/elements/media" 13 | ) 14 | 15 | var video *media.Video 16 | 17 | func main() { 18 | document := tinydom.GetDocument() 19 | 20 | body := document.GetElementById("body-component") 21 | 22 | h1 := document.CreateElement("h1") 23 | h1.SetInnerHTML("Welcome to tinydom - Hello TinyWorld <3") 24 | body.AppendChildBr(h1) 25 | body.Br() 26 | 27 | h2 := document.CreateElement("h1") 28 | h2.SetInnerHTML("Yes! I do compile with TinyGo!") 29 | body.AppendChildBr(h2) 30 | body.Br() 31 | 32 | body.Br() 33 | 34 | body.Br() 35 | 36 | myForm := form.New() 37 | 38 | nameLabel := label.New() 39 | nameLabel.SetInnerHTML("Name:") 40 | textInput := input.NewTextInput() 41 | 42 | passwordLabel := label.New() 43 | passwordLabel.SetInnerHTML("Password:") 44 | passwordInput := input.New(input.PasswordInput) 45 | 46 | submitInput := input.New(input.SubmitInput) 47 | 48 | err := myForm.Append(nameLabel.Element, textInput.Element, passwordLabel.Element, passwordInput.Element, submitInput.Element) 49 | if err != nil { 50 | println(err.Error()) 51 | } 52 | 53 | body.AppendChild(myForm.Element) 54 | 55 | body.Br() 56 | body.Br() 57 | largeButton := input.New(input.ButtonInput) 58 | largeButton.SetValue("Large") 59 | largeButton.AddEventListener("click", js.FuncOf(large)) 60 | 61 | smallButton := input.New(input.ButtonInput) 62 | smallButton.SetValue("Small") 63 | smallButton.AddEventListener("click", js.FuncOf(small)) 64 | 65 | body.AppendChildren(smallButton.Element, largeButton.Element) 66 | body.Br() 67 | 68 | video = media.NewVideoParams(640, 360, true, false, true, &media.VideoSource{ 69 | Source: "video.mp4", 70 | Type: media.MP4, 71 | }) 72 | 73 | body.AppendChild(video.Element) 74 | body.Br() 75 | body.Br() 76 | 77 | link := href.New("https://www.bigbuckbunny.org/", "Big Buck Bunny") 78 | body.AppendChild(link.Element) 79 | 80 | aElement := a.New("https://google.com", "Jub") 81 | body.AppendChild(aElement.Element) 82 | 83 | select {} 84 | } 85 | 86 | func large(this js.Value, args []js.Value) interface{} { 87 | println("large") 88 | video.SetWidth(1280) 89 | video.SetHeight(720) 90 | return nil 91 | } 92 | 93 | func small(this js.Value, args []js.Value) interface{} { 94 | println("small") 95 | video.SetWidth(640) 96 | video.SetHeight(360) 97 | return nil 98 | } 99 | -------------------------------------------------------------------------------- /elements/input/input.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | import ( 4 | "github.com/Nerzal/tinydom" 5 | ) 6 | 7 | type Input struct { 8 | *tinydom.Element 9 | iType InputType 10 | } 11 | 12 | func New(inputType InputType) *Input { 13 | input := tinydom.GetDocument().CreateElement("input") 14 | input.SetAttribute("type", string(inputType)) 15 | return &Input{Element: input, iType: inputType} 16 | } 17 | 18 | func NewTextInput() *Input { 19 | return New(TextInput) 20 | } 21 | 22 | func FromElement(e *tinydom.Element) *Input { 23 | _, inputType := e.GetAttribute("type") 24 | 25 | return &Input{Element: e, iType: InputType(inputType)} 26 | } 27 | 28 | func (i *Input) Autofocus() bool { 29 | result, _ := i.GetAttribute("autofocus") 30 | return result 31 | } 32 | 33 | func (i *Input) SetAutofocus(b bool) *Input { 34 | i.SetAttribute("autofocus", b) 35 | return i 36 | } 37 | 38 | func (i *Input) Autocomplete() bool { 39 | result, _ := i.GetAttribute("autocomplete") 40 | return result 41 | } 42 | 43 | func (i *Input) SetAutocomplete(b bool) *Input { 44 | i.SetAttribute("autocomplete", b) 45 | return i 46 | } 47 | 48 | func (i *Input) For() string { 49 | return i.Get("for").String() 50 | } 51 | 52 | func (i *Input) SetFor(value string) *Input { 53 | i.SetAttribute("for", value) 54 | return i 55 | } 56 | 57 | func (i *Input) FormEnctype() string { 58 | return i.Get("formenctype").String() 59 | } 60 | 61 | func (i *Input) SetFormEnctype(value string) error { 62 | if i.iType != SubmitInput { 63 | return ErrInvalidAttribute 64 | } 65 | 66 | i.Set("formenctype", value) 67 | return nil 68 | } 69 | 70 | func (i *Input) FormTarget() string { 71 | return i.Get("formtarget").String() 72 | } 73 | 74 | func (i *Input) SetFormTarget(value tinydom.Target) error { 75 | if i.iType != SubmitInput { 76 | return ErrInvalidAttribute 77 | } 78 | 79 | i.Set("formtarget", value.String()) 80 | return nil 81 | } 82 | 83 | func (i *Input) FormNoValidate() string { 84 | return i.Get("formnovalidate").String() 85 | } 86 | 87 | func (i *Input) SetFormNoValidate() error { 88 | if i.iType != SubmitInput { 89 | return ErrInvalidAttribute 90 | } 91 | 92 | i.Set("formnovalidate", "") 93 | return nil 94 | } 95 | 96 | func (i *Input) List() string { 97 | return i.Get("list").String() 98 | } 99 | 100 | func (i *Input) SetList(value string) *Input { 101 | i.Set("list", value) 102 | return i 103 | } 104 | 105 | func (i *Input) Min() string { 106 | return i.Get("min").String() 107 | } 108 | 109 | func (i *Input) SetMin(min string) *Input { 110 | i.Set("min", min) 111 | return i 112 | } 113 | 114 | func (i *Input) MaxLength() string { 115 | return i.Get("maxlength").String() 116 | } 117 | 118 | func (i *Input) SetMaxLength(length string) *Input { 119 | i.Set("maxlength", length) 120 | return i 121 | } 122 | 123 | func (i *Input) Max() string { 124 | return i.Get("max").String() 125 | } 126 | 127 | func (i *Input) SetMax(max string) *Input { 128 | i.Set("max", max) 129 | return i 130 | } 131 | 132 | func (i *Input) Checked() string { 133 | return i.Get("checked").String() 134 | } 135 | 136 | func (i *Input) SetChecked(checked string) *Input { 137 | i.Set("checked", checked) 138 | return i 139 | } 140 | 141 | func (i *Input) Required() string { 142 | return i.Get("required").String() 143 | } 144 | 145 | func (i *Input) SetRequired(required string) *Input { 146 | i.Set("required", required) 147 | return i 148 | } 149 | 150 | func (i *Input) Pattern() string { 151 | return i.Get("pattern").String() 152 | } 153 | 154 | func (i *Input) SetPattern(pattern string) *Input { 155 | i.Set("pattern", pattern) 156 | return i 157 | } 158 | 159 | func (i *Input) Step() string { 160 | return i.Get("step").String() 161 | } 162 | 163 | func (i *Input) SetStep(step string) *Input { 164 | i.Set("step", step) 165 | return i 166 | } 167 | 168 | func (i *Input) Value() string { 169 | return i.Get("value").String() 170 | } 171 | 172 | func (i *Input) SetValue(v string) *Input { 173 | i.Set("value", v) 174 | return i 175 | } 176 | 177 | func (i *Input) Width() string { 178 | return i.Get("width").String() 179 | } 180 | 181 | func (i *Input) SetWidth(v string) *Input { 182 | i.Set("width", v) 183 | return i 184 | } 185 | 186 | func (i *Input) Height() string { 187 | return i.Get("height").String() 188 | } 189 | 190 | func (i *Input) SetHeight(v string) *Input { 191 | i.Set("height", v) 192 | return i 193 | } 194 | -------------------------------------------------------------------------------- /element.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | "syscall/js" 7 | ) 8 | 9 | type Element struct { 10 | js.Value 11 | } 12 | 13 | func (e *Element) HasFocus() bool { 14 | return e.IsEqualNode(GetDocument().ActiveElement()) 15 | } 16 | 17 | func (e *Element) AppendBefore(n *Element) { 18 | e.ParentNode().InsertBefore(n, e) 19 | } 20 | 21 | func (e *Element) AppendAfter(n *Element) { 22 | e.ParentNode().InsertBefore(n, e.NextSibling()) 23 | } 24 | 25 | func (e *Element) AppendChild(child *Element) { 26 | e.Call("appendChild", child) 27 | } 28 | 29 | func (e *Element) AppendChildren(children ...*Element) { 30 | for _, child := range children { 31 | e.AppendChild(child) 32 | } 33 | } 34 | 35 | // AppendChildBr appends the child and adds an additional br 36 | func (e *Element) AppendChildBr(child *Element) { 37 | e.Call("appendChild", child) 38 | e.Call("appendChild", GetDocument().CreateElement("br")) 39 | } 40 | 41 | func (e *Element) AppendChildrenBr(children ...*Element) { 42 | for _, child := range children { 43 | e.AppendChildBr(child) 44 | } 45 | } 46 | 47 | func (e *Element) Br() { 48 | br := GetDocument().CreateElement("br") 49 | e.AppendChild(br) 50 | } 51 | 52 | func (e *Element) RemoveAllChildNodes() { 53 | for e.HasChildNodes() { 54 | e.RemoveChild(e.LastChild()) 55 | } 56 | } 57 | 58 | func (e *Element) SetId(id string) *Element { 59 | e.Set("id", id) 60 | return e 61 | } 62 | 63 | func (e *Element) SetAttribute(key, value interface{}) *Element { 64 | e.Call("setAttribute", key, value) 65 | return e 66 | } 67 | 68 | func (e *Element) SetClass(values ...string) *Element { 69 | return e.SetMultiValueAttribute("class", values...) 70 | } 71 | 72 | // ErrClassAlreadyExisting is being thrown when trying to append the same class multiple times 73 | var ErrClassAlreadyExisting = errors.New("tried to append class multiple times") 74 | 75 | func (e *Element) AppendClass(values ...string) error { 76 | existing, currentClasses := e.Class() 77 | 78 | if !existing { 79 | e.SetClass(values...) 80 | return nil 81 | } 82 | 83 | for _, newClass := range values { 84 | for _, existingclass := range currentClasses { 85 | if newClass == existingclass { 86 | return ErrClassAlreadyExisting 87 | } 88 | } 89 | } 90 | 91 | newClass := append(currentClasses, values...) 92 | e.SetClass(newClass...) 93 | 94 | return nil 95 | } 96 | 97 | func (e *Element) Class() (bool, []string) { 98 | exists, attributeValues := e.GetAttribute("class") 99 | if !exists { 100 | return false, nil 101 | } 102 | 103 | splittedValues := strings.Split(attributeValues, " ") 104 | 105 | result := make([]string, len(attributeValues)) 106 | for i, value := range splittedValues { 107 | result[i] = value 108 | } 109 | 110 | return true, result 111 | } 112 | 113 | func (e *Element) SetMultiValueAttribute(attributeName string, values ...string) *Element { 114 | var value string 115 | 116 | valueCount := len(values) 117 | 118 | for i, rel := range values { 119 | value += rel 120 | 121 | if i < valueCount { 122 | value += " " 123 | } 124 | } 125 | 126 | e.SetAttribute(attributeName, value) 127 | return e 128 | } 129 | 130 | func (e *Element) SetInnerHTML(value string) *Element { 131 | e.Set("innerHTML", value) 132 | return e 133 | } 134 | 135 | func (e *Element) InnerHTML() string { 136 | return e.Get("innerHTML").String() 137 | } 138 | 139 | func (e *Element) OuterHTML() string { 140 | return e.Get("outerHTML").String() 141 | } 142 | 143 | func (e *Element) SetOuterHTML(html string) *Element { 144 | e.Set("outerHTML", html) 145 | return e 146 | } 147 | 148 | func (e *Element) TagName() string { 149 | return e.Get("tagName").String() 150 | } 151 | 152 | // GetAttribute returns the searched attribute, returns false if the attribute wasn't found. 153 | func (e *Element) GetAttribute(name string) (bool, string) { 154 | if !e.HasAttribute(name) { 155 | return false, "" 156 | } 157 | 158 | return true, e.Call("getAttribute", name).String() 159 | } 160 | 161 | func (e *Element) HasAttribute(name string) bool { 162 | return e.Call("hasAttribute", name).Bool() 163 | } 164 | 165 | func (e *Element) QuerySelector(selectors string) *Element { 166 | return &Element{e.Call("querySelector", selectors)} 167 | } 168 | 169 | func (e *Element) QuerySelectorAll(selectors string) []*Element { 170 | nodeList := e.Call("querySelectorAll", selectors) 171 | length := nodeList.Get("length").Int() 172 | 173 | nodes := make([]*Element, length) 174 | 175 | for i := 0; i < length; i++ { 176 | nodes[i] = &Element{nodeList.Call("item", i)} 177 | } 178 | 179 | return nodes 180 | } 181 | 182 | func (e *Element) GetElementsByTagName(tagName string) []*Element { 183 | nodeList := e.Call("getElementsByTagName", tagName) 184 | length := nodeList.Get("length").Int() 185 | 186 | nodes := make([]*Element, length) 187 | 188 | for i := 0; i < length; i++ { 189 | nodes[i] = &Element{nodeList.Call("item", i)} 190 | } 191 | 192 | return nodes 193 | } 194 | 195 | func (e *Element) ChildNodes() []*Element { 196 | nodeList := e.Get("childNodes") 197 | length := nodeList.Get("length").Int() 198 | var nodes []*Element 199 | for i := 0; i < length; i++ { 200 | nodes = append(nodes, &Element{nodeList.Call("item", i)}) 201 | } 202 | return nodes 203 | } 204 | 205 | func (e *Element) FindChildNode(tag string) *Element { 206 | children := e.ChildNodes() 207 | for _, child := range children { 208 | if child.TagName() == tag { 209 | return child 210 | } 211 | } 212 | 213 | return nil 214 | } 215 | 216 | func (e *Element) FirstChild() *Element { 217 | return &Element{e.Get("firstChild")} 218 | } 219 | 220 | func (e *Element) LastChild() *Element { 221 | return &Element{e.Get("lastChild")} 222 | } 223 | 224 | func (e *Element) NextSibling() *Element { 225 | return &Element{e.Get("nextSibling")} 226 | } 227 | 228 | func (e *Element) NodeType() int { 229 | return e.Get("nodeType").Int() 230 | } 231 | 232 | func (e *Element) NodeValue() string { 233 | return e.Get("nodeValue").String() 234 | } 235 | 236 | func (e *Element) SetNodeValue(s string) *Element { 237 | e.Set("nodeValue", s) 238 | return e 239 | } 240 | func (e *Element) Name() string { 241 | return e.Get("name").String() 242 | } 243 | 244 | func (e *Element) SetName(n string) *Element { 245 | e.Set("name", n) 246 | return e 247 | } 248 | 249 | func (e *Element) ParentNode() *Element { 250 | return &Element{e.Get("parentNode")} 251 | } 252 | 253 | func (e *Element) TextContent() string { 254 | return e.Get("textContent").String() 255 | } 256 | 257 | func (e *Element) SetTextContent(s string) *Element { 258 | e.Set("textContent", s) 259 | return e 260 | } 261 | 262 | func (e *Element) Contains(n *Element) bool { 263 | return e.Call("contains", n).Bool() 264 | } 265 | 266 | func (e *Element) HasChildNodes() bool { 267 | return e.Call("hasChildNodes").Bool() 268 | } 269 | 270 | func (e *Element) InsertBefore(newNode, referenceNode *Element) *Element { 271 | return &Element{e.Call("insertBefore", newNode, referenceNode)} 272 | } 273 | 274 | func (e *Element) IsEqualNode(n *Element) bool { 275 | return e.Call("isEqualNode", n).Bool() 276 | } 277 | 278 | func (e *Element) IsSameNode(n *Element) bool { 279 | return e.Call("isSameNode", n).Bool() 280 | } 281 | 282 | func (e *Element) LookupPrefix() string { 283 | return e.Call("lookupPrefix").String() 284 | } 285 | 286 | func (e *Element) Normalize() { 287 | e.Call("normalize") 288 | } 289 | 290 | func (e *Element) RemoveChild(c *Element) *Element { 291 | return &Element{e.Call("removeChild", c)} 292 | } 293 | 294 | func (e *Element) ReplaceChild(newChild, oldChild *Element) *Element { 295 | return &Element{e.Call("replaceChild", newChild, oldChild)} 296 | } 297 | 298 | func (e *Element) AddEventListener(t string, listener js.Func) *Element { 299 | e.Call("addEventListener", t, listener) 300 | return e 301 | } 302 | 303 | func (e *Element) RemoveEventListener(t string, listener js.Func) *Element { 304 | e.Call("removeEventListener", t, listener) 305 | return e 306 | } 307 | 308 | func (e *Element) Style() *CSS { 309 | return &CSS{e.Get("style")} 310 | } 311 | 312 | func (e *Element) Dataset() *Element { 313 | return &Element{e.Get("dataset")} 314 | } 315 | 316 | func (e *Element) Blur() *Element { 317 | e.Call("blur") 318 | return e 319 | } 320 | 321 | func (e *Element) Focus() *Element { 322 | e.Call("focus") 323 | return e 324 | } 325 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2021] [Tobias Theel (Nerzal)] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /example/wasm_exec.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // 5 | // This file has been modified for use by the TinyGo compiler. 6 | 7 | (() => { 8 | // Map multiple JavaScript environments to a single common API, 9 | // preferring web standards over Node.js API. 10 | // 11 | // Environments considered: 12 | // - Browsers 13 | // - Node.js 14 | // - Electron 15 | // - Parcel 16 | 17 | if (typeof global !== "undefined") { 18 | // global already exists 19 | } else if (typeof window !== "undefined") { 20 | window.global = window; 21 | } else if (typeof self !== "undefined") { 22 | self.global = self; 23 | } else { 24 | throw new Error("cannot export Go (neither global, window nor self is defined)"); 25 | } 26 | 27 | if (!global.require && typeof require !== "undefined") { 28 | global.require = require; 29 | } 30 | 31 | if (!global.fs && global.require) { 32 | global.fs = require("fs"); 33 | } 34 | 35 | const enosys = () => { 36 | const err = new Error("not implemented"); 37 | err.code = "ENOSYS"; 38 | return err; 39 | }; 40 | 41 | if (!global.fs) { 42 | let outputBuf = ""; 43 | global.fs = { 44 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused 45 | writeSync(fd, buf) { 46 | outputBuf += decoder.decode(buf); 47 | const nl = outputBuf.lastIndexOf("\n"); 48 | if (nl != -1) { 49 | console.log(outputBuf.substr(0, nl)); 50 | outputBuf = outputBuf.substr(nl + 1); 51 | } 52 | return buf.length; 53 | }, 54 | write(fd, buf, offset, length, position, callback) { 55 | if (offset !== 0 || length !== buf.length || position !== null) { 56 | callback(enosys()); 57 | return; 58 | } 59 | const n = this.writeSync(fd, buf); 60 | callback(null, n); 61 | }, 62 | chmod(path, mode, callback) { callback(enosys()); }, 63 | chown(path, uid, gid, callback) { callback(enosys()); }, 64 | close(fd, callback) { callback(enosys()); }, 65 | fchmod(fd, mode, callback) { callback(enosys()); }, 66 | fchown(fd, uid, gid, callback) { callback(enosys()); }, 67 | fstat(fd, callback) { callback(enosys()); }, 68 | fsync(fd, callback) { callback(null); }, 69 | ftruncate(fd, length, callback) { callback(enosys()); }, 70 | lchown(path, uid, gid, callback) { callback(enosys()); }, 71 | link(path, link, callback) { callback(enosys()); }, 72 | lstat(path, callback) { callback(enosys()); }, 73 | mkdir(path, perm, callback) { callback(enosys()); }, 74 | open(path, flags, mode, callback) { callback(enosys()); }, 75 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); }, 76 | readdir(path, callback) { callback(enosys()); }, 77 | readlink(path, callback) { callback(enosys()); }, 78 | rename(from, to, callback) { callback(enosys()); }, 79 | rmdir(path, callback) { callback(enosys()); }, 80 | stat(path, callback) { callback(enosys()); }, 81 | symlink(path, link, callback) { callback(enosys()); }, 82 | truncate(path, length, callback) { callback(enosys()); }, 83 | unlink(path, callback) { callback(enosys()); }, 84 | utimes(path, atime, mtime, callback) { callback(enosys()); }, 85 | }; 86 | } 87 | 88 | if (!global.process) { 89 | global.process = { 90 | getuid() { return -1; }, 91 | getgid() { return -1; }, 92 | geteuid() { return -1; }, 93 | getegid() { return -1; }, 94 | getgroups() { throw enosys(); }, 95 | pid: -1, 96 | ppid: -1, 97 | umask() { throw enosys(); }, 98 | cwd() { throw enosys(); }, 99 | chdir() { throw enosys(); }, 100 | } 101 | } 102 | 103 | if (!global.crypto) { 104 | const nodeCrypto = require("crypto"); 105 | global.crypto = { 106 | getRandomValues(b) { 107 | nodeCrypto.randomFillSync(b); 108 | }, 109 | }; 110 | } 111 | 112 | if (!global.performance) { 113 | global.performance = { 114 | now() { 115 | const [sec, nsec] = process.hrtime(); 116 | return sec * 1000 + nsec / 1000000; 117 | }, 118 | }; 119 | } 120 | 121 | if (!global.TextEncoder) { 122 | global.TextEncoder = require("util").TextEncoder; 123 | } 124 | 125 | if (!global.TextDecoder) { 126 | global.TextDecoder = require("util").TextDecoder; 127 | } 128 | 129 | // End of polyfills for common API. 130 | 131 | const encoder = new TextEncoder("utf-8"); 132 | const decoder = new TextDecoder("utf-8"); 133 | var logLine = []; 134 | 135 | global.Go = class { 136 | constructor() { 137 | this._callbackTimeouts = new Map(); 138 | this._nextCallbackTimeoutID = 1; 139 | 140 | const mem = () => { 141 | // The buffer may change when requesting more memory. 142 | return new DataView(this._inst.exports.memory.buffer); 143 | } 144 | 145 | const setInt64 = (addr, v) => { 146 | mem().setUint32(addr + 0, v, true); 147 | mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); 148 | } 149 | 150 | const getInt64 = (addr) => { 151 | const low = mem().getUint32(addr + 0, true); 152 | const high = mem().getInt32(addr + 4, true); 153 | return low + high * 4294967296; 154 | } 155 | 156 | const loadValue = (addr) => { 157 | const f = mem().getFloat64(addr, true); 158 | if (f === 0) { 159 | return undefined; 160 | } 161 | if (!isNaN(f)) { 162 | return f; 163 | } 164 | 165 | const id = mem().getUint32(addr, true); 166 | return this._values[id]; 167 | } 168 | 169 | const storeValue = (addr, v) => { 170 | const nanHead = 0x7FF80000; 171 | 172 | if (typeof v === "number") { 173 | if (isNaN(v)) { 174 | mem().setUint32(addr + 4, nanHead, true); 175 | mem().setUint32(addr, 0, true); 176 | return; 177 | } 178 | if (v === 0) { 179 | mem().setUint32(addr + 4, nanHead, true); 180 | mem().setUint32(addr, 1, true); 181 | return; 182 | } 183 | mem().setFloat64(addr, v, true); 184 | return; 185 | } 186 | 187 | switch (v) { 188 | case undefined: 189 | mem().setFloat64(addr, 0, true); 190 | return; 191 | case null: 192 | mem().setUint32(addr + 4, nanHead, true); 193 | mem().setUint32(addr, 2, true); 194 | return; 195 | case true: 196 | mem().setUint32(addr + 4, nanHead, true); 197 | mem().setUint32(addr, 3, true); 198 | return; 199 | case false: 200 | mem().setUint32(addr + 4, nanHead, true); 201 | mem().setUint32(addr, 4, true); 202 | return; 203 | } 204 | 205 | let id = this._ids.get(v); 206 | if (id === undefined) { 207 | id = this._idPool.pop(); 208 | if (id === undefined) { 209 | id = this._values.length; 210 | } 211 | this._values[id] = v; 212 | this._goRefCounts[id] = 0; 213 | this._ids.set(v, id); 214 | } 215 | this._goRefCounts[id]++; 216 | let typeFlag = 1; 217 | switch (typeof v) { 218 | case "string": 219 | typeFlag = 2; 220 | break; 221 | case "symbol": 222 | typeFlag = 3; 223 | break; 224 | case "function": 225 | typeFlag = 4; 226 | break; 227 | } 228 | mem().setUint32(addr + 4, nanHead | typeFlag, true); 229 | mem().setUint32(addr, id, true); 230 | } 231 | 232 | const loadSlice = (array, len, cap) => { 233 | return new Uint8Array(this._inst.exports.memory.buffer, array, len); 234 | } 235 | 236 | const loadSliceOfValues = (array, len, cap) => { 237 | const a = new Array(len); 238 | for (let i = 0; i < len; i++) { 239 | a[i] = loadValue(array + i * 8); 240 | } 241 | return a; 242 | } 243 | 244 | const loadString = (ptr, len) => { 245 | return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len)); 246 | } 247 | 248 | const timeOrigin = Date.now() - performance.now(); 249 | this.importObject = { 250 | wasi_unstable: { 251 | // https://github.com/bytecodealliance/wasmtime/blob/master/docs/WASI-api.md#__wasi_fd_write 252 | fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) { 253 | let nwritten = 0; 254 | if (fd == 1) { 255 | for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) { 256 | let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32 257 | let ptr = mem().getUint32(iov_ptr + 0, true); 258 | let len = mem().getUint32(iov_ptr + 4, true); 259 | for (let i = 0; i < len; i++) { 260 | let c = mem().getUint8(ptr + i); 261 | if (c == 13) { // CR 262 | // ignore 263 | } else if (c == 10) { // LF 264 | // write line 265 | let line = decoder.decode(new Uint8Array(logLine)); 266 | logLine = []; 267 | console.log(line); 268 | } else { 269 | logLine.push(c); 270 | } 271 | } 272 | } 273 | } else { 274 | console.error('invalid file descriptor:', fd); 275 | } 276 | mem().setUint32(nwritten_ptr, nwritten, true); 277 | return 0; 278 | }, 279 | }, 280 | env: { 281 | // func ticks() float64 282 | "runtime.ticks": () => { 283 | return timeOrigin + performance.now(); 284 | }, 285 | 286 | // func sleepTicks(timeout float64) 287 | "runtime.sleepTicks": (timeout) => { 288 | // Do not sleep, only reactivate scheduler after the given timeout. 289 | setTimeout(this._inst.exports.go_scheduler, timeout); 290 | }, 291 | 292 | // func Exit(code int) 293 | "syscall.Exit": (code) => { 294 | if (global.process) { 295 | // Node.js 296 | process.exit(code); 297 | } else { 298 | // Can't exit in a browser. 299 | throw 'trying to exit with code ' + code; 300 | } 301 | }, 302 | 303 | // func finalizeRef(v ref) 304 | "syscall/js.finalizeRef": (v_addr) => { 305 | // Note: TinyGo does not support finalizers so this is only called 306 | // for one specific case, by js.go:jsString. 307 | const id = mem().getUint32(v_addr, true); 308 | this._goRefCounts[id]--; 309 | if (this._goRefCounts[id] === 0) { 310 | const v = this._values[id]; 311 | this._values[id] = null; 312 | this._ids.delete(v); 313 | this._idPool.push(id); 314 | } 315 | }, 316 | 317 | // func stringVal(value string) ref 318 | "syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => { 319 | const s = loadString(value_ptr, value_len); 320 | storeValue(ret_ptr, s); 321 | }, 322 | 323 | // func valueGet(v ref, p string) ref 324 | "syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => { 325 | let prop = loadString(p_ptr, p_len); 326 | let value = loadValue(v_addr); 327 | let result = Reflect.get(value, prop); 328 | storeValue(retval, result); 329 | }, 330 | 331 | // func valueSet(v ref, p string, x ref) 332 | "syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => { 333 | const v = loadValue(v_addr); 334 | const p = loadString(p_ptr, p_len); 335 | const x = loadValue(x_addr); 336 | Reflect.set(v, p, x); 337 | }, 338 | 339 | // func valueDelete(v ref, p string) 340 | "syscall/js.valueDelete": (v_addr, p_ptr, p_len) => { 341 | const v = loadValue(v_addr); 342 | const p = loadString(p_ptr, p_len); 343 | Reflect.deleteProperty(v, p); 344 | }, 345 | 346 | // func valueIndex(v ref, i int) ref 347 | "syscall/js.valueIndex": (ret_addr, v_addr, i) => { 348 | storeValue(ret_addr, Reflect.get(loadValue(v_addr), i)); 349 | }, 350 | 351 | // valueSetIndex(v ref, i int, x ref) 352 | "syscall/js.valueSetIndex": (v_addr, i, x_addr) => { 353 | Reflect.set(loadValue(v_addr), i, loadValue(x_addr)); 354 | }, 355 | 356 | // func valueCall(v ref, m string, args []ref) (ref, bool) 357 | "syscall/js.valueCall": (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => { 358 | const v = loadValue(v_addr); 359 | const name = loadString(m_ptr, m_len); 360 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 361 | try { 362 | const m = Reflect.get(v, name); 363 | storeValue(ret_addr, Reflect.apply(m, v, args)); 364 | mem().setUint8(ret_addr + 8, 1); 365 | } catch (err) { 366 | storeValue(ret_addr, err); 367 | mem().setUint8(ret_addr + 8, 0); 368 | } 369 | }, 370 | 371 | // func valueInvoke(v ref, args []ref) (ref, bool) 372 | "syscall/js.valueInvoke": (ret_addr, v_addr, args_ptr, args_len, args_cap) => { 373 | try { 374 | const v = loadValue(v_addr); 375 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 376 | storeValue(ret_addr, Reflect.apply(v, undefined, args)); 377 | mem().setUint8(ret_addr + 8, 1); 378 | } catch (err) { 379 | storeValue(ret_addr, err); 380 | mem().setUint8(ret_addr + 8, 0); 381 | } 382 | }, 383 | 384 | // func valueNew(v ref, args []ref) (ref, bool) 385 | "syscall/js.valueNew": (ret_addr, v_addr, args_ptr, args_len, args_cap) => { 386 | const v = loadValue(v_addr); 387 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 388 | try { 389 | storeValue(ret_addr, Reflect.construct(v, args)); 390 | mem().setUint8(ret_addr + 8, 1); 391 | } catch (err) { 392 | storeValue(ret_addr, err); 393 | mem().setUint8(ret_addr + 8, 0); 394 | } 395 | }, 396 | 397 | // func valueLength(v ref) int 398 | "syscall/js.valueLength": (v_addr) => { 399 | return loadValue(v_addr).length; 400 | }, 401 | 402 | // valuePrepareString(v ref) (ref, int) 403 | "syscall/js.valuePrepareString": (ret_addr, v_addr) => { 404 | const s = String(loadValue(v_addr)); 405 | const str = encoder.encode(s); 406 | storeValue(ret_addr, str); 407 | setInt64(ret_addr + 8, str.length); 408 | }, 409 | 410 | // valueLoadString(v ref, b []byte) 411 | "syscall/js.valueLoadString": (v_addr, slice_ptr, slice_len, slice_cap) => { 412 | const str = loadValue(v_addr); 413 | loadSlice(slice_ptr, slice_len, slice_cap).set(str); 414 | }, 415 | 416 | // func valueInstanceOf(v ref, t ref) bool 417 | "syscall/js.valueInstanceOf": (v_addr, t_addr) => { 418 | return loadValue(v_attr) instanceof loadValue(t_addr); 419 | }, 420 | 421 | // func copyBytesToGo(dst []byte, src ref) (int, bool) 422 | "syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => { 423 | let num_bytes_copied_addr = ret_addr; 424 | let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable 425 | 426 | const dst = loadSlice(dest_addr, dest_len); 427 | const src = loadValue(source_addr); 428 | if (!(src instanceof Uint8Array)) { 429 | mem().setUint8(returned_status_addr, 0); // Return "not ok" status 430 | return; 431 | } 432 | const toCopy = src.subarray(0, dst.length); 433 | dst.set(toCopy); 434 | setInt64(num_bytes_copied_addr, toCopy.length); 435 | mem().setUint8(returned_status_addr, 1); // Return "ok" status 436 | }, 437 | 438 | // copyBytesToJS(dst ref, src []byte) (int, bool) 439 | // Originally copied from upstream Go project, then modified: 440 | // https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416 441 | "syscall/js.copyBytesToJS": (ret_addr, dest_addr, source_addr, source_len, source_cap) => { 442 | let num_bytes_copied_addr = ret_addr; 443 | let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable 444 | 445 | const dst = loadValue(dest_addr); 446 | const src = loadSlice(source_addr, source_len); 447 | if (!(dst instanceof Uint8Array)) { 448 | mem().setUint8(returned_status_addr, 0); // Return "not ok" status 449 | return; 450 | } 451 | const toCopy = src.subarray(0, dst.length); 452 | dst.set(toCopy); 453 | setInt64(num_bytes_copied_addr, toCopy.length); 454 | mem().setUint8(returned_status_addr, 1); // Return "ok" status 455 | }, 456 | } 457 | }; 458 | } 459 | 460 | async run(instance) { 461 | this._inst = instance; 462 | this._values = [ // JS values that Go currently has references to, indexed by reference id 463 | NaN, 464 | 0, 465 | null, 466 | true, 467 | false, 468 | global, 469 | this, 470 | ]; 471 | this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id 472 | this._ids = new Map(); // mapping from JS values to reference ids 473 | this._idPool = []; // unused ids that have been garbage collected 474 | this.exited = false; // whether the Go program has exited 475 | 476 | const mem = new DataView(this._inst.exports.memory.buffer) 477 | 478 | while (true) { 479 | const callbackPromise = new Promise((resolve) => { 480 | this._resolveCallbackPromise = () => { 481 | if (this.exited) { 482 | throw new Error("bad callback: Go program has already exited"); 483 | } 484 | setTimeout(resolve, 0); // make sure it is asynchronous 485 | }; 486 | }); 487 | this._inst.exports._start(); 488 | if (this.exited) { 489 | break; 490 | } 491 | await callbackPromise; 492 | } 493 | } 494 | 495 | _resume() { 496 | if (this.exited) { 497 | throw new Error("Go program has already exited"); 498 | } 499 | this._inst.exports.resume(); 500 | if (this.exited) { 501 | this._resolveExitPromise(); 502 | } 503 | } 504 | 505 | _makeFuncWrapper(id) { 506 | const go = this; 507 | return function() { 508 | const event = { id: id, this: this, args: arguments }; 509 | go._pendingEvent = event; 510 | go._resume(); 511 | return event.result; 512 | }; 513 | } 514 | } 515 | 516 | if ( 517 | global.require && 518 | global.require.main === module && 519 | global.process && 520 | global.process.versions && 521 | !global.process.versions.electron 522 | ) { 523 | if (process.argv.length != 3) { 524 | console.error("usage: go_js_wasm_exec [wasm binary] [arguments]"); 525 | process.exit(1); 526 | } 527 | 528 | const go = new Go(); 529 | WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { 530 | return go.run(result.instance); 531 | }).catch((err) => { 532 | console.error(err); 533 | process.exit(1); 534 | }); 535 | } 536 | })(); -------------------------------------------------------------------------------- /example/html/wasm_exec.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // 5 | // This file has been modified for use by the TinyGo compiler. 6 | 7 | (() => { 8 | // Map multiple JavaScript environments to a single common API, 9 | // preferring web standards over Node.js API. 10 | // 11 | // Environments considered: 12 | // - Browsers 13 | // - Node.js 14 | // - Electron 15 | // - Parcel 16 | 17 | if (typeof global !== "undefined") { 18 | // global already exists 19 | } else if (typeof window !== "undefined") { 20 | window.global = window; 21 | } else if (typeof self !== "undefined") { 22 | self.global = self; 23 | } else { 24 | throw new Error("cannot export Go (neither global, window nor self is defined)"); 25 | } 26 | 27 | if (!global.require && typeof require !== "undefined") { 28 | global.require = require; 29 | } 30 | 31 | if (!global.fs && global.require) { 32 | global.fs = require("fs"); 33 | } 34 | 35 | const enosys = () => { 36 | const err = new Error("not implemented"); 37 | err.code = "ENOSYS"; 38 | return err; 39 | }; 40 | 41 | if (!global.fs) { 42 | let outputBuf = ""; 43 | global.fs = { 44 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused 45 | writeSync(fd, buf) { 46 | outputBuf += decoder.decode(buf); 47 | const nl = outputBuf.lastIndexOf("\n"); 48 | if (nl != -1) { 49 | console.log(outputBuf.substr(0, nl)); 50 | outputBuf = outputBuf.substr(nl + 1); 51 | } 52 | return buf.length; 53 | }, 54 | write(fd, buf, offset, length, position, callback) { 55 | if (offset !== 0 || length !== buf.length || position !== null) { 56 | callback(enosys()); 57 | return; 58 | } 59 | const n = this.writeSync(fd, buf); 60 | callback(null, n); 61 | }, 62 | chmod(path, mode, callback) { callback(enosys()); }, 63 | chown(path, uid, gid, callback) { callback(enosys()); }, 64 | close(fd, callback) { callback(enosys()); }, 65 | fchmod(fd, mode, callback) { callback(enosys()); }, 66 | fchown(fd, uid, gid, callback) { callback(enosys()); }, 67 | fstat(fd, callback) { callback(enosys()); }, 68 | fsync(fd, callback) { callback(null); }, 69 | ftruncate(fd, length, callback) { callback(enosys()); }, 70 | lchown(path, uid, gid, callback) { callback(enosys()); }, 71 | link(path, link, callback) { callback(enosys()); }, 72 | lstat(path, callback) { callback(enosys()); }, 73 | mkdir(path, perm, callback) { callback(enosys()); }, 74 | open(path, flags, mode, callback) { callback(enosys()); }, 75 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); }, 76 | readdir(path, callback) { callback(enosys()); }, 77 | readlink(path, callback) { callback(enosys()); }, 78 | rename(from, to, callback) { callback(enosys()); }, 79 | rmdir(path, callback) { callback(enosys()); }, 80 | stat(path, callback) { callback(enosys()); }, 81 | symlink(path, link, callback) { callback(enosys()); }, 82 | truncate(path, length, callback) { callback(enosys()); }, 83 | unlink(path, callback) { callback(enosys()); }, 84 | utimes(path, atime, mtime, callback) { callback(enosys()); }, 85 | }; 86 | } 87 | 88 | if (!global.process) { 89 | global.process = { 90 | getuid() { return -1; }, 91 | getgid() { return -1; }, 92 | geteuid() { return -1; }, 93 | getegid() { return -1; }, 94 | getgroups() { throw enosys(); }, 95 | pid: -1, 96 | ppid: -1, 97 | umask() { throw enosys(); }, 98 | cwd() { throw enosys(); }, 99 | chdir() { throw enosys(); }, 100 | } 101 | } 102 | 103 | if (!global.crypto) { 104 | const nodeCrypto = require("crypto"); 105 | global.crypto = { 106 | getRandomValues(b) { 107 | nodeCrypto.randomFillSync(b); 108 | }, 109 | }; 110 | } 111 | 112 | if (!global.performance) { 113 | global.performance = { 114 | now() { 115 | const [sec, nsec] = process.hrtime(); 116 | return sec * 1000 + nsec / 1000000; 117 | }, 118 | }; 119 | } 120 | 121 | if (!global.TextEncoder) { 122 | global.TextEncoder = require("util").TextEncoder; 123 | } 124 | 125 | if (!global.TextDecoder) { 126 | global.TextDecoder = require("util").TextDecoder; 127 | } 128 | 129 | // End of polyfills for common API. 130 | 131 | const encoder = new TextEncoder("utf-8"); 132 | const decoder = new TextDecoder("utf-8"); 133 | var logLine = []; 134 | 135 | global.Go = class { 136 | constructor() { 137 | this._callbackTimeouts = new Map(); 138 | this._nextCallbackTimeoutID = 1; 139 | 140 | const mem = () => { 141 | // The buffer may change when requesting more memory. 142 | return new DataView(this._inst.exports.memory.buffer); 143 | } 144 | 145 | const setInt64 = (addr, v) => { 146 | mem().setUint32(addr + 0, v, true); 147 | mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); 148 | } 149 | 150 | const getInt64 = (addr) => { 151 | const low = mem().getUint32(addr + 0, true); 152 | const high = mem().getInt32(addr + 4, true); 153 | return low + high * 4294967296; 154 | } 155 | 156 | const loadValue = (addr) => { 157 | const f = mem().getFloat64(addr, true); 158 | if (f === 0) { 159 | return undefined; 160 | } 161 | if (!isNaN(f)) { 162 | return f; 163 | } 164 | 165 | const id = mem().getUint32(addr, true); 166 | return this._values[id]; 167 | } 168 | 169 | const storeValue = (addr, v) => { 170 | const nanHead = 0x7FF80000; 171 | 172 | if (typeof v === "number") { 173 | if (isNaN(v)) { 174 | mem().setUint32(addr + 4, nanHead, true); 175 | mem().setUint32(addr, 0, true); 176 | return; 177 | } 178 | if (v === 0) { 179 | mem().setUint32(addr + 4, nanHead, true); 180 | mem().setUint32(addr, 1, true); 181 | return; 182 | } 183 | mem().setFloat64(addr, v, true); 184 | return; 185 | } 186 | 187 | switch (v) { 188 | case undefined: 189 | mem().setFloat64(addr, 0, true); 190 | return; 191 | case null: 192 | mem().setUint32(addr + 4, nanHead, true); 193 | mem().setUint32(addr, 2, true); 194 | return; 195 | case true: 196 | mem().setUint32(addr + 4, nanHead, true); 197 | mem().setUint32(addr, 3, true); 198 | return; 199 | case false: 200 | mem().setUint32(addr + 4, nanHead, true); 201 | mem().setUint32(addr, 4, true); 202 | return; 203 | } 204 | 205 | let id = this._ids.get(v); 206 | if (id === undefined) { 207 | id = this._idPool.pop(); 208 | if (id === undefined) { 209 | id = this._values.length; 210 | } 211 | this._values[id] = v; 212 | this._goRefCounts[id] = 0; 213 | this._ids.set(v, id); 214 | } 215 | this._goRefCounts[id]++; 216 | let typeFlag = 1; 217 | switch (typeof v) { 218 | case "string": 219 | typeFlag = 2; 220 | break; 221 | case "symbol": 222 | typeFlag = 3; 223 | break; 224 | case "function": 225 | typeFlag = 4; 226 | break; 227 | } 228 | mem().setUint32(addr + 4, nanHead | typeFlag, true); 229 | mem().setUint32(addr, id, true); 230 | } 231 | 232 | const loadSlice = (array, len, cap) => { 233 | return new Uint8Array(this._inst.exports.memory.buffer, array, len); 234 | } 235 | 236 | const loadSliceOfValues = (array, len, cap) => { 237 | const a = new Array(len); 238 | for (let i = 0; i < len; i++) { 239 | a[i] = loadValue(array + i * 8); 240 | } 241 | return a; 242 | } 243 | 244 | const loadString = (ptr, len) => { 245 | return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len)); 246 | } 247 | 248 | const timeOrigin = Date.now() - performance.now(); 249 | this.importObject = { 250 | wasi_unstable: { 251 | // https://github.com/bytecodealliance/wasmtime/blob/master/docs/WASI-api.md#__wasi_fd_write 252 | fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) { 253 | let nwritten = 0; 254 | if (fd == 1) { 255 | for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) { 256 | let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32 257 | let ptr = mem().getUint32(iov_ptr + 0, true); 258 | let len = mem().getUint32(iov_ptr + 4, true); 259 | for (let i = 0; i < len; i++) { 260 | let c = mem().getUint8(ptr + i); 261 | if (c == 13) { // CR 262 | // ignore 263 | } else if (c == 10) { // LF 264 | // write line 265 | let line = decoder.decode(new Uint8Array(logLine)); 266 | logLine = []; 267 | console.log(line); 268 | } else { 269 | logLine.push(c); 270 | } 271 | } 272 | } 273 | } else { 274 | console.error('invalid file descriptor:', fd); 275 | } 276 | mem().setUint32(nwritten_ptr, nwritten, true); 277 | return 0; 278 | }, 279 | }, 280 | env: { 281 | // func ticks() float64 282 | "runtime.ticks": () => { 283 | return timeOrigin + performance.now(); 284 | }, 285 | 286 | // func sleepTicks(timeout float64) 287 | "runtime.sleepTicks": (timeout) => { 288 | // Do not sleep, only reactivate scheduler after the given timeout. 289 | setTimeout(this._inst.exports.go_scheduler, timeout); 290 | }, 291 | 292 | // func Exit(code int) 293 | "syscall.Exit": (code) => { 294 | if (global.process) { 295 | // Node.js 296 | process.exit(code); 297 | } else { 298 | // Can't exit in a browser. 299 | throw 'trying to exit with code ' + code; 300 | } 301 | }, 302 | 303 | // func finalizeRef(v ref) 304 | "syscall/js.finalizeRef": (v_addr) => { 305 | // Note: TinyGo does not support finalizers so this is only called 306 | // for one specific case, by js.go:jsString. 307 | const id = mem().getUint32(v_addr, true); 308 | this._goRefCounts[id]--; 309 | if (this._goRefCounts[id] === 0) { 310 | const v = this._values[id]; 311 | this._values[id] = null; 312 | this._ids.delete(v); 313 | this._idPool.push(id); 314 | } 315 | }, 316 | 317 | // func stringVal(value string) ref 318 | "syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => { 319 | const s = loadString(value_ptr, value_len); 320 | storeValue(ret_ptr, s); 321 | }, 322 | 323 | // func valueGet(v ref, p string) ref 324 | "syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => { 325 | let prop = loadString(p_ptr, p_len); 326 | let value = loadValue(v_addr); 327 | let result = Reflect.get(value, prop); 328 | storeValue(retval, result); 329 | }, 330 | 331 | // func valueSet(v ref, p string, x ref) 332 | "syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => { 333 | const v = loadValue(v_addr); 334 | const p = loadString(p_ptr, p_len); 335 | const x = loadValue(x_addr); 336 | Reflect.set(v, p, x); 337 | }, 338 | 339 | // func valueDelete(v ref, p string) 340 | "syscall/js.valueDelete": (v_addr, p_ptr, p_len) => { 341 | const v = loadValue(v_addr); 342 | const p = loadString(p_ptr, p_len); 343 | Reflect.deleteProperty(v, p); 344 | }, 345 | 346 | // func valueIndex(v ref, i int) ref 347 | "syscall/js.valueIndex": (ret_addr, v_addr, i) => { 348 | storeValue(ret_addr, Reflect.get(loadValue(v_addr), i)); 349 | }, 350 | 351 | // valueSetIndex(v ref, i int, x ref) 352 | "syscall/js.valueSetIndex": (v_addr, i, x_addr) => { 353 | Reflect.set(loadValue(v_addr), i, loadValue(x_addr)); 354 | }, 355 | 356 | // func valueCall(v ref, m string, args []ref) (ref, bool) 357 | "syscall/js.valueCall": (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => { 358 | const v = loadValue(v_addr); 359 | const name = loadString(m_ptr, m_len); 360 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 361 | try { 362 | const m = Reflect.get(v, name); 363 | storeValue(ret_addr, Reflect.apply(m, v, args)); 364 | mem().setUint8(ret_addr + 8, 1); 365 | } catch (err) { 366 | storeValue(ret_addr, err); 367 | mem().setUint8(ret_addr + 8, 0); 368 | } 369 | }, 370 | 371 | // func valueInvoke(v ref, args []ref) (ref, bool) 372 | "syscall/js.valueInvoke": (ret_addr, v_addr, args_ptr, args_len, args_cap) => { 373 | try { 374 | const v = loadValue(v_addr); 375 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 376 | storeValue(ret_addr, Reflect.apply(v, undefined, args)); 377 | mem().setUint8(ret_addr + 8, 1); 378 | } catch (err) { 379 | storeValue(ret_addr, err); 380 | mem().setUint8(ret_addr + 8, 0); 381 | } 382 | }, 383 | 384 | // func valueNew(v ref, args []ref) (ref, bool) 385 | "syscall/js.valueNew": (ret_addr, v_addr, args_ptr, args_len, args_cap) => { 386 | const v = loadValue(v_addr); 387 | const args = loadSliceOfValues(args_ptr, args_len, args_cap); 388 | try { 389 | storeValue(ret_addr, Reflect.construct(v, args)); 390 | mem().setUint8(ret_addr + 8, 1); 391 | } catch (err) { 392 | storeValue(ret_addr, err); 393 | mem().setUint8(ret_addr + 8, 0); 394 | } 395 | }, 396 | 397 | // func valueLength(v ref) int 398 | "syscall/js.valueLength": (v_addr) => { 399 | return loadValue(v_addr).length; 400 | }, 401 | 402 | // valuePrepareString(v ref) (ref, int) 403 | "syscall/js.valuePrepareString": (ret_addr, v_addr) => { 404 | const s = String(loadValue(v_addr)); 405 | const str = encoder.encode(s); 406 | storeValue(ret_addr, str); 407 | setInt64(ret_addr + 8, str.length); 408 | }, 409 | 410 | // valueLoadString(v ref, b []byte) 411 | "syscall/js.valueLoadString": (v_addr, slice_ptr, slice_len, slice_cap) => { 412 | const str = loadValue(v_addr); 413 | loadSlice(slice_ptr, slice_len, slice_cap).set(str); 414 | }, 415 | 416 | // func valueInstanceOf(v ref, t ref) bool 417 | "syscall/js.valueInstanceOf": (v_addr, t_addr) => { 418 | return loadValue(v_attr) instanceof loadValue(t_addr); 419 | }, 420 | 421 | // func copyBytesToGo(dst []byte, src ref) (int, bool) 422 | "syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => { 423 | let num_bytes_copied_addr = ret_addr; 424 | let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable 425 | 426 | const dst = loadSlice(dest_addr, dest_len); 427 | const src = loadValue(source_addr); 428 | if (!(src instanceof Uint8Array)) { 429 | mem().setUint8(returned_status_addr, 0); // Return "not ok" status 430 | return; 431 | } 432 | const toCopy = src.subarray(0, dst.length); 433 | dst.set(toCopy); 434 | setInt64(num_bytes_copied_addr, toCopy.length); 435 | mem().setUint8(returned_status_addr, 1); // Return "ok" status 436 | }, 437 | 438 | // copyBytesToJS(dst ref, src []byte) (int, bool) 439 | // Originally copied from upstream Go project, then modified: 440 | // https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416 441 | "syscall/js.copyBytesToJS": (ret_addr, dest_addr, source_addr, source_len, source_cap) => { 442 | let num_bytes_copied_addr = ret_addr; 443 | let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable 444 | 445 | const dst = loadValue(dest_addr); 446 | const src = loadSlice(source_addr, source_len); 447 | if (!(dst instanceof Uint8Array)) { 448 | mem().setUint8(returned_status_addr, 0); // Return "not ok" status 449 | return; 450 | } 451 | const toCopy = src.subarray(0, dst.length); 452 | dst.set(toCopy); 453 | setInt64(num_bytes_copied_addr, toCopy.length); 454 | mem().setUint8(returned_status_addr, 1); // Return "ok" status 455 | }, 456 | } 457 | }; 458 | } 459 | 460 | async run(instance) { 461 | this._inst = instance; 462 | this._values = [ // JS values that Go currently has references to, indexed by reference id 463 | NaN, 464 | 0, 465 | null, 466 | true, 467 | false, 468 | global, 469 | this, 470 | ]; 471 | this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id 472 | this._ids = new Map(); // mapping from JS values to reference ids 473 | this._idPool = []; // unused ids that have been garbage collected 474 | this.exited = false; // whether the Go program has exited 475 | 476 | const mem = new DataView(this._inst.exports.memory.buffer) 477 | 478 | while (true) { 479 | const callbackPromise = new Promise((resolve) => { 480 | this._resolveCallbackPromise = () => { 481 | if (this.exited) { 482 | throw new Error("bad callback: Go program has already exited"); 483 | } 484 | setTimeout(resolve, 0); // make sure it is asynchronous 485 | }; 486 | }); 487 | this._inst.exports._start(); 488 | if (this.exited) { 489 | break; 490 | } 491 | await callbackPromise; 492 | } 493 | } 494 | 495 | _resume() { 496 | if (this.exited) { 497 | throw new Error("Go program has already exited"); 498 | } 499 | this._inst.exports.resume(); 500 | if (this.exited) { 501 | this._resolveExitPromise(); 502 | } 503 | } 504 | 505 | _makeFuncWrapper(id) { 506 | const go = this; 507 | return function() { 508 | const event = { id: id, this: this, args: arguments }; 509 | go._pendingEvent = event; 510 | go._resume(); 511 | return event.result; 512 | }; 513 | } 514 | } 515 | 516 | if ( 517 | global.require && 518 | global.require.main === module && 519 | global.process && 520 | global.process.versions && 521 | !global.process.versions.electron 522 | ) { 523 | if (process.argv.length != 3) { 524 | console.error("usage: go_js_wasm_exec [wasm binary] [arguments]"); 525 | process.exit(1); 526 | } 527 | 528 | const go = new Go(); 529 | WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { 530 | return go.run(result.instance); 531 | }).catch((err) => { 532 | console.error(err); 533 | process.exit(1); 534 | }); 535 | } 536 | })(); -------------------------------------------------------------------------------- /css.go: -------------------------------------------------------------------------------- 1 | package tinydom 2 | 3 | import "syscall/js" 4 | 5 | type CSS struct { 6 | js.Value 7 | } 8 | 9 | func (s *CSS) CssText() string { 10 | return s.Get("cssText").String() 11 | } 12 | 13 | func (s *CSS) Length() int { 14 | return s.Get("length").Int() 15 | } 16 | 17 | func (s *CSS) AlignContent() string { 18 | return s.Get("alignContent").String() 19 | } 20 | 21 | func (s *CSS) SetAlignContent(v string) { 22 | s.Set("alignContent", v) 23 | } 24 | 25 | func (s *CSS) AlignItems() string { 26 | return s.Get("alignItems").String() 27 | } 28 | 29 | func (s *CSS) SetAlignItems(v string) { 30 | s.Set("alignItems", v) 31 | } 32 | 33 | func (s *CSS) AlignSelf() string { 34 | return s.Get("alignSelf").String() 35 | } 36 | 37 | func (s *CSS) SetAlignSelf(v string) { 38 | s.Set("alignSelf", v) 39 | } 40 | 41 | func (s *CSS) Animation() string { 42 | return s.Get("animation").String() 43 | } 44 | 45 | func (s *CSS) SetAnimation(v string) { 46 | s.Set("animation", v) 47 | } 48 | 49 | func (s *CSS) AnimationDelay() string { 50 | return s.Get("animationDelay").String() 51 | } 52 | 53 | func (s *CSS) SetAnimationDelay(v string) { 54 | s.Set("animationDelay", v) 55 | } 56 | 57 | func (s *CSS) AnimationDirection() string { 58 | return s.Get("animationDirection").String() 59 | } 60 | 61 | func (s *CSS) SetAnimationDirection(v string) { 62 | s.Set("animationDirection", v) 63 | } 64 | 65 | func (s *CSS) AnimationDuration() string { 66 | return s.Get("animationDuration").String() 67 | } 68 | 69 | func (s *CSS) SetAnimationDuration(v string) { 70 | s.Set("animationDuration", v) 71 | } 72 | 73 | func (s *CSS) AnimationFillMode() string { 74 | return s.Get("animationFillMode").String() 75 | } 76 | 77 | func (s *CSS) SetAnimationFillMode(v string) { 78 | s.Set("animationFillMode", v) 79 | } 80 | 81 | func (s *CSS) AnimationIterationCount() string { 82 | return s.Get("animationIterationCount").String() 83 | } 84 | 85 | func (s *CSS) SetAnimationIterationCount(v string) { 86 | s.Set("animationIterationCount", v) 87 | } 88 | 89 | func (s *CSS) AnimationName() string { 90 | return s.Get("animationName").String() 91 | } 92 | 93 | func (s *CSS) SetAnimationName(v string) { 94 | s.Set("animationName", v) 95 | } 96 | 97 | func (s *CSS) AnimationTimingFunction() string { 98 | return s.Get("animationTimingFunction").String() 99 | } 100 | 101 | func (s *CSS) SetAnimationTimingFunction(v string) { 102 | s.Set("animationTimingFunction", v) 103 | } 104 | 105 | func (s *CSS) AnimationPlayState() string { 106 | return s.Get("animationPlayState").String() 107 | } 108 | 109 | func (s *CSS) SetAnimationPlayState(v string) { 110 | s.Set("animationPlayState", v) 111 | } 112 | 113 | func (s *CSS) Background() string { 114 | return s.Get("background").String() 115 | } 116 | 117 | func (s *CSS) SetBackground(v string) { 118 | s.Set("background", v) 119 | } 120 | 121 | func (s *CSS) BackgroundAttachment() string { 122 | return s.Get("backgroundAttachment").String() 123 | } 124 | 125 | func (s *CSS) SetBackgroundAttachment(v string) { 126 | s.Set("backgroundAttachment", v) 127 | } 128 | 129 | func (s *CSS) BackgroundColor() string { 130 | return s.Get("backgroundColor").String() 131 | } 132 | 133 | func (s *CSS) SetBackgroundColor(v string) { 134 | s.Set("backgroundColor", v) 135 | } 136 | 137 | func (s *CSS) BackgroundImage() string { 138 | return s.Get("backgroundImage").String() 139 | } 140 | 141 | func (s *CSS) SetBackgroundImage(v string) { 142 | s.Set("backgroundImage", v) 143 | } 144 | 145 | func (s *CSS) BackgroundPosition() string { 146 | return s.Get("backgroundPosition").String() 147 | } 148 | 149 | func (s *CSS) SetBackgroundPosition(v string) { 150 | s.Set("backgroundPosition", v) 151 | } 152 | 153 | func (s *CSS) BackgroundRepeat() string { 154 | return s.Get("backgroundRepeat").String() 155 | } 156 | 157 | func (s *CSS) SetBackgroundRepeat(v string) { 158 | s.Set("backgroundRepeat", v) 159 | } 160 | 161 | func (s *CSS) BackgroundClip() string { 162 | return s.Get("backgroundClip").String() 163 | } 164 | 165 | func (s *CSS) SetBackgroundClip(v string) { 166 | s.Set("backgroundClip", v) 167 | } 168 | 169 | func (s *CSS) BackgroundOrigin() string { 170 | return s.Get("backgroundOrigin").String() 171 | } 172 | 173 | func (s *CSS) SetBackgroundOrigin(v string) { 174 | s.Set("backgroundOrigin", v) 175 | } 176 | 177 | func (s *CSS) BackgroundSize() string { 178 | return s.Get("backgroundSize").String() 179 | } 180 | 181 | func (s *CSS) SetBackgroundSize(v string) { 182 | s.Set("backgroundSize", v) 183 | } 184 | 185 | func (s *CSS) BackfaceVisibility() string { 186 | return s.Get("backfaceVisibility").String() 187 | } 188 | 189 | func (s *CSS) SetBackfaceVisibility(v string) { 190 | s.Set("backfaceVisibility", v) 191 | } 192 | 193 | func (s *CSS) Border() string { 194 | return s.Get("border").String() 195 | } 196 | 197 | func (s *CSS) SetBorder(v string) { 198 | s.Set("border", v) 199 | } 200 | 201 | func (s *CSS) BorderBottom() string { 202 | return s.Get("borderBottom").String() 203 | } 204 | 205 | func (s *CSS) SetBorderBottom(v string) { 206 | s.Set("borderBottom", v) 207 | } 208 | 209 | func (s *CSS) BorderBottomColor() string { 210 | return s.Get("borderBottomColor").String() 211 | } 212 | 213 | func (s *CSS) SetBorderBottomColor(v string) { 214 | s.Set("borderBottomColor", v) 215 | } 216 | 217 | func (s *CSS) BorderBottomLeftRadius() string { 218 | return s.Get("borderBottomLeftRadius").String() 219 | } 220 | 221 | func (s *CSS) SetBorderBottomLeftRadius(v string) { 222 | s.Set("borderBottomLeftRadius", v) 223 | } 224 | 225 | func (s *CSS) BorderBottomRightRadius() string { 226 | return s.Get("borderBottomRightRadius").String() 227 | } 228 | 229 | func (s *CSS) SetBorderBottomRightRadius(v string) { 230 | s.Set("borderBottomRightRadius", v) 231 | } 232 | 233 | func (s *CSS) BorderBottomStyle() string { 234 | return s.Get("borderBottomStyle").String() 235 | } 236 | 237 | func (s *CSS) SetBorderBottomStyle(v string) { 238 | s.Set("borderBottomStyle", v) 239 | } 240 | 241 | func (s *CSS) BorderBottomWidth() string { 242 | return s.Get("borderBottomWidth").String() 243 | } 244 | 245 | func (s *CSS) SetBorderBottomWidth(v string) { 246 | s.Set("borderBottomWidth", v) 247 | } 248 | 249 | func (s *CSS) BorderCollapse() string { 250 | return s.Get("borderCollapse").String() 251 | } 252 | 253 | func (s *CSS) SetBorderCollapse(v string) { 254 | s.Set("borderCollapse", v) 255 | } 256 | 257 | func (s *CSS) BorderColor() string { 258 | return s.Get("borderColor").String() 259 | } 260 | 261 | func (s *CSS) SetBorderColor(v string) { 262 | s.Set("borderColor", v) 263 | } 264 | 265 | func (s *CSS) BorderImage() string { 266 | return s.Get("borderImage").String() 267 | } 268 | 269 | func (s *CSS) SetBorderImage(v string) { 270 | s.Set("borderImage", v) 271 | } 272 | 273 | func (s *CSS) BorderImageOutset() string { 274 | return s.Get("borderImageOutset").String() 275 | } 276 | 277 | func (s *CSS) SetBorderImageOutset(v string) { 278 | s.Set("borderImageOutset", v) 279 | } 280 | 281 | func (s *CSS) BorderImageRepeat() string { 282 | return s.Get("borderImageRepeat").String() 283 | } 284 | 285 | func (s *CSS) SetBorderImageRepeat(v string) { 286 | s.Set("borderImageRepeat", v) 287 | } 288 | 289 | func (s *CSS) BorderImageSlice() string { 290 | return s.Get("borderImageSlice").String() 291 | } 292 | 293 | func (s *CSS) SetBorderImageSlice(v string) { 294 | s.Set("borderImageSlice", v) 295 | } 296 | 297 | func (s *CSS) BorderImageSource() string { 298 | return s.Get("borderImageSource").String() 299 | } 300 | 301 | func (s *CSS) SetBorderImageSource(v string) { 302 | s.Set("borderImageSource", v) 303 | } 304 | 305 | func (s *CSS) BorderImageWidth() string { 306 | return s.Get("borderImageWidth").String() 307 | } 308 | 309 | func (s *CSS) SetBorderImageWidth(v string) { 310 | s.Set("borderImageWidth", v) 311 | } 312 | 313 | func (s *CSS) BorderLeft() string { 314 | return s.Get("borderLeft").String() 315 | } 316 | 317 | func (s *CSS) SetBorderLeft(v string) { 318 | s.Set("borderLeft", v) 319 | } 320 | 321 | func (s *CSS) BorderLeftColor() string { 322 | return s.Get("borderLeftColor").String() 323 | } 324 | 325 | func (s *CSS) SetBorderLeftColor(v string) { 326 | s.Set("borderLeftColor", v) 327 | } 328 | 329 | func (s *CSS) BorderLeftStyle() string { 330 | return s.Get("borderLeftStyle").String() 331 | } 332 | 333 | func (s *CSS) SetBorderLeftStyle(v string) { 334 | s.Set("borderLeftStyle", v) 335 | } 336 | 337 | func (s *CSS) BorderLeftWidth() string { 338 | return s.Get("borderLeftWidth").String() 339 | } 340 | 341 | func (s *CSS) SetBorderLeftWidth(v string) { 342 | s.Set("borderLeftWidth", v) 343 | } 344 | 345 | func (s *CSS) BorderRadius() string { 346 | return s.Get("borderRadius").String() 347 | } 348 | 349 | func (s *CSS) SetBorderRadius(v string) { 350 | s.Set("borderRadius", v) 351 | } 352 | 353 | func (s *CSS) BorderRight() string { 354 | return s.Get("borderRight").String() 355 | } 356 | 357 | func (s *CSS) SetBorderRight(v string) { 358 | s.Set("borderRight", v) 359 | } 360 | 361 | func (s *CSS) BorderRightColor() string { 362 | return s.Get("borderRightColor").String() 363 | } 364 | 365 | func (s *CSS) SetBorderRightColor(v string) { 366 | s.Set("borderRightColor", v) 367 | } 368 | 369 | func (s *CSS) BorderRightStyle() string { 370 | return s.Get("borderRightStyle").String() 371 | } 372 | 373 | func (s *CSS) SetBorderRightStyle(v string) { 374 | s.Set("borderRightStyle", v) 375 | } 376 | 377 | func (s *CSS) BorderRightWidth() string { 378 | return s.Get("borderRightWidth").String() 379 | } 380 | 381 | func (s *CSS) SetBorderRightWidth(v string) { 382 | s.Set("borderRightWidth", v) 383 | } 384 | 385 | func (s *CSS) BorderSpacing() string { 386 | return s.Get("borderSpacing").String() 387 | } 388 | 389 | func (s *CSS) SetBorderSpacing(v string) { 390 | s.Set("borderSpacing", v) 391 | } 392 | 393 | func (s *CSS) BorderStyle() string { 394 | return s.Get("borderStyle").String() 395 | } 396 | 397 | func (s *CSS) SetBorderStyle(v string) { 398 | s.Set("borderStyle", v) 399 | } 400 | 401 | func (s *CSS) BorderTop() string { 402 | return s.Get("borderTop").String() 403 | } 404 | 405 | func (s *CSS) SetBorderTop(v string) { 406 | s.Set("borderTop", v) 407 | } 408 | 409 | func (s *CSS) BorderTopColor() string { 410 | return s.Get("borderTopColor").String() 411 | } 412 | 413 | func (s *CSS) SetBorderTopColor(v string) { 414 | s.Set("borderTopColor", v) 415 | } 416 | 417 | func (s *CSS) BorderTopLeftRadius() string { 418 | return s.Get("borderTopLeftRadius").String() 419 | } 420 | 421 | func (s *CSS) SetBorderTopLeftRadius(v string) { 422 | s.Set("borderTopLeftRadius", v) 423 | } 424 | 425 | func (s *CSS) BorderTopRightRadius() string { 426 | return s.Get("borderTopRightRadius").String() 427 | } 428 | 429 | func (s *CSS) SetBorderTopRightRadius(v string) { 430 | s.Set("borderTopRightRadius", v) 431 | } 432 | 433 | func (s *CSS) BorderTopStyle() string { 434 | return s.Get("borderTopStyle").String() 435 | } 436 | 437 | func (s *CSS) SetBorderTopStyle(v string) { 438 | s.Set("borderTopStyle", v) 439 | } 440 | 441 | func (s *CSS) BorderTopWidth() string { 442 | return s.Get("borderTopWidth").String() 443 | } 444 | 445 | func (s *CSS) SetBorderTopWidth(v string) { 446 | s.Set("borderTopWidth", v) 447 | } 448 | 449 | func (s *CSS) BorderWidth() string { 450 | return s.Get("borderWidth").String() 451 | } 452 | 453 | func (s *CSS) SetBorderWidth(v string) { 454 | s.Set("borderWidth", v) 455 | } 456 | 457 | func (s *CSS) Bottom() string { 458 | return s.Get("bottom").String() 459 | } 460 | 461 | func (s *CSS) SetBottom(v string) { 462 | s.Set("bottom", v) 463 | } 464 | 465 | func (s *CSS) BoxShadow() string { 466 | return s.Get("boxShadow").String() 467 | } 468 | 469 | func (s *CSS) SetBoxShadow(v string) { 470 | s.Set("boxShadow", v) 471 | } 472 | 473 | func (s *CSS) BoxSizing() string { 474 | return s.Get("boxSizing").String() 475 | } 476 | 477 | func (s *CSS) SetBoxSizing(v string) { 478 | s.Set("boxSizing", v) 479 | } 480 | 481 | func (s *CSS) CaptionSide() string { 482 | return s.Get("captionSide").String() 483 | } 484 | 485 | func (s *CSS) SetCaptionSide(v string) { 486 | s.Set("captionSide", v) 487 | } 488 | 489 | func (s *CSS) Clear() string { 490 | return s.Get("clear").String() 491 | } 492 | 493 | func (s *CSS) SetClear(v string) { 494 | s.Set("clear", v) 495 | } 496 | 497 | func (s *CSS) Clip() string { 498 | return s.Get("clip").String() 499 | } 500 | 501 | func (s *CSS) SetClip(v string) { 502 | s.Set("clip", v) 503 | } 504 | 505 | func (s *CSS) Color() string { 506 | return s.Get("color").String() 507 | } 508 | 509 | func (s *CSS) SetColor(v string) { 510 | s.Set("color", v) 511 | } 512 | 513 | func (s *CSS) ColumnCount() string { 514 | return s.Get("columnCount").String() 515 | } 516 | 517 | func (s *CSS) SetColumnCount(v string) { 518 | s.Set("columnCount", v) 519 | } 520 | 521 | func (s *CSS) ColumnFill() string { 522 | return s.Get("columnFill").String() 523 | } 524 | 525 | func (s *CSS) SetColumnFill(v string) { 526 | s.Set("columnFill", v) 527 | } 528 | 529 | func (s *CSS) ColumnGap() string { 530 | return s.Get("columnGap").String() 531 | } 532 | 533 | func (s *CSS) SetColumnGap(v string) { 534 | s.Set("columnGap", v) 535 | } 536 | 537 | func (s *CSS) ColumnRule() string { 538 | return s.Get("columnRule").String() 539 | } 540 | 541 | func (s *CSS) SetColumnRule(v string) { 542 | s.Set("columnRule", v) 543 | } 544 | 545 | func (s *CSS) ColumnRuleColor() string { 546 | return s.Get("columnRuleColor").String() 547 | } 548 | 549 | func (s *CSS) SetColumnRuleColor(v string) { 550 | s.Set("columnRuleColor", v) 551 | } 552 | 553 | func (s *CSS) ColumnRuleStyle() string { 554 | return s.Get("columnRuleStyle").String() 555 | } 556 | 557 | func (s *CSS) SetColumnRuleStyle(v string) { 558 | s.Set("columnRuleStyle", v) 559 | } 560 | 561 | func (s *CSS) ColumnRuleWidth() string { 562 | return s.Get("columnRuleWidth").String() 563 | } 564 | 565 | func (s *CSS) SetColumnRuleWidth(v string) { 566 | s.Set("columnRuleWidth", v) 567 | } 568 | 569 | func (s *CSS) Columns() string { 570 | return s.Get("columns").String() 571 | } 572 | 573 | func (s *CSS) SetColumns(v string) { 574 | s.Set("columns", v) 575 | } 576 | 577 | func (s *CSS) ColumnSpan() string { 578 | return s.Get("columnSpan").String() 579 | } 580 | 581 | func (s *CSS) SetColumnSpan(v string) { 582 | s.Set("columnSpan", v) 583 | } 584 | 585 | func (s *CSS) ColumnWidth() string { 586 | return s.Get("columnWidth").String() 587 | } 588 | 589 | func (s *CSS) SetColumnWidth(v string) { 590 | s.Set("columnWidth", v) 591 | } 592 | 593 | func (s *CSS) CounterIncrement() string { 594 | return s.Get("counterIncrement").String() 595 | } 596 | 597 | func (s *CSS) SetCounterIncrement(v string) { 598 | s.Set("counterIncrement", v) 599 | } 600 | 601 | func (s *CSS) CounterReset() string { 602 | return s.Get("counterReset").String() 603 | } 604 | 605 | func (s *CSS) SetCounterReset(v string) { 606 | s.Set("counterReset", v) 607 | } 608 | 609 | func (s *CSS) Cursor() string { 610 | return s.Get("cursor").String() 611 | } 612 | 613 | func (s *CSS) SetCursor(v string) { 614 | s.Set("cursor", v) 615 | } 616 | 617 | func (s *CSS) Direction() string { 618 | return s.Get("direction").String() 619 | } 620 | 621 | func (s *CSS) SetDirection(v string) { 622 | s.Set("direction", v) 623 | } 624 | 625 | func (s *CSS) Display() string { 626 | return s.Get("display").String() 627 | } 628 | 629 | func (s *CSS) SetDisplay(v string) { 630 | s.Set("display", v) 631 | } 632 | 633 | func (s *CSS) EmptyCells() string { 634 | return s.Get("emptyCells").String() 635 | } 636 | 637 | func (s *CSS) SetEmptyCells(v string) { 638 | s.Set("emptyCells", v) 639 | } 640 | 641 | func (s *CSS) Filter() string { 642 | return s.Get("filter").String() 643 | } 644 | 645 | func (s *CSS) SetFilter(v string) { 646 | s.Set("filter", v) 647 | } 648 | 649 | func (s *CSS) Flex() string { 650 | return s.Get("flex").String() 651 | } 652 | 653 | func (s *CSS) SetFlex(v string) { 654 | s.Set("flex", v) 655 | } 656 | 657 | func (s *CSS) FlexBasis() string { 658 | return s.Get("flexBasis").String() 659 | } 660 | 661 | func (s *CSS) SetFlexBasis(v string) { 662 | s.Set("flexBasis", v) 663 | } 664 | 665 | func (s *CSS) FlexDirection() string { 666 | return s.Get("flexDirection").String() 667 | } 668 | 669 | func (s *CSS) SetFlexDirection(v string) { 670 | s.Set("flexDirection", v) 671 | } 672 | 673 | func (s *CSS) FlexFlow() string { 674 | return s.Get("flexFlow").String() 675 | } 676 | 677 | func (s *CSS) SetFlexFlow(v string) { 678 | s.Set("flexFlow", v) 679 | } 680 | 681 | func (s *CSS) FlexGrow() string { 682 | return s.Get("flexGrow").String() 683 | } 684 | 685 | func (s *CSS) SetFlexGrow(v string) { 686 | s.Set("flexGrow", v) 687 | } 688 | 689 | func (s *CSS) FlexShrink() string { 690 | return s.Get("flexShrink").String() 691 | } 692 | 693 | func (s *CSS) SetFlexShrink(v string) { 694 | s.Set("flexShrink", v) 695 | } 696 | 697 | func (s *CSS) FlexWrap() string { 698 | return s.Get("flexWrap").String() 699 | } 700 | 701 | func (s *CSS) SetFlexWrap(v string) { 702 | s.Set("flexWrap", v) 703 | } 704 | 705 | func (s *CSS) CssFloat() string { 706 | return s.Get("cssFloat").String() 707 | } 708 | 709 | func (s *CSS) SetCssFloat(v string) { 710 | s.Set("cssFloat", v) 711 | } 712 | 713 | func (s *CSS) Font() string { 714 | return s.Get("font").String() 715 | } 716 | 717 | func (s *CSS) SetFont(v string) { 718 | s.Set("font", v) 719 | } 720 | 721 | func (s *CSS) FontFamily() string { 722 | return s.Get("fontFamily").String() 723 | } 724 | 725 | func (s *CSS) SetFontFamily(v string) { 726 | s.Set("fontFamily", v) 727 | } 728 | 729 | func (s *CSS) FontSize() string { 730 | return s.Get("fontSize").String() 731 | } 732 | 733 | func (s *CSS) SetFontSize(v string) { 734 | s.Set("fontSize", v) 735 | } 736 | 737 | func (s *CSS) FontStyle() string { 738 | return s.Get("fontStyle").String() 739 | } 740 | 741 | func (s *CSS) SetFontStyle(v string) { 742 | s.Set("fontStyle", v) 743 | } 744 | 745 | func (s *CSS) FontVariant() string { 746 | return s.Get("fontVariant").String() 747 | } 748 | 749 | func (s *CSS) SetFontVariant(v string) { 750 | s.Set("fontVariant", v) 751 | } 752 | 753 | func (s *CSS) FontWeight() string { 754 | return s.Get("fontWeight").String() 755 | } 756 | 757 | func (s *CSS) SetFontWeight(v string) { 758 | s.Set("fontWeight", v) 759 | } 760 | 761 | func (s *CSS) FontSizeAdjust() string { 762 | return s.Get("fontSizeAdjust").String() 763 | } 764 | 765 | func (s *CSS) SetFontSizeAdjust(v string) { 766 | s.Set("fontSizeAdjust", v) 767 | } 768 | 769 | func (s *CSS) Height() string { 770 | return s.Get("height").String() 771 | } 772 | 773 | func (s *CSS) SetHeight(v string) { 774 | s.Set("height", v) 775 | } 776 | 777 | func (s *CSS) JustifyContent() string { 778 | return s.Get("justifyContent").String() 779 | } 780 | 781 | func (s *CSS) SetJustifyContent(v string) { 782 | s.Set("justifyContent", v) 783 | } 784 | 785 | func (s *CSS) Left() string { 786 | return s.Get("left").String() 787 | } 788 | 789 | func (s *CSS) SetLeft(v string) { 790 | s.Set("left", v) 791 | } 792 | 793 | func (s *CSS) LetterSpacing() string { 794 | return s.Get("letterSpacing").String() 795 | } 796 | 797 | func (s *CSS) SetLetterSpacing(v string) { 798 | s.Set("letterSpacing", v) 799 | } 800 | 801 | func (s *CSS) LineHeight() string { 802 | return s.Get("lineHeight").String() 803 | } 804 | 805 | func (s *CSS) SetLineHeight(v string) { 806 | s.Set("lineHeight", v) 807 | } 808 | 809 | func (s *CSS) ListStyle() string { 810 | return s.Get("listStyle").String() 811 | } 812 | 813 | func (s *CSS) SetListStyle(v string) { 814 | s.Set("listStyle", v) 815 | } 816 | 817 | func (s *CSS) ListStyleImage() string { 818 | return s.Get("listStyleImage").String() 819 | } 820 | 821 | func (s *CSS) SetListStyleImage(v string) { 822 | s.Set("listStyleImage", v) 823 | } 824 | 825 | func (s *CSS) ListStylePosition() string { 826 | return s.Get("listStylePosition").String() 827 | } 828 | 829 | func (s *CSS) SetListStylePosition(v string) { 830 | s.Set("listStylePosition", v) 831 | } 832 | 833 | func (s *CSS) ListStyleType() string { 834 | return s.Get("listStyleType").String() 835 | } 836 | 837 | func (s *CSS) SetListStyleType(v string) { 838 | s.Set("listStyleType", v) 839 | } 840 | 841 | func (s *CSS) Margin() string { 842 | return s.Get("margin").String() 843 | } 844 | 845 | func (s *CSS) SetMargin(v string) { 846 | s.Set("margin", v) 847 | } 848 | 849 | func (s *CSS) MarginBottom() string { 850 | return s.Get("marginBottom").String() 851 | } 852 | 853 | func (s *CSS) SetMarginBottom(v string) { 854 | s.Set("marginBottom", v) 855 | } 856 | 857 | func (s *CSS) MarginLeft() string { 858 | return s.Get("marginLeft").String() 859 | } 860 | 861 | func (s *CSS) SetMarginLeft(v string) { 862 | s.Set("marginLeft", v) 863 | } 864 | 865 | func (s *CSS) MarginRight() string { 866 | return s.Get("marginRight").String() 867 | } 868 | 869 | func (s *CSS) SetMarginRight(v string) { 870 | s.Set("marginRight", v) 871 | } 872 | 873 | func (s *CSS) MarginTop() string { 874 | return s.Get("marginTop").String() 875 | } 876 | 877 | func (s *CSS) SetMarginTop(v string) { 878 | s.Set("marginTop", v) 879 | } 880 | 881 | func (s *CSS) MaxHeight() string { 882 | return s.Get("maxHeight").String() 883 | } 884 | 885 | func (s *CSS) SetMaxHeight(v string) { 886 | s.Set("maxHeight", v) 887 | } 888 | 889 | func (s *CSS) MaxWidth() string { 890 | return s.Get("maxWidth").String() 891 | } 892 | 893 | func (s *CSS) SetMaxWidth(v string) { 894 | s.Set("maxWidth", v) 895 | } 896 | 897 | func (s *CSS) MinHeight() string { 898 | return s.Get("minHeight").String() 899 | } 900 | 901 | func (s *CSS) SetMinHeight(v string) { 902 | s.Set("minHeight", v) 903 | } 904 | 905 | func (s *CSS) MinWidth() string { 906 | return s.Get("minWidth").String() 907 | } 908 | 909 | func (s *CSS) SetMinWidth(v string) { 910 | s.Set("minWidth", v) 911 | } 912 | 913 | func (s *CSS) Opacity() string { 914 | return s.Get("opacity").String() 915 | } 916 | 917 | func (s *CSS) SetOpacity(v string) { 918 | s.Set("opacity", v) 919 | } 920 | 921 | func (s *CSS) Order() string { 922 | return s.Get("order").String() 923 | } 924 | 925 | func (s *CSS) SetOrder(v string) { 926 | s.Set("order", v) 927 | } 928 | 929 | func (s *CSS) Orphans() string { 930 | return s.Get("orphans").String() 931 | } 932 | 933 | func (s *CSS) SetOrphans(v string) { 934 | s.Set("orphans", v) 935 | } 936 | 937 | func (s *CSS) Outline() string { 938 | return s.Get("outline").String() 939 | } 940 | 941 | func (s *CSS) SetOutline(v string) { 942 | s.Set("outline", v) 943 | } 944 | 945 | func (s *CSS) OutlineColor() string { 946 | return s.Get("outlineColor").String() 947 | } 948 | 949 | func (s *CSS) SetOutlineColor(v string) { 950 | s.Set("outlineColor", v) 951 | } 952 | 953 | func (s *CSS) OutlineOffset() string { 954 | return s.Get("outlineOffset").String() 955 | } 956 | 957 | func (s *CSS) SetOutlineOffset(v string) { 958 | s.Set("outlineOffset", v) 959 | } 960 | 961 | func (s *CSS) OutlineStyle() string { 962 | return s.Get("outlineStyle").String() 963 | } 964 | 965 | func (s *CSS) SetOutlineStyle(v string) { 966 | s.Set("outlineStyle", v) 967 | } 968 | 969 | func (s *CSS) OutlineWidth() string { 970 | return s.Get("outlineWidth").String() 971 | } 972 | 973 | func (s *CSS) SetOutlineWidth(v string) { 974 | s.Set("outlineWidth", v) 975 | } 976 | 977 | func (s *CSS) Overflow() string { 978 | return s.Get("overflow").String() 979 | } 980 | 981 | func (s *CSS) SetOverflow(v string) { 982 | s.Set("overflow", v) 983 | } 984 | 985 | func (s *CSS) OverflowX() string { 986 | return s.Get("overflowX").String() 987 | } 988 | 989 | func (s *CSS) SetOverflowX(v string) { 990 | s.Set("overflowX", v) 991 | } 992 | 993 | func (s *CSS) OverflowY() string { 994 | return s.Get("overflowY").String() 995 | } 996 | 997 | func (s *CSS) SetOverflowY(v string) { 998 | s.Set("overflowY", v) 999 | } 1000 | 1001 | func (s *CSS) Padding() string { 1002 | return s.Get("padding").String() 1003 | } 1004 | 1005 | func (s *CSS) SetPadding(v string) { 1006 | s.Set("padding", v) 1007 | } 1008 | 1009 | func (s *CSS) PaddingBottom() string { 1010 | return s.Get("paddingBottom").String() 1011 | } 1012 | 1013 | func (s *CSS) SetPaddingBottom(v string) { 1014 | s.Set("paddingBottom", v) 1015 | } 1016 | 1017 | func (s *CSS) PaddingLeft() string { 1018 | return s.Get("paddingLeft").String() 1019 | } 1020 | 1021 | func (s *CSS) SetPaddingLeft(v string) { 1022 | s.Set("paddingLeft", v) 1023 | } 1024 | 1025 | func (s *CSS) PaddingRight() string { 1026 | return s.Get("paddingRight").String() 1027 | } 1028 | 1029 | func (s *CSS) SetPaddingRight(v string) { 1030 | s.Set("paddingRight", v) 1031 | } 1032 | 1033 | func (s *CSS) PaddingTop() string { 1034 | return s.Get("paddingTop").String() 1035 | } 1036 | 1037 | func (s *CSS) SetPaddingTop(v string) { 1038 | s.Set("paddingTop", v) 1039 | } 1040 | 1041 | func (s *CSS) PageBreakAfter() string { 1042 | return s.Get("pageBreakAfter").String() 1043 | } 1044 | 1045 | func (s *CSS) SetPageBreakAfter(v string) { 1046 | s.Set("pageBreakAfter", v) 1047 | } 1048 | 1049 | func (s *CSS) PageBreakBefore() string { 1050 | return s.Get("pageBreakBefore").String() 1051 | } 1052 | 1053 | func (s *CSS) SetPageBreakBefore(v string) { 1054 | s.Set("pageBreakBefore", v) 1055 | } 1056 | 1057 | func (s *CSS) PageBreakInside() string { 1058 | return s.Get("pageBreakInside").String() 1059 | } 1060 | 1061 | func (s *CSS) SetPageBreakInside(v string) { 1062 | s.Set("pageBreakInside", v) 1063 | } 1064 | 1065 | func (s *CSS) Perspective() string { 1066 | return s.Get("perspective").String() 1067 | } 1068 | 1069 | func (s *CSS) SetPerspective(v string) { 1070 | s.Set("perspective", v) 1071 | } 1072 | 1073 | func (s *CSS) PerspectiveOrigin() string { 1074 | return s.Get("perspectiveOrigin").String() 1075 | } 1076 | 1077 | func (s *CSS) SetPerspectiveOrigin(v string) { 1078 | s.Set("perspectiveOrigin", v) 1079 | } 1080 | 1081 | func (s *CSS) Position() string { 1082 | return s.Get("position").String() 1083 | } 1084 | 1085 | func (s *CSS) SetPosition(v string) { 1086 | s.Set("position", v) 1087 | } 1088 | 1089 | func (s *CSS) Quotes() string { 1090 | return s.Get("quotes").String() 1091 | } 1092 | 1093 | func (s *CSS) SetQuotes(v string) { 1094 | s.Set("quotes", v) 1095 | } 1096 | 1097 | func (s *CSS) Resize() string { 1098 | return s.Get("resize").String() 1099 | } 1100 | 1101 | func (s *CSS) SetResize(v string) { 1102 | s.Set("resize", v) 1103 | } 1104 | 1105 | func (s *CSS) Right() string { 1106 | return s.Get("right").String() 1107 | } 1108 | 1109 | func (s *CSS) SetRight(v string) { 1110 | s.Set("right", v) 1111 | } 1112 | 1113 | func (s *CSS) TableLayout() string { 1114 | return s.Get("tableLayout").String() 1115 | } 1116 | 1117 | func (s *CSS) SetTableLayout(v string) { 1118 | s.Set("tableLayout", v) 1119 | } 1120 | 1121 | func (s *CSS) TabSize() string { 1122 | return s.Get("tabSize").String() 1123 | } 1124 | 1125 | func (s *CSS) SetTabSize(v string) { 1126 | s.Set("tabSize", v) 1127 | } 1128 | 1129 | func (s *CSS) TextAlign() string { 1130 | return s.Get("textAlign").String() 1131 | } 1132 | 1133 | func (s *CSS) SetTextAlign(v string) { 1134 | s.Set("textAlign", v) 1135 | } 1136 | 1137 | func (s *CSS) TextAlignLast() string { 1138 | return s.Get("textAlignLast").String() 1139 | } 1140 | 1141 | func (s *CSS) SetTextAlignLast(v string) { 1142 | s.Set("textAlignLast", v) 1143 | } 1144 | 1145 | func (s *CSS) TextDecoration() string { 1146 | return s.Get("textDecoration").String() 1147 | } 1148 | 1149 | func (s *CSS) SetTextDecoration(v string) { 1150 | s.Set("textDecoration", v) 1151 | } 1152 | 1153 | func (s *CSS) TextDecorationColor() string { 1154 | return s.Get("textDecorationColor").String() 1155 | } 1156 | 1157 | func (s *CSS) SetTextDecorationColor(v string) { 1158 | s.Set("textDecorationColor", v) 1159 | } 1160 | 1161 | func (s *CSS) TextDecorationLine() string { 1162 | return s.Get("textDecorationLine").String() 1163 | } 1164 | 1165 | func (s *CSS) SetTextDecorationLine(v string) { 1166 | s.Set("textDecorationLine", v) 1167 | } 1168 | 1169 | func (s *CSS) TextDecorationStyle() string { 1170 | return s.Get("textDecorationStyle").String() 1171 | } 1172 | 1173 | func (s *CSS) SetTextDecorationStyle(v string) { 1174 | s.Set("textDecorationStyle", v) 1175 | } 1176 | 1177 | func (s *CSS) TextIndent() string { 1178 | return s.Get("textIndent").String() 1179 | } 1180 | 1181 | func (s *CSS) SetTextIndent(v string) { 1182 | s.Set("textIndent", v) 1183 | } 1184 | 1185 | func (s *CSS) TextOverflow() string { 1186 | return s.Get("textOverflow").String() 1187 | } 1188 | 1189 | func (s *CSS) SetTextOverflow(v string) { 1190 | s.Set("textOverflow", v) 1191 | } 1192 | 1193 | func (s *CSS) TextShadow() string { 1194 | return s.Get("textShadow").String() 1195 | } 1196 | 1197 | func (s *CSS) SetTextShadow(v string) { 1198 | s.Set("textShadow", v) 1199 | } 1200 | 1201 | func (s *CSS) TextTransform() string { 1202 | return s.Get("textTransform").String() 1203 | } 1204 | 1205 | func (s *CSS) SetTextTransform(v string) { 1206 | s.Set("textTransform", v) 1207 | } 1208 | 1209 | func (s *CSS) Top() string { 1210 | return s.Get("top").String() 1211 | } 1212 | 1213 | func (s *CSS) SetTop(v string) { 1214 | s.Set("top", v) 1215 | } 1216 | 1217 | func (s *CSS) Transform() string { 1218 | return s.Get("transform").String() 1219 | } 1220 | 1221 | func (s *CSS) SetTransform(v string) { 1222 | s.Set("transform", v) 1223 | } 1224 | 1225 | func (s *CSS) TransformOrigin() string { 1226 | return s.Get("transformOrigin").String() 1227 | } 1228 | 1229 | func (s *CSS) SetTransformOrigin(v string) { 1230 | s.Set("transformOrigin", v) 1231 | } 1232 | 1233 | func (s *CSS) TransformStyle() string { 1234 | return s.Get("transformStyle").String() 1235 | } 1236 | 1237 | func (s *CSS) SetTransformStyle(v string) { 1238 | s.Set("transformStyle", v) 1239 | } 1240 | 1241 | func (s *CSS) Transition() string { 1242 | return s.Get("transition").String() 1243 | } 1244 | 1245 | func (s *CSS) SetTransition(v string) { 1246 | s.Set("transition", v) 1247 | } 1248 | 1249 | func (s *CSS) TransitionProperty() string { 1250 | return s.Get("transitionProperty").String() 1251 | } 1252 | 1253 | func (s *CSS) SetTransitionProperty(v string) { 1254 | s.Set("transitionProperty", v) 1255 | } 1256 | 1257 | func (s *CSS) TransitionDuration() string { 1258 | return s.Get("transitionDuration").String() 1259 | } 1260 | 1261 | func (s *CSS) SetTransitionDuration(v string) { 1262 | s.Set("transitionDuration", v) 1263 | } 1264 | 1265 | func (s *CSS) TransitionTimingFunction() string { 1266 | return s.Get("transitionTimingFunction").String() 1267 | } 1268 | 1269 | func (s *CSS) SetTransitionTimingFunction(v string) { 1270 | s.Set("transitionTimingFunction", v) 1271 | } 1272 | 1273 | func (s *CSS) TransitionDelay() string { 1274 | return s.Get("transitionDelay").String() 1275 | } 1276 | 1277 | func (s *CSS) SetTransitionDelay(v string) { 1278 | s.Set("transitionDelay", v) 1279 | } 1280 | 1281 | func (s *CSS) UnicodeBidi() string { 1282 | return s.Get("unicodeBidi").String() 1283 | } 1284 | 1285 | func (s *CSS) SetUnicodeBidi(v string) { 1286 | s.Set("unicodeBidi", v) 1287 | } 1288 | 1289 | func (s *CSS) UserSelect() string { 1290 | return s.Get("userSelect").String() 1291 | } 1292 | 1293 | func (s *CSS) SetUserSelect(v string) { 1294 | s.Set("userSelect", v) 1295 | } 1296 | 1297 | func (s *CSS) VerticalAlign() string { 1298 | return s.Get("verticalAlign").String() 1299 | } 1300 | 1301 | func (s *CSS) SetVerticalAlign(v string) { 1302 | s.Set("verticalAlign", v) 1303 | } 1304 | 1305 | func (s *CSS) Visibility() string { 1306 | return s.Get("visibility").String() 1307 | } 1308 | 1309 | func (s *CSS) SetVisibility(v string) { 1310 | s.Set("visibility", v) 1311 | } 1312 | 1313 | func (s *CSS) WhiteSpace() string { 1314 | return s.Get("whiteSpace").String() 1315 | } 1316 | 1317 | func (s *CSS) SetWhiteSpace(v string) { 1318 | s.Set("whiteSpace", v) 1319 | } 1320 | 1321 | func (s *CSS) Width() string { 1322 | return s.Get("width").String() 1323 | } 1324 | 1325 | func (s *CSS) SetWidth(v string) { 1326 | s.Set("width", v) 1327 | } 1328 | 1329 | func (s *CSS) WordBreak() string { 1330 | return s.Get("wordBreak").String() 1331 | } 1332 | 1333 | func (s *CSS) SetWordBreak(v string) { 1334 | s.Set("wordBreak", v) 1335 | } 1336 | 1337 | func (s *CSS) WordSpacing() string { 1338 | return s.Get("wordSpacing").String() 1339 | } 1340 | 1341 | func (s *CSS) SetWordSpacing(v string) { 1342 | s.Set("wordSpacing", v) 1343 | } 1344 | 1345 | func (s *CSS) WordWrap() string { 1346 | return s.Get("wordWrap").String() 1347 | } 1348 | 1349 | func (s *CSS) SetWordWrap(v string) { 1350 | s.Set("wordWrap", v) 1351 | } 1352 | 1353 | func (s *CSS) Widows() string { 1354 | return s.Get("widows").String() 1355 | } 1356 | 1357 | func (s *CSS) SetWidows(v string) { 1358 | s.Set("widows", v) 1359 | } 1360 | 1361 | func (s *CSS) ZIndex() string { 1362 | return s.Get("zIndex").String() 1363 | } 1364 | 1365 | func (s *CSS) SetZIndex(v string) { 1366 | s.Set("zIndex", v) 1367 | } 1368 | --------------------------------------------------------------------------------