1// Package dom provides GopherJS bindings for the JavaScript DOM APIs.
2//
3// This package is an in progress effort of providing idiomatic Go
4// bindings for the DOM, wrapping the JavaScript DOM APIs. The API is
5// neither complete nor frozen yet, but a great amount of the DOM is
6// already useable.
7//
8// While the package tries to be idiomatic Go, it also tries to stick
9// closely to the JavaScript APIs, so that one does not need to learn
10// a new set of APIs if one is already familiar with it.
11//
12// One decision that hasn't been made yet is what parts exactly should
13// be part of this package. It is, for example, possible that the
14// canvas APIs will live in a separate package. On the other hand,
15// types such as StorageEvent (the event that gets fired when the
16// HTML5 storage area changes) will be part of this package, simply
17// due to how the DOM is structured – even if the actual storage APIs
18// might live in a separate package. This might require special care
19// to avoid circular dependencies.
20//
21// The documentation for some of the identifiers is based on the
22// MDN Web Docs by Mozilla Contributors (https://developer.mozilla.org/en-US/docs/Web/API),
23// licensed under CC-BY-SA 2.5 (https://creativecommons.org/licenses/by-sa/2.5/).
24//
25//
26// Getting started
27//
28// The usual entry point of using the dom package is by using the
29// GetWindow() function which will return a Window, from which you can
30// get things such as the current Document.
31//
32//
33// Interfaces
34//
35// The DOM has a big amount of different element and event types, but
36// they all follow three interfaces. All functions that work on or
37// return generic elements/events will return one of the three
38// interfaces Element, HTMLElement or Event. In these interface values
39// there will be concrete implementations, such as
40// HTMLParagraphElement or FocusEvent. It's also not unusual that
41// values of type Element also implement HTMLElement. In all cases,
42// type assertions can be used.
43//
44// Example:
45//     el := dom.GetWindow().Document().QuerySelector(".some-element")
46//     htmlEl := el.(dom.HTMLElement)
47//     pEl := el.(*dom.HTMLParagraphElement)
48//
49//
50// Live collections
51//
52// Several functions in the JavaScript DOM return "live"
53// collections of elements, that is collections that will be
54// automatically updated when elements get removed or added to the
55// DOM. Our bindings, however, return static slices of elements that,
56// once created, will not automatically reflect updates to the DOM.
57// This is primarily done so that slices can actually be used, as
58// opposed to a form of iterator, but also because we think that
59// magically changing data isn't Go's nature and that snapshots of
60// state are a lot easier to reason about.
61//
62// This does not, however, mean that all objects are snapshots.
63// Elements, events and generally objects that aren't slices or maps
64// are simple wrappers around JavaScript objects, and as such
65// attributes as well as method calls will always return the most
66// current data. To reflect this behaviour, these bindings use
67// pointers to make the semantics clear. Consider the following
68// example:
69//
70//     d := dom.GetWindow().Document()
71//     e1 := d.GetElementByID("my-element")
72//     e2 := d.GetElementByID("my-element")
73//
74//     e1.Class().SetString("some-class")
75//     println(e1.Class().String() == e2.Class().String())
76//
77// The above example will print `true`.
78//
79//
80// DOMTokenList
81//
82// Some objects in the JS API have two versions of attributes, one
83// that returns a string and one that returns a DOMTokenList to ease
84// manipulation of string-delimited lists. Some other objects only
85// provide DOMTokenList, sometimes DOMSettableTokenList. To simplify
86// these bindings, only the DOMTokenList variant will be made
87// available, by the type TokenList. In cases where the string
88// attribute was the only way to completely replace the value, our
89// TokenList will provide Set([]string) and SetString(string) methods,
90// which will be able to accomplish the same. Additionally, our
91// TokenList will provide methods to convert it to strings and slices.
92//
93//
94// Backwards compatibility
95//
96// This package has a relatively stable API. However, there will be
97// backwards incompatible changes from time to time. This is because
98// the package isn't complete yet, as well as because the DOM is a
99// moving target, and APIs do change sometimes.
100//
101// While an attempt is made to reduce changing function signatures to
102// a minimum, it can't always be guaranteed. Sometimes mistakes in the
103// bindings are found that require changing arguments or return
104// values.
105//
106// Interfaces defined in this package may also change on a
107// semi-regular basis, as new methods are added to them. This happens
108// because the bindings aren't complete and can never really be, as
109// new features are added to the DOM.
110//
111// If you depend on none of the APIs changing unexpectedly, you're
112// advised to vendor this package.
113package dom // import "honnef.co/go/js/dom"
114
115import (
116	"image"
117	"image/color"
118	"strings"
119	"time"
120
121	"github.com/gopherjs/gopherjs/js"
122)
123
124// toString returns the string representation of o. If o is nil or
125// undefined, the empty string will be returned instead.
126func toString(o *js.Object) string {
127	if o == nil || o == js.Undefined {
128		return ""
129	}
130	return o.String()
131}
132
133func callRecover(o *js.Object, fn string, args ...interface{}) (err error) {
134	defer func() {
135		e := recover()
136		if e == nil {
137			return
138		}
139		if panicErr, ok := e.(error); ok && panicErr != nil {
140			err = panicErr
141		} else {
142			panic(e)
143		}
144	}()
145	o.Call(fn, args...)
146	return nil
147}
148
149func elementConstructor(o *js.Object) *js.Object {
150	if n := o.Get("node"); n != js.Undefined {
151		// Support elements wrapped in Polymer's DOM APIs.
152		return n.Get("constructor")
153	}
154	return o.Get("constructor")
155}
156
157func arrayToObjects(o *js.Object) []*js.Object {
158	var out []*js.Object
159	for i := 0; i < o.Length(); i++ {
160		out = append(out, o.Index(i))
161	}
162	return out
163}
164
165func nodeListToObjects(o *js.Object) []*js.Object {
166	if o.Get("constructor") == js.Global.Get("Array") {
167		// Support Polymer's DOM APIs, which uses Arrays instead of
168		// NodeLists
169		return arrayToObjects(o)
170	}
171	var out []*js.Object
172	length := o.Get("length").Int()
173	for i := 0; i < length; i++ {
174		out = append(out, o.Call("item", i))
175	}
176	return out
177}
178
179func nodeListToNodes(o *js.Object) []Node {
180	var out []Node
181	for _, obj := range nodeListToObjects(o) {
182		out = append(out, wrapNode(obj))
183	}
184	return out
185}
186
187func nodeListToElements(o *js.Object) []Element {
188	var out []Element
189	for _, obj := range nodeListToObjects(o) {
190		out = append(out, wrapElement(obj))
191	}
192	return out
193}
194
195func nodeListToHTMLElements(o *js.Object) []HTMLElement {
196	var out []HTMLElement
197	for _, obj := range nodeListToObjects(o) {
198		out = append(out, wrapHTMLElement(obj))
199	}
200	return out
201}
202
203func WrapDocument(o *js.Object) Document {
204	return wrapDocument(o)
205}
206
207func WrapDocumentFragment(o *js.Object) DocumentFragment {
208	return wrapDocumentFragment(o)
209}
210
211func WrapNode(o *js.Object) Node {
212	return wrapNode(o)
213}
214
215func WrapElement(o *js.Object) Element {
216	return wrapElement(o)
217}
218
219func WrapHTMLElement(o *js.Object) HTMLElement {
220	return wrapHTMLElement(o)
221}
222
223func wrapDocument(o *js.Object) Document {
224	switch elementConstructor(o) {
225	case js.Global.Get("HTMLDocument"):
226		return &htmlDocument{&document{&BasicNode{o}}}
227	default:
228		return &document{&BasicNode{o}}
229	}
230}
231
232func wrapDocumentFragment(o *js.Object) DocumentFragment {
233	switch elementConstructor(o) {
234	// TODO: do we have any other stuff we want to check
235	default:
236		return &documentFragment{&BasicNode{o}}
237	}
238}
239
240func wrapNode(o *js.Object) Node {
241	if o == nil || o == js.Undefined {
242		return nil
243	}
244	switch elementConstructor(o) {
245	// TODO all the non-element cases
246	case js.Global.Get("Text"):
247		return &Text{&BasicNode{o}}
248	default:
249		return wrapElement(o)
250	}
251}
252
253func wrapElement(o *js.Object) Element {
254	if o == nil || o == js.Undefined {
255		return nil
256	}
257	switch elementConstructor(o) {
258	// TODO all the non-HTML cases
259	default:
260		return wrapHTMLElement(o)
261	}
262}
263
264func wrapHTMLElement(o *js.Object) HTMLElement {
265	if o == nil || o == js.Undefined {
266		return nil
267	}
268	el := &BasicHTMLElement{&BasicElement{&BasicNode{o}}}
269	c := elementConstructor(o)
270	switch c {
271	case js.Global.Get("HTMLAnchorElement"):
272		return &HTMLAnchorElement{BasicHTMLElement: el, URLUtils: &URLUtils{Object: o}}
273	case js.Global.Get("HTMLAppletElement"):
274		return &HTMLAppletElement{BasicHTMLElement: el}
275	case js.Global.Get("HTMLAreaElement"):
276		return &HTMLAreaElement{BasicHTMLElement: el, URLUtils: &URLUtils{Object: o}}
277	case js.Global.Get("HTMLAudioElement"):
278		return &HTMLAudioElement{HTMLMediaElement: &HTMLMediaElement{BasicHTMLElement: el}}
279	case js.Global.Get("HTMLBaseElement"):
280		return &HTMLBaseElement{BasicHTMLElement: el}
281	case js.Global.Get("HTMLBodyElement"):
282		return &HTMLBodyElement{BasicHTMLElement: el}
283	case js.Global.Get("HTMLBRElement"):
284		return &HTMLBRElement{BasicHTMLElement: el}
285	case js.Global.Get("HTMLButtonElement"):
286		return &HTMLButtonElement{BasicHTMLElement: el}
287	case js.Global.Get("HTMLCanvasElement"):
288		return &HTMLCanvasElement{BasicHTMLElement: el}
289	case js.Global.Get("HTMLDataElement"):
290		return &HTMLDataElement{BasicHTMLElement: el}
291	case js.Global.Get("HTMLDataListElement"):
292		return &HTMLDataListElement{BasicHTMLElement: el}
293	case js.Global.Get("HTMLDirectoryElement"):
294		return &HTMLDirectoryElement{BasicHTMLElement: el}
295	case js.Global.Get("HTMLDivElement"):
296		return &HTMLDivElement{BasicHTMLElement: el}
297	case js.Global.Get("HTMLDListElement"):
298		return &HTMLDListElement{BasicHTMLElement: el}
299	case js.Global.Get("HTMLEmbedElement"):
300		return &HTMLEmbedElement{BasicHTMLElement: el}
301	case js.Global.Get("HTMLFieldSetElement"):
302		return &HTMLFieldSetElement{BasicHTMLElement: el}
303	case js.Global.Get("HTMLFontElement"):
304		return &HTMLFontElement{BasicHTMLElement: el}
305	case js.Global.Get("HTMLFormElement"):
306		return &HTMLFormElement{BasicHTMLElement: el}
307	case js.Global.Get("HTMLFrameElement"):
308		return &HTMLFrameElement{BasicHTMLElement: el}
309	case js.Global.Get("HTMLFrameSetElement"):
310		return &HTMLFrameSetElement{BasicHTMLElement: el}
311	case js.Global.Get("HTMLHeadElement"):
312		return &HTMLHeadElement{BasicHTMLElement: el}
313	case js.Global.Get("HTMLHeadingElement"):
314		return &HTMLHeadingElement{BasicHTMLElement: el}
315	case js.Global.Get("HTMLHtmlElement"):
316		return &HTMLHtmlElement{BasicHTMLElement: el}
317	case js.Global.Get("HTMLHRElement"):
318		return &HTMLHRElement{BasicHTMLElement: el}
319	case js.Global.Get("HTMLIFrameElement"):
320		return &HTMLIFrameElement{BasicHTMLElement: el}
321	case js.Global.Get("HTMLImageElement"):
322		return &HTMLImageElement{BasicHTMLElement: el}
323	case js.Global.Get("HTMLInputElement"):
324		return &HTMLInputElement{BasicHTMLElement: el}
325	case js.Global.Get("HTMLKeygenElement"):
326		return &HTMLKeygenElement{BasicHTMLElement: el}
327	case js.Global.Get("HTMLLabelElement"):
328		return &HTMLLabelElement{BasicHTMLElement: el}
329	case js.Global.Get("HTMLLegendElement"):
330		return &HTMLLegendElement{BasicHTMLElement: el}
331	case js.Global.Get("HTMLLIElement"):
332		return &HTMLLIElement{BasicHTMLElement: el}
333	case js.Global.Get("HTMLLinkElement"):
334		return &HTMLLinkElement{BasicHTMLElement: el}
335	case js.Global.Get("HTMLMapElement"):
336		return &HTMLMapElement{BasicHTMLElement: el}
337	case js.Global.Get("HTMLMediaElement"):
338		return &HTMLMediaElement{BasicHTMLElement: el}
339	case js.Global.Get("HTMLMenuElement"):
340		return &HTMLMenuElement{BasicHTMLElement: el}
341	case js.Global.Get("HTMLMetaElement"):
342		return &HTMLMetaElement{BasicHTMLElement: el}
343	case js.Global.Get("HTMLMeterElement"):
344		return &HTMLMeterElement{BasicHTMLElement: el}
345	case js.Global.Get("HTMLModElement"):
346		return &HTMLModElement{BasicHTMLElement: el}
347	case js.Global.Get("HTMLObjectElement"):
348		return &HTMLObjectElement{BasicHTMLElement: el}
349	case js.Global.Get("HTMLOListElement"):
350		return &HTMLOListElement{BasicHTMLElement: el}
351	case js.Global.Get("HTMLOptGroupElement"):
352		return &HTMLOptGroupElement{BasicHTMLElement: el}
353	case js.Global.Get("HTMLOptionElement"):
354		return &HTMLOptionElement{BasicHTMLElement: el}
355	case js.Global.Get("HTMLOutputElement"):
356		return &HTMLOutputElement{BasicHTMLElement: el}
357	case js.Global.Get("HTMLParagraphElement"):
358		return &HTMLParagraphElement{BasicHTMLElement: el}
359	case js.Global.Get("HTMLParamElement"):
360		return &HTMLParamElement{BasicHTMLElement: el}
361	case js.Global.Get("HTMLPreElement"):
362		return &HTMLPreElement{BasicHTMLElement: el}
363	case js.Global.Get("HTMLProgressElement"):
364		return &HTMLProgressElement{BasicHTMLElement: el}
365	case js.Global.Get("HTMLQuoteElement"):
366		return &HTMLQuoteElement{BasicHTMLElement: el}
367	case js.Global.Get("HTMLScriptElement"):
368		return &HTMLScriptElement{BasicHTMLElement: el}
369	case js.Global.Get("HTMLSelectElement"):
370		return &HTMLSelectElement{BasicHTMLElement: el}
371	case js.Global.Get("HTMLSourceElement"):
372		return &HTMLSourceElement{BasicHTMLElement: el}
373	case js.Global.Get("HTMLSpanElement"):
374		return &HTMLSpanElement{BasicHTMLElement: el}
375	case js.Global.Get("HTMLStyleElement"):
376		return &HTMLStyleElement{BasicHTMLElement: el}
377	case js.Global.Get("HTMLTableElement"):
378		return &HTMLTableElement{BasicHTMLElement: el}
379	case js.Global.Get("HTMLTableCaptionElement"):
380		return &HTMLTableCaptionElement{BasicHTMLElement: el}
381	case js.Global.Get("HTMLTableCellElement"):
382		return &HTMLTableCellElement{BasicHTMLElement: el}
383	case js.Global.Get("HTMLTableDataCellElement"):
384		return &HTMLTableDataCellElement{BasicHTMLElement: el}
385	case js.Global.Get("HTMLTableHeaderCellElement"):
386		return &HTMLTableHeaderCellElement{BasicHTMLElement: el}
387	case js.Global.Get("HTMLTableColElement"):
388		return &HTMLTableColElement{BasicHTMLElement: el}
389	case js.Global.Get("HTMLTableRowElement"):
390		return &HTMLTableRowElement{BasicHTMLElement: el}
391	case js.Global.Get("HTMLTableSectionElement"):
392		return &HTMLTableSectionElement{BasicHTMLElement: el}
393	case js.Global.Get("HTMLTextAreaElement"):
394		return &HTMLTextAreaElement{BasicHTMLElement: el}
395	case js.Global.Get("HTMLTimeElement"):
396		return &HTMLTimeElement{BasicHTMLElement: el}
397	case js.Global.Get("HTMLTitleElement"):
398		return &HTMLTitleElement{BasicHTMLElement: el}
399	case js.Global.Get("HTMLTrackElement"):
400		return &HTMLTrackElement{BasicHTMLElement: el}
401	case js.Global.Get("HTMLUListElement"):
402		return &HTMLUListElement{BasicHTMLElement: el}
403	case js.Global.Get("HTMLUnknownElement"):
404		return &HTMLUnknownElement{BasicHTMLElement: el}
405	case js.Global.Get("HTMLVideoElement"):
406		return &HTMLVideoElement{HTMLMediaElement: &HTMLMediaElement{BasicHTMLElement: el}}
407	case js.Global.Get("HTMLElement"):
408		return el
409	default:
410		return el
411	}
412}
413
414func getForm(o *js.Object) *HTMLFormElement {
415	form := wrapHTMLElement(o.Get("form"))
416	if form == nil {
417		return nil
418	}
419	return form.(*HTMLFormElement)
420}
421
422func getLabels(o *js.Object) []*HTMLLabelElement {
423	labels := nodeListToElements(o.Get("labels"))
424	out := make([]*HTMLLabelElement, len(labels))
425	for i, label := range labels {
426		out[i] = label.(*HTMLLabelElement)
427	}
428	return out
429}
430
431func getOptions(o *js.Object, attr string) []*HTMLOptionElement {
432	options := nodeListToElements(o.Get(attr))
433	out := make([]*HTMLOptionElement, len(options))
434	for i, option := range options {
435		out[i] = option.(*HTMLOptionElement)
436	}
437	return out
438}
439
440func GetWindow() Window {
441	return &window{js.Global}
442}
443
444type TokenList struct {
445	dtl *js.Object // the underlying DOMTokenList
446	o   *js.Object // the object to which the DOMTokenList belongs
447	sa  string     // the name of the corresponding string attribute, empty if there isn't one
448
449	Length int `js:"length"`
450}
451
452func (tl *TokenList) Item(idx int) string {
453	o := tl.dtl.Call("item", idx)
454	return toString(o)
455}
456
457func (tl *TokenList) Contains(token string) bool {
458	return tl.dtl.Call("contains", token).Bool()
459}
460
461func (tl *TokenList) Add(token string) {
462	tl.dtl.Call("add", token)
463}
464
465func (tl *TokenList) Remove(token string) {
466	tl.dtl.Call("remove", token)
467}
468
469func (tl *TokenList) Toggle(token string) {
470	tl.dtl.Call("toggle", token)
471}
472
473func (tl *TokenList) String() string {
474	if tl.sa != "" {
475		return tl.o.Get(tl.sa).String()
476	}
477	if tl.dtl.Get("constructor") == js.Global.Get("DOMSettableTokenList") {
478		return tl.dtl.Get("value").String()
479	}
480	// We could manually construct the string, but I am not aware of
481	// any case where we have neither a string attribute nor
482	// DOMSettableTokenList.
483	return ""
484}
485
486func (tl *TokenList) Slice() []string {
487	var out []string
488	length := tl.dtl.Get("length").Int()
489	for i := 0; i < length; i++ {
490		out = append(out, tl.dtl.Call("item", i).String())
491	}
492	return out
493}
494
495// SetString sets the TokenList's value to the space-separated list of
496// tokens in s.
497func (tl *TokenList) SetString(s string) {
498	if tl.sa != "" {
499		tl.o.Set(tl.sa, s)
500		return
501	}
502	if tl.dtl.Get("constructor") == js.Global.Get("DOMSettableTokenList") {
503		tl.dtl.Set("value", s)
504		return
505	}
506	// This shouldn't be possible
507	panic("no way to SetString on this TokenList")
508}
509
510// Set sets the TokenList's value to the list of tokens in s.
511//
512// Individual tokens in s shouldn't countain spaces.
513func (tl *TokenList) Set(s []string) {
514	tl.SetString(strings.Join(s, " "))
515}
516
517type Document interface {
518	Node
519	ParentNode
520
521	Async() bool
522	SetAsync(bool)
523	Doctype() DocumentType
524	DocumentElement() Element
525	DocumentURI() string
526	Implementation() DOMImplementation
527	LastStyleSheetSet() string
528	PreferredStyleSheetSet() string // TODO correct type?
529	SelectedStyleSheetSet() string  // TODO correct type?
530	StyleSheets() []StyleSheet      // TODO s/StyleSheet/Stylesheet/ ?
531	StyleSheetSets() []StyleSheet   // TODO correct type?
532	AdoptNode(node Node) Node
533	ImportNode(node Node, deep bool) Node
534	CreateElement(name string) Element
535	CreateElementNS(namespace, name string) Element
536	CreateTextNode(s string) *Text
537	ElementFromPoint(x, y int) Element
538	EnableStyleSheetsForSet(name string)
539	GetElementsByClassName(name string) []Element
540	GetElementsByTagName(name string) []Element
541	GetElementsByTagNameNS(ns, name string) []Element
542	GetElementByID(id string) Element
543	QuerySelector(sel string) Element
544	QuerySelectorAll(sel string) []Element
545
546	CreateDocumentFragment() DocumentFragment
547}
548
549type DocumentFragment interface {
550	Node
551	ParentNode
552	QuerySelector(sel string) Element
553	QuerySelectorAll(sel string) []Element
554	GetElementByID(id string) Element
555}
556
557type HTMLDocument interface {
558	Document
559
560	ActiveElement() HTMLElement
561	Body() HTMLElement
562	Cookie() string
563	SetCookie(string)
564	DefaultView() Window
565	DesignMode() bool
566	SetDesignMode(bool)
567	Domain() string
568	SetDomain(string)
569	Forms() []*HTMLFormElement
570	Head() *HTMLHeadElement
571	Images() []*HTMLImageElement
572	LastModified() time.Time
573	Links() []HTMLElement
574	Location() *Location
575	Plugins() []*HTMLEmbedElement
576	ReadyState() string
577	Referrer() string
578	Scripts() []*HTMLScriptElement
579	Title() string
580	SetTitle(string)
581	URL() string
582
583	// TODO HTMLDocument methods
584}
585
586type documentFragment struct {
587	*BasicNode
588}
589
590func (d documentFragment) GetElementByID(id string) Element {
591	return wrapElement(d.Call("getElementById", id))
592}
593
594func (d documentFragment) QuerySelector(sel string) Element {
595	return (&BasicElement{&BasicNode{d.Object}}).QuerySelector(sel)
596}
597
598func (d documentFragment) QuerySelectorAll(sel string) []Element {
599	return (&BasicElement{&BasicNode{d.Object}}).QuerySelectorAll(sel)
600}
601
602type document struct {
603	*BasicNode
604}
605
606type htmlDocument struct {
607	*document
608}
609
610func (d *htmlDocument) ActiveElement() HTMLElement {
611	return wrapHTMLElement(d.Get("activeElement"))
612}
613
614func (d *htmlDocument) Body() HTMLElement {
615	return wrapHTMLElement(d.Get("body"))
616}
617
618func (d *htmlDocument) Cookie() string {
619	return d.Get("cookie").String()
620}
621
622func (d *htmlDocument) SetCookie(s string) {
623	d.Set("cookie", s)
624}
625
626func (d *htmlDocument) DefaultView() Window {
627	return &window{d.Get("defaultView")}
628}
629
630func (d *htmlDocument) DesignMode() bool {
631	s := d.Get("designMode").String()
632	return s != "off"
633}
634
635func (d *htmlDocument) SetDesignMode(b bool) {
636	s := "off"
637	if b {
638		s = "on"
639	}
640	d.Set("designMode", s)
641}
642
643func (d *htmlDocument) Domain() string {
644	return d.Get("domain").String()
645}
646
647func (d *htmlDocument) SetDomain(s string) {
648	d.Set("domain", s)
649}
650
651func (d *htmlDocument) Forms() []*HTMLFormElement {
652	var els []*HTMLFormElement
653	forms := d.Get("forms")
654	length := forms.Get("length").Int()
655	for i := 0; i < length; i++ {
656		els = append(els, wrapHTMLElement(forms.Call("item", i)).(*HTMLFormElement))
657	}
658	return els
659}
660
661func (d *htmlDocument) Head() *HTMLHeadElement {
662	head := wrapElement(d.Get("head"))
663	if head == nil {
664		return nil
665	}
666	return head.(*HTMLHeadElement)
667}
668
669func (d *htmlDocument) Images() []*HTMLImageElement {
670	var els []*HTMLImageElement
671	images := d.Get("images")
672	length := images.Get("length").Int()
673	for i := 0; i < length; i++ {
674		els = append(els, wrapHTMLElement(images.Call("item", i)).(*HTMLImageElement))
675	}
676	return els
677}
678
679func (d *htmlDocument) LastModified() time.Time {
680	return d.Get("lastModified").Interface().(time.Time)
681}
682
683func (d *htmlDocument) Links() []HTMLElement {
684	var els []HTMLElement
685	links := d.Get("links")
686	length := links.Get("length").Int()
687	for i := 0; i < length; i++ {
688		els = append(els, wrapHTMLElement(links.Call("item", i)))
689	}
690	return els
691}
692
693func (d *htmlDocument) Location() *Location {
694	o := d.Get("location")
695	return &Location{Object: o, URLUtils: &URLUtils{Object: o}}
696}
697
698func (d *htmlDocument) Plugins() []*HTMLEmbedElement {
699	var els []*HTMLEmbedElement
700	forms := d.Get("plugins")
701	length := forms.Get("length").Int()
702	for i := 0; i < length; i++ {
703		els = append(els, wrapHTMLElement(forms.Call("item", i)).(*HTMLEmbedElement))
704	}
705	return els
706}
707
708func (d *htmlDocument) ReadyState() string {
709	return d.Get("readyState").String()
710}
711
712func (d *htmlDocument) Referrer() string {
713	return d.Get("referrer").String()
714}
715
716func (d *htmlDocument) Scripts() []*HTMLScriptElement {
717	var els []*HTMLScriptElement
718	forms := d.Get("scripts")
719	length := forms.Get("length").Int()
720	for i := 0; i < length; i++ {
721		els = append(els, wrapHTMLElement(forms.Call("item", i)).(*HTMLScriptElement))
722	}
723	return els
724}
725
726func (d *htmlDocument) Title() string {
727	return d.Get("title").String()
728}
729
730func (d *htmlDocument) SetTitle(s string) {
731	d.Set("title", s)
732}
733
734func (d *htmlDocument) URL() string {
735	return d.Get("URL").String()
736}
737
738func (d document) Async() bool {
739	return d.Get("async").Bool()
740}
741
742func (d document) SetAsync(b bool) {
743	d.Set("async", b)
744}
745
746func (d document) Doctype() DocumentType {
747	// FIXME implement
748	panic("not implemented")
749}
750
751func (d document) DocumentElement() Element {
752	return wrapElement(d.Get("documentElement"))
753}
754
755func (d document) DocumentURI() string {
756	return d.Get("documentURI").String()
757}
758
759func (d document) Implementation() DOMImplementation {
760	// FIXME implement
761	panic("not implemented")
762}
763
764func (d document) LastStyleSheetSet() string {
765	return d.Get("lastStyleSheetSet").String()
766}
767
768func (d document) PreferredStyleSheetSet() string {
769	return d.Get("preferredStyleSheetSet").String()
770}
771
772func (d document) SelectedStyleSheetSet() string {
773	return d.Get("selectedStyleSheetSet").String()
774}
775
776func (d document) StyleSheets() []StyleSheet {
777	// FIXME implement
778	panic("not implemented")
779}
780
781func (d document) StyleSheetSets() []StyleSheet {
782	// FIXME implement
783	panic("not implemented")
784}
785
786func (d document) AdoptNode(node Node) Node {
787	return wrapNode(d.Call("adoptNode", node.Underlying()))
788}
789
790func (d document) ImportNode(node Node, deep bool) Node {
791	return wrapNode(d.Call("importNode", node.Underlying(), deep))
792}
793
794func (d document) CreateDocumentFragment() DocumentFragment {
795	return wrapDocumentFragment(d.Call("createDocumentFragment"))
796}
797
798func (d document) CreateElement(name string) Element {
799	return wrapElement(d.Call("createElement", name))
800}
801
802func (d document) CreateElementNS(ns string, name string) Element {
803	return wrapElement(d.Call("createElementNS", ns, name))
804}
805
806func (d document) CreateTextNode(s string) *Text {
807	return wrapNode(d.Call("createTextNode", s)).(*Text)
808}
809
810func (d document) ElementFromPoint(x, y int) Element {
811	return wrapElement(d.Call("elementFromPoint", x, y))
812}
813
814func (d document) EnableStyleSheetsForSet(name string) {
815	d.Call("enableStyleSheetsForSet", name)
816}
817
818func (d document) GetElementsByClassName(name string) []Element {
819	return (&BasicElement{&BasicNode{d.Object}}).GetElementsByClassName(name)
820}
821
822func (d document) GetElementsByTagName(name string) []Element {
823	return (&BasicElement{&BasicNode{d.Object}}).GetElementsByTagName(name)
824}
825
826func (d document) GetElementsByTagNameNS(ns, name string) []Element {
827	return (&BasicElement{&BasicNode{d.Object}}).GetElementsByTagNameNS(ns, name)
828}
829
830func (d document) GetElementByID(id string) Element {
831	return wrapElement(d.Call("getElementById", id))
832}
833
834func (d document) QuerySelector(sel string) Element {
835	return (&BasicElement{&BasicNode{d.Object}}).QuerySelector(sel)
836}
837
838func (d document) QuerySelectorAll(sel string) []Element {
839	return (&BasicElement{&BasicNode{d.Object}}).QuerySelectorAll(sel)
840}
841
842type URLUtils struct {
843	*js.Object
844
845	Href     string `js:"href"`
846	Protocol string `js:"protocol"`
847	Host     string `js:"host"`
848	Hostname string `js:"hostname"`
849	Port     string `js:"port"`
850	Pathname string `js:"pathname"`
851	Search   string `js:"search"`
852	Hash     string `js:"hash"`
853	Username string `js:"username"`
854	Password string `js:"password"`
855	Origin   string `js:"origin"`
856}
857
858// TODO Location methods
859
860type Location struct {
861	*js.Object
862	*URLUtils
863}
864
865type HTMLElement interface {
866	Element
867	GlobalEventHandlers
868
869	AccessKey() string
870	Dataset() map[string]string
871	SetAccessKey(string)
872	AccessKeyLabel() string
873	SetAccessKeyLabel(string)
874	ContentEditable() string
875	SetContentEditable(string)
876	IsContentEditable() bool
877	Dir() string
878	SetDir(string)
879	Draggable() bool
880	SetDraggable(bool)
881	Lang() string
882	SetLang(string)
883	OffsetHeight() float64
884	OffsetLeft() float64
885	OffsetParent() HTMLElement
886	OffsetTop() float64
887	OffsetWidth() float64
888	Style() *CSSStyleDeclaration
889	Title() string
890	SetTitle(string)
891	Blur()
892	Click()
893	Focus()
894}
895type SVGElement interface {
896	Element
897	// TODO
898}
899
900type GlobalEventHandlers interface{}
901
902type Window interface {
903	EventTarget
904
905	Console() *Console
906	Document() Document
907	FrameElement() Element
908	Location() *Location
909	Name() string
910	SetName(string)
911	InnerHeight() int
912	InnerWidth() int
913	Length() int
914	Opener() Window
915	OuterHeight() int
916	OuterWidth() int
917	ScrollX() int
918	ScrollY() int
919	Parent() Window
920	ScreenX() int
921	ScreenY() int
922	ScrollMaxX() int
923	ScrollMaxY() int
924	Top() Window
925	History() History
926	Navigator() Navigator
927	Screen() *Screen
928	Alert(string)
929	Back()
930	Blur()
931	CancelAnimationFrame(int)
932	ClearInterval(int)
933	ClearTimeout(int)
934	Close()
935	Confirm(string) bool
936	Focus()
937	Forward()
938	GetComputedStyle(el Element, pseudoElt string) *CSSStyleDeclaration
939	GetSelection() Selection
940	Home()
941	MoveBy(dx, dy int)
942	MoveTo(x, y int)
943	Open(url, name, features string) Window
944	OpenDialog(url, name, features string, args []interface{}) Window
945	PostMessage(message string, target string, transfer []interface{})
946	Print()
947	Prompt(prompt string, initial string) string
948	RequestAnimationFrame(callback func(time.Duration)) int
949	ResizeBy(dw, dh int)
950	ResizeTo(w, h int)
951	Scroll(x, y int)
952	ScrollBy(dx, dy int)
953	ScrollByLines(int)
954	ScrollTo(x, y int)
955	SetCursor(name string)
956	SetInterval(fn func(), delay int) int
957	SetTimeout(fn func(), delay int) int
958	Stop()
959	// TODO constructors
960}
961
962type window struct {
963	// TODO EventTarget
964	*js.Object
965}
966
967func (w *window) Console() *Console {
968	return &Console{w.Get("console")}
969}
970
971func (w *window) Document() Document {
972	return wrapDocument(w.Get("document"))
973}
974
975func (w *window) FrameElement() Element {
976	return wrapElement(w.Get("frameElement"))
977}
978
979func (w *window) Location() *Location {
980	o := w.Get("location")
981	return &Location{Object: o, URLUtils: &URLUtils{Object: o}}
982}
983
984func (w *window) Name() string {
985	return w.Get("name").String()
986}
987
988func (w *window) SetName(s string) {
989	w.Set("name", s)
990}
991
992func (w *window) InnerHeight() int {
993	return w.Get("innerHeight").Int()
994}
995
996func (w *window) InnerWidth() int {
997	return w.Get("innerWidth").Int()
998}
999
1000func (w *window) Length() int {
1001	return w.Get("length").Int()
1002}
1003
1004func (w *window) Opener() Window {
1005	return &window{w.Get("opener")}
1006}
1007
1008func (w *window) OuterHeight() int {
1009	return w.Get("outerHeight").Int()
1010}
1011
1012func (w *window) OuterWidth() int {
1013	return w.Get("outerWidth").Int()
1014}
1015
1016func (w *window) ScrollX() int {
1017	return w.Get("scrollX").Int()
1018}
1019
1020func (w *window) ScrollY() int {
1021	return w.Get("scrollY").Int()
1022}
1023
1024func (w *window) Parent() Window {
1025	return &window{w.Get("parent")}
1026}
1027
1028func (w *window) ScreenX() int {
1029	return w.Get("screenX").Int()
1030}
1031
1032func (w *window) ScreenY() int {
1033	return w.Get("screenY").Int()
1034}
1035
1036func (w *window) ScrollMaxX() int {
1037	return w.Get("scrollMaxX").Int()
1038}
1039
1040func (w *window) ScrollMaxY() int {
1041	return w.Get("scrollMaxY").Int()
1042}
1043
1044func (w *window) Top() Window {
1045	return &window{w.Get("top")}
1046}
1047
1048func (w *window) History() History {
1049	// FIXME implement
1050	return nil
1051}
1052
1053func (w *window) Navigator() Navigator {
1054	// FIXME implement
1055	panic("not implemented")
1056}
1057
1058func (w *window) Screen() *Screen {
1059	return &Screen{Object: w.Get("screen")}
1060}
1061
1062func (w *window) Alert(msg string) {
1063	w.Call("alert", msg)
1064}
1065
1066func (w *window) Back() {
1067	w.Call("back")
1068}
1069
1070func (w *window) Blur() {
1071	w.Call("blur")
1072}
1073
1074func (w *window) ClearInterval(id int) {
1075	w.Call("clearInterval", id)
1076}
1077
1078func (w *window) ClearTimeout(id int) {
1079	w.Call("clearTimeout", id)
1080}
1081
1082func (w *window) Close() {
1083	w.Call("close")
1084}
1085
1086func (w *window) Confirm(prompt string) bool {
1087	return w.Call("confirm", prompt).Bool()
1088}
1089
1090func (w *window) Focus() {
1091	w.Call("focus")
1092}
1093
1094func (w *window) Forward() {
1095	w.Call("forward")
1096}
1097
1098// GetComputedStyle returns the values of all CSS properties of an
1099// element after applying the active stylesheets. pseudoElt specifies
1100// the pseudo-element to match. For normal elements, it must be the
1101// empty string.
1102func (w *window) GetComputedStyle(el Element, pseudoElt string) *CSSStyleDeclaration {
1103	var optArg interface{}
1104	if pseudoElt != "" {
1105		optArg = pseudoElt
1106	}
1107	return &CSSStyleDeclaration{w.Call("getComputedStyle", el.Underlying(), optArg)}
1108}
1109
1110func (w *window) GetSelection() Selection {
1111	// FIXME implement
1112	panic("not implemented")
1113}
1114
1115func (w *window) Home() {
1116	w.Call("home")
1117}
1118
1119func (w *window) MoveBy(dx, dy int) {
1120	w.Call("moveBy", dx, dy)
1121}
1122
1123func (w *window) MoveTo(x, y int) {
1124	w.Call("moveTo", x, y)
1125}
1126
1127func (w *window) Open(url, name, features string) Window {
1128	return &window{w.Call("open", url, name, features)}
1129}
1130
1131func (w *window) OpenDialog(url, name, features string, args []interface{}) Window {
1132	return &window{w.Call("openDialog", url, name, features, args)}
1133}
1134
1135func (w *window) PostMessage(message string, target string, transfer []interface{}) {
1136	w.Call("postMessage", message, target, transfer)
1137}
1138
1139func (w *window) Print() {
1140	w.Call("print")
1141}
1142
1143func (w *window) Prompt(prompt string, initial string) string {
1144	return w.Call("prompt", prompt, initial).String()
1145}
1146
1147func (w *window) ResizeBy(dw, dh int) {
1148	w.Call("resizeBy", dw, dh)
1149}
1150
1151func (w *window) ResizeTo(width, height int) {
1152	w.Call("resizeTo", width, height)
1153}
1154
1155func (w *window) Scroll(x, y int) {
1156	w.Call("scroll", x, y)
1157}
1158
1159func (w *window) ScrollBy(dx, dy int) {
1160	w.Call("scrollBy", dx, dy)
1161}
1162
1163func (w *window) ScrollByLines(i int) {
1164	w.Call("scrollByLines", i)
1165}
1166
1167func (w *window) ScrollTo(x, y int) {
1168	w.Call("scrollTo", x, y)
1169}
1170
1171func (w *window) SetCursor(name string) {
1172	w.Call("setCursor", name)
1173}
1174
1175func (w *window) SetInterval(fn func(), delay int) int {
1176	return w.Call("setInterval", fn, delay).Int()
1177}
1178
1179func (w *window) SetTimeout(fn func(), delay int) int {
1180	return w.Call("setTimeout", fn, delay).Int()
1181}
1182
1183func (w *window) Stop() {
1184	w.Call("stop")
1185}
1186
1187// TODO reuse util.EventTarget
1188
1189func (w *window) AddEventListener(typ string, useCapture bool, listener func(Event)) func(o *js.Object) {
1190	wrapper := func(o *js.Object) { listener(wrapEvent(o)) }
1191	w.Call("addEventListener", typ, wrapper, useCapture)
1192	return wrapper
1193}
1194
1195func (w *window) RemoveEventListener(typ string, useCapture bool, listener func(*js.Object)) {
1196	w.Call("removeEventListener", typ, listener, useCapture)
1197}
1198
1199func (w *window) DispatchEvent(event Event) bool {
1200	return w.Call("dispatchEvent", event).Bool()
1201}
1202
1203func wrapDOMHighResTimeStamp(o *js.Object) time.Duration {
1204	return time.Duration(o.Float() * float64(time.Millisecond))
1205}
1206
1207func (w *window) RequestAnimationFrame(callback func(time.Duration)) int {
1208	wrapper := func(o *js.Object) { callback(wrapDOMHighResTimeStamp(o)) }
1209	return w.Call("requestAnimationFrame", wrapper).Int()
1210}
1211
1212func (w *window) CancelAnimationFrame(requestID int) {
1213	w.Call("cancelAnimationFrame", requestID)
1214}
1215
1216// TODO all the other window methods
1217
1218type Selection interface {
1219	// TODO
1220}
1221
1222type Screen struct {
1223	*js.Object
1224	AvailTop    int `js:"availTop"`
1225	AvailLeft   int `js:"availLeft"`
1226	AvailHeight int `js:"availHeight"`
1227	AvailWidth  int `js:"availWidth"`
1228	ColorDepth  int `js:"colorDepth"`
1229	Height      int `js:"height"`
1230	Left        int `js:"left"`
1231	PixelDepth  int `js:"pixelDepth"`
1232	Top         int `js:"top"`
1233	Width       int `js:"width"`
1234}
1235
1236type Navigator interface {
1237	NavigatorID
1238	NavigatorLanguage
1239	NavigatorOnLine
1240	NavigatorGeolocation
1241	// NavigatorPlugins
1242	// NetworkInformation
1243	CookieEnabled() bool
1244	DoNotTrack() string
1245	RegisterProtocolHandler(protocol, uri, title string)
1246}
1247
1248type NavigatorID interface {
1249	AppName() string
1250	AppVersion() string
1251	Platform() string
1252	Product() string
1253	UserAgent() string
1254}
1255
1256type NavigatorLanguage interface {
1257	Language() string
1258}
1259
1260type NavigatorOnLine interface {
1261	Online() bool
1262}
1263
1264type NavigatorGeolocation interface {
1265	Geolocation() Geolocation
1266}
1267
1268type Geolocation interface {
1269	// TODO wrap PositionOptions into something that uses the JS
1270	// object
1271	CurrentPosition(success func(Position), err func(PositionError), opts PositionOptions) Position
1272	WatchPosition(success func(Position), err func(PositionError), opts PositionOptions) int
1273	ClearWatch(int)
1274}
1275
1276type PositionError struct {
1277	*js.Object
1278	Code int `js:"code"`
1279}
1280
1281func (err *PositionError) Error() string {
1282	return err.Call("message").String()
1283}
1284
1285type PositionOptions struct {
1286	EnableHighAccuracy bool
1287	Timeout            time.Duration
1288	MaximumAge         time.Duration
1289}
1290
1291type Position struct {
1292	Coords    *Coordinates
1293	Timestamp time.Time
1294}
1295
1296type Coordinates struct {
1297	*js.Object
1298	Latitude         float64 `js:"latitude"`
1299	Longitude        float64 `js:"longitude"`
1300	Altitude         float64 `js:"altitude"`
1301	Accuracy         float64 `js:"accuracy"`
1302	AltitudeAccuracy float64 `js:"altitudeAccuracy"`
1303	Heading          float64 `js:"heading"`
1304	Speed            float64 `js:"speed"`
1305}
1306
1307type History interface {
1308	Length() int
1309	State() interface{}
1310	Back()
1311	Forward()
1312	Go(offset int)
1313	PushState(state interface{}, title string, url string)
1314	ReplaceState(state interface{}, title string, url string)
1315}
1316
1317type Console struct {
1318	*js.Object
1319	// TODO will replace the js/console package
1320}
1321
1322type SVGDocument interface{}
1323type DocumentType interface{}
1324type DOMImplementation interface{}
1325type StyleSheet interface{}
1326type CSSStyleSheet interface{}
1327
1328type Node interface {
1329	EventTarget
1330
1331	Underlying() *js.Object
1332	BaseURI() string
1333	ChildNodes() []Node
1334	FirstChild() Node
1335	LastChild() Node
1336	NextSibling() Node
1337	NodeName() string
1338	NodeType() int
1339	NodeValue() string
1340	SetNodeValue(string)
1341	OwnerDocument() Document
1342	ParentNode() Node
1343	ParentElement() Element
1344	PreviousSibling() Node
1345	TextContent() string
1346	SetTextContent(string)
1347	AppendChild(Node)
1348	CloneNode(deep bool) Node
1349	CompareDocumentPosition(Node) int
1350	Contains(Node) bool
1351	HasChildNodes() bool
1352	InsertBefore(which Node, before Node)
1353	IsDefaultNamespace(string) bool
1354	IsEqualNode(Node) bool
1355	LookupPrefix() string
1356	LookupNamespaceURI(string) string
1357	Normalize()
1358	RemoveChild(Node)
1359	ReplaceChild(newChild, oldChild Node)
1360}
1361
1362// Type BasicNode implements the Node interface and is embedded by
1363// concrete node types and element types.
1364type BasicNode struct {
1365	*js.Object
1366}
1367
1368func (n *BasicNode) Underlying() *js.Object {
1369	return n.Object
1370}
1371
1372func (n *BasicNode) AddEventListener(typ string, useCapture bool, listener func(Event)) func(*js.Object) {
1373	wrapper := func(o *js.Object) { listener(wrapEvent(o)) }
1374	n.Call("addEventListener", typ, wrapper, useCapture)
1375	return wrapper
1376}
1377
1378func (n *BasicNode) RemoveEventListener(typ string, useCapture bool, listener func(*js.Object)) {
1379	n.Call("removeEventListener", typ, listener, useCapture)
1380}
1381
1382func (n *BasicNode) DispatchEvent(event Event) bool {
1383	return n.Call("dispatchEvent", event).Bool()
1384}
1385
1386func (n *BasicNode) BaseURI() string {
1387	return n.Get("baseURI").String()
1388}
1389
1390func (n *BasicNode) ChildNodes() []Node {
1391	return nodeListToNodes(n.Get("childNodes"))
1392}
1393
1394func (n *BasicNode) FirstChild() Node {
1395	return wrapNode(n.Get("firstChild"))
1396}
1397
1398func (n *BasicNode) LastChild() Node {
1399	return wrapNode(n.Get("lastChild"))
1400}
1401
1402func (n *BasicNode) NextSibling() Node {
1403	return wrapNode(n.Get("nextSibling"))
1404}
1405
1406func (n *BasicNode) NodeName() string {
1407	return n.Get("nodeName").String()
1408}
1409
1410func (n *BasicNode) NodeType() int {
1411	return n.Get("nodeType").Int()
1412}
1413
1414func (n *BasicNode) NodeValue() string {
1415	return toString(n.Get("nodeValue"))
1416}
1417
1418func (n *BasicNode) SetNodeValue(s string) {
1419	n.Set("nodeValue", s)
1420}
1421
1422func (n *BasicNode) OwnerDocument() Document {
1423	// FIXME implement
1424	panic("not implemented")
1425}
1426
1427func (n *BasicNode) ParentNode() Node {
1428	return wrapNode(n.Get("parentNode"))
1429}
1430
1431func (n *BasicNode) ParentElement() Element {
1432	return wrapElement(n.Get("parentElement"))
1433}
1434
1435func (n *BasicNode) PreviousSibling() Node {
1436	return wrapNode(n.Get("previousSibling"))
1437}
1438
1439func (n *BasicNode) TextContent() string {
1440	return toString(n.Get("textContent"))
1441}
1442
1443func (n *BasicNode) SetTextContent(s string) {
1444	n.Set("textContent", s)
1445}
1446
1447func (n *BasicNode) AppendChild(newchild Node) {
1448	n.Call("appendChild", newchild.Underlying())
1449}
1450
1451func (n *BasicNode) CloneNode(deep bool) Node {
1452	return wrapNode(n.Call("cloneNode", deep))
1453}
1454
1455const (
1456	DocumentPositionDisconnected           = 1
1457	DocumentPositionPreceding              = 2
1458	DocumentPositionFollowing              = 4
1459	DocumentPositionContains               = 8
1460	DocumentPositionContainedBy            = 16
1461	DocumentPositionImplementationSpecific = 32
1462)
1463
1464func (n *BasicNode) CompareDocumentPosition(other Node) int {
1465	return n.Call("compareDocumentPosition", other.Underlying()).Int()
1466}
1467
1468func (n *BasicNode) Contains(other Node) bool {
1469	return n.Call("contains", other.Underlying()).Bool()
1470}
1471
1472func (n *BasicNode) HasChildNodes() bool {
1473	return n.Call("hasChildNodes").Bool()
1474}
1475
1476func (n *BasicNode) InsertBefore(which Node, before Node) {
1477	var o interface{}
1478	if before != nil {
1479		o = before.Underlying()
1480	}
1481	n.Call("insertBefore", which.Underlying(), o)
1482}
1483
1484func (n *BasicNode) IsDefaultNamespace(s string) bool {
1485	return n.Call("isDefaultNamespace", s).Bool()
1486}
1487
1488func (n *BasicNode) IsEqualNode(other Node) bool {
1489	return n.Call("isEqualNode", other.Underlying()).Bool()
1490}
1491
1492func (n *BasicNode) LookupPrefix() string {
1493	return n.Call("lookupPrefix").String()
1494}
1495
1496func (n *BasicNode) LookupNamespaceURI(s string) string {
1497	return toString(n.Call("lookupNamespaceURI", s))
1498}
1499
1500func (n *BasicNode) Normalize() {
1501	n.Call("normalize")
1502}
1503
1504func (n *BasicNode) RemoveChild(other Node) {
1505	n.Call("removeChild", other.Underlying())
1506}
1507
1508func (n *BasicNode) ReplaceChild(newChild, oldChild Node) {
1509	n.Call("replaceChild", newChild.Underlying(), oldChild.Underlying())
1510}
1511
1512type Element interface {
1513	Node
1514	ParentNode
1515	ChildNode
1516
1517	Attributes() map[string]string
1518	Class() *TokenList
1519	ID() string
1520	SetID(string)
1521	TagName() string
1522	GetAttribute(string) string                   // TODO can attributes only be strings?
1523	GetAttributeNS(ns string, name string) string // can attributes only be strings?
1524	GetBoundingClientRect() ClientRect
1525	GetElementsByClassName(string) []Element
1526	GetElementsByTagName(string) []Element
1527	GetElementsByTagNameNS(ns string, name string) []Element
1528	HasAttribute(string) bool
1529	HasAttributeNS(ns string, name string) bool
1530	QuerySelector(string) Element
1531	QuerySelectorAll(string) []Element
1532	RemoveAttribute(string)
1533	RemoveAttributeNS(ns string, name string)
1534	SetAttribute(name string, value string)
1535	SetAttributeNS(ns string, name string, value string)
1536	InnerHTML() string
1537	SetInnerHTML(string)
1538	OuterHTML() string
1539	SetOuterHTML(string)
1540}
1541
1542type ClientRect struct {
1543	*js.Object
1544	Height float64 `js:"height"`
1545	Width  float64 `js:"width"`
1546	Left   float64 `js:"left"`
1547	Right  float64 `js:"right"`
1548	Top    float64 `js:"top"`
1549	Bottom float64 `js:"bottom"`
1550}
1551
1552type ParentNode interface {
1553	// No properties/methods that aren't experimental
1554}
1555
1556type ChildNode interface {
1557	PreviousElementSibling() Element
1558	NextElementSibling() Element
1559}
1560
1561// Type BasicHTMLElement implements the HTMLElement interface and is
1562// embedded by concrete HTML element types.
1563type BasicHTMLElement struct {
1564	*BasicElement
1565	// TODO globalEventHandlers
1566}
1567
1568func (e *BasicHTMLElement) AccessKey() string {
1569	return e.Get("accessKey").String()
1570}
1571
1572func (e *BasicHTMLElement) Dataset() map[string]string {
1573	o := e.Get("dataset")
1574	data := map[string]string{}
1575	keys := js.Keys(o)
1576	for _, key := range keys {
1577		data[key] = o.Get(key).String()
1578	}
1579	return data
1580}
1581
1582func (e *BasicHTMLElement) SetAccessKey(s string) {
1583	e.Set("accessKey", s)
1584}
1585
1586func (e *BasicHTMLElement) AccessKeyLabel() string {
1587	return e.Get("accessKeyLabel").String()
1588}
1589
1590func (e *BasicHTMLElement) SetAccessKeyLabel(s string) {
1591	e.Set("accessKeyLabel", s)
1592}
1593
1594func (e *BasicHTMLElement) ContentEditable() string {
1595	return e.Get("contentEditable").String()
1596}
1597
1598func (e *BasicHTMLElement) SetContentEditable(s string) {
1599	e.Set("contentEditable", s)
1600}
1601
1602func (e *BasicHTMLElement) IsContentEditable() bool {
1603	return e.Get("isContentEditable").Bool()
1604}
1605
1606func (e *BasicHTMLElement) Dir() string {
1607	return e.Get("dir").String()
1608}
1609
1610func (e *BasicHTMLElement) SetDir(s string) {
1611	e.Set("dir", s)
1612}
1613
1614func (e *BasicHTMLElement) Draggable() bool {
1615	return e.Get("draggable").Bool()
1616}
1617
1618func (e *BasicHTMLElement) SetDraggable(b bool) {
1619	e.Set("draggable", b)
1620}
1621
1622func (e *BasicHTMLElement) Lang() string {
1623	return e.Get("lang").String()
1624}
1625
1626func (e *BasicHTMLElement) SetLang(s string) {
1627	e.Set("lang", s)
1628}
1629
1630func (e *BasicHTMLElement) OffsetHeight() float64 {
1631	return e.Get("offsetHeight").Float()
1632}
1633
1634func (e *BasicHTMLElement) OffsetLeft() float64 {
1635	return e.Get("offsetLeft").Float()
1636}
1637
1638func (e *BasicHTMLElement) OffsetParent() HTMLElement {
1639	return wrapHTMLElement(e.Get("offsetParent"))
1640}
1641
1642func (e *BasicHTMLElement) OffsetTop() float64 {
1643	return e.Get("offsetTop").Float()
1644}
1645
1646func (e *BasicHTMLElement) OffsetWidth() float64 {
1647	return e.Get("offsetWidth").Float()
1648}
1649
1650func (e *BasicHTMLElement) Style() *CSSStyleDeclaration {
1651	return &CSSStyleDeclaration{e.Get("style")}
1652}
1653
1654func (e *BasicHTMLElement) TabIndex() int {
1655	return e.Get("tabIndex").Int()
1656}
1657
1658func (e *BasicHTMLElement) SetTabIndex(i int) {
1659	e.Set("tabIndex", i)
1660}
1661
1662func (e *BasicHTMLElement) Title() string {
1663	return e.Get("title").String()
1664}
1665
1666func (e *BasicHTMLElement) SetTitle(s string) {
1667	e.Set("title", s)
1668}
1669
1670func (e *BasicHTMLElement) Blur() {
1671	e.Call("blur")
1672}
1673
1674func (e *BasicHTMLElement) Click() {
1675	e.Call("click")
1676}
1677
1678func (e *BasicHTMLElement) Focus() {
1679	e.Call("focus")
1680}
1681
1682// Type BasicElement implements the Element interface and is embedded
1683// by concrete element types and HTML element types.
1684type BasicElement struct {
1685	*BasicNode
1686}
1687
1688func (e *BasicElement) Attributes() map[string]string {
1689	o := e.Get("attributes")
1690	attrs := map[string]string{}
1691	length := o.Get("length").Int()
1692	for i := 0; i < length; i++ {
1693		item := o.Call("item", i)
1694		attrs[item.Get("name").String()] = item.Get("value").String()
1695	}
1696	return attrs
1697}
1698
1699func (e *BasicElement) GetBoundingClientRect() ClientRect {
1700	obj := e.Call("getBoundingClientRect")
1701	return ClientRect{Object: obj}
1702}
1703
1704func (e *BasicElement) PreviousElementSibling() Element {
1705	return wrapElement(e.Get("previousElementSibling"))
1706}
1707
1708func (e *BasicElement) NextElementSibling() Element {
1709	return wrapElement(e.Get("nextElementSibling"))
1710}
1711
1712func (e *BasicElement) Class() *TokenList {
1713	return &TokenList{dtl: e.Get("classList"), o: e.Object, sa: "className"}
1714}
1715
1716// SetClass sets the element's className attribute to s. Consider
1717// using the Class method instead.
1718func (e *BasicElement) SetClass(s string) {
1719	e.Set("className", s)
1720}
1721
1722func (e *BasicElement) ID() string {
1723	return e.Get("id").String()
1724}
1725
1726func (e *BasicElement) SetID(s string) {
1727	e.Set("id", s)
1728}
1729
1730func (e *BasicElement) TagName() string {
1731	return e.Get("tagName").String()
1732}
1733
1734func (e *BasicElement) GetAttribute(name string) string {
1735	return toString(e.Call("getAttribute", name))
1736}
1737
1738func (e *BasicElement) GetAttributeNS(ns string, name string) string {
1739	return toString(e.Call("getAttributeNS", ns, name))
1740}
1741
1742func (e *BasicElement) GetElementsByClassName(s string) []Element {
1743	return nodeListToElements(e.Call("getElementsByClassName", s))
1744}
1745
1746func (e *BasicElement) GetElementsByTagName(s string) []Element {
1747	return nodeListToElements(e.Call("getElementsByTagName", s))
1748}
1749
1750func (e *BasicElement) GetElementsByTagNameNS(ns string, name string) []Element {
1751	return nodeListToElements(e.Call("getElementsByTagNameNS", ns, name))
1752}
1753
1754func (e *BasicElement) HasAttribute(s string) bool {
1755	return e.Call("hasAttribute", s).Bool()
1756}
1757
1758func (e *BasicElement) HasAttributeNS(ns string, name string) bool {
1759	return e.Call("hasAttributeNS", ns, name).Bool()
1760}
1761
1762func (e *BasicElement) QuerySelector(s string) Element {
1763	return wrapElement(e.Call("querySelector", s))
1764}
1765
1766func (e *BasicElement) QuerySelectorAll(s string) []Element {
1767	return nodeListToElements(e.Call("querySelectorAll", s))
1768}
1769
1770func (e *BasicElement) RemoveAttribute(s string) {
1771	e.Call("removeAttribute", s)
1772}
1773
1774func (e *BasicElement) RemoveAttributeNS(ns string, name string) {
1775	e.Call("removeAttributeNS", ns, name)
1776}
1777
1778func (e *BasicElement) SetAttribute(name string, value string) {
1779	e.Call("setAttribute", name, value)
1780}
1781
1782func (e *BasicElement) SetAttributeNS(ns string, name string, value string) {
1783	e.Call("setAttributeNS", ns, name, value)
1784}
1785
1786func (e *BasicElement) InnerHTML() string {
1787	return e.Get("innerHTML").String()
1788}
1789
1790func (e *BasicElement) SetInnerHTML(s string) {
1791	e.Set("innerHTML", s)
1792}
1793
1794func (e *BasicElement) OuterHTML() string {
1795	return e.Get("outerHTML").String()
1796}
1797
1798func (e *BasicElement) SetOuterHTML(s string) {
1799	e.Set("outerHTML", s)
1800}
1801
1802type HTMLAnchorElement struct {
1803	*BasicHTMLElement
1804	*URLUtils
1805	HrefLang string `js:"hreflang"`
1806	Media    string `js:"media"`
1807	TabIndex int    `js:"tabIndex"`
1808	Target   string `js:"target"`
1809	Text     string `js:"text"`
1810	Type     string `js:"type"`
1811}
1812
1813func (e *HTMLAnchorElement) Rel() *TokenList {
1814	return &TokenList{dtl: e.Get("relList"), o: e.Object, sa: "rel"}
1815}
1816
1817type HTMLAppletElement struct {
1818	*BasicHTMLElement
1819	Alt      string `js:"alt"`
1820	Coords   string `js:"coords"`
1821	HrefLang string `js:"hreflang"`
1822	Media    string `js:"media"`
1823	Search   string `js:"search"`
1824	Shape    string `js:"shape"`
1825	TabIndex int    `js:"tabIndex"`
1826	Target   string `js:"target"`
1827	Type     string `js:"type"`
1828}
1829
1830func (e *HTMLAppletElement) Rel() *TokenList {
1831	return &TokenList{dtl: e.Get("relList"), o: e.Object, sa: "rel"}
1832}
1833
1834type HTMLAreaElement struct {
1835	*BasicHTMLElement
1836	*URLUtils
1837	Alt      string `js:"alt"`
1838	Coords   string `js:"coords"`
1839	HrefLang string `js:"hreflang"`
1840	Media    string `js:"media"`
1841	Search   string `js:"search"`
1842	Shape    string `js:"shape"`
1843	TabIndex int    `js:"tabIndex"`
1844	Target   string `js:"target"`
1845	Type     string `js:"type"`
1846}
1847
1848func (e *HTMLAreaElement) Rel() *TokenList {
1849	return &TokenList{dtl: e.Get("relList"), o: e.Object, sa: "rel"}
1850}
1851
1852type HTMLAudioElement struct{ *HTMLMediaElement }
1853
1854type HTMLBRElement struct{ *BasicHTMLElement }
1855
1856type HTMLBaseElement struct{ *BasicHTMLElement }
1857
1858func (e *HTMLBaseElement) Href() string {
1859	return e.Get("href").String()
1860}
1861
1862func (e *HTMLBaseElement) Target() string {
1863	return e.Get("target").String()
1864}
1865
1866type HTMLBodyElement struct{ *BasicHTMLElement }
1867
1868type HTMLButtonElement struct {
1869	*BasicHTMLElement
1870	AutoFocus         bool   `js:"autofocus"`
1871	Disabled          bool   `js:"disabled"`
1872	FormAction        string `js:"formAction"`
1873	FormEncType       string `js:"formEncType"`
1874	FormMethod        string `js:"formMethod"`
1875	FormNoValidate    bool   `js:"formNoValidate"`
1876	FormTarget        string `js:"formTarget"`
1877	Name              string `js:"name"`
1878	TabIndex          int    `js:"tabIndex"`
1879	Type              string `js:"type"`
1880	ValidationMessage string `js:"validationMessage"`
1881	Value             string `js:"value"`
1882	WillValidate      bool   `js:"willValidate"`
1883}
1884
1885func (e *HTMLButtonElement) Form() *HTMLFormElement {
1886	return getForm(e.Object)
1887}
1888
1889func (e *HTMLButtonElement) Labels() []*HTMLLabelElement {
1890	return getLabels(e.Object)
1891}
1892
1893func (e *HTMLButtonElement) Validity() *ValidityState {
1894	// TODO replace with a field once GopherJS supports that
1895	return &ValidityState{Object: e.Get("validity")}
1896}
1897
1898func (e *HTMLButtonElement) CheckValidity() bool {
1899	return e.Call("checkValidity").Bool()
1900}
1901
1902func (e *HTMLButtonElement) SetCustomValidity(s string) {
1903	e.Call("setCustomValidity", s)
1904}
1905
1906type HTMLCanvasElement struct {
1907	*BasicHTMLElement
1908	Height int `js:"height"`
1909	Width  int `js:"width"`
1910}
1911
1912type CanvasRenderingContext2D struct {
1913	*js.Object
1914
1915	// Colors, Styles, and Shadows
1916
1917	FillStyle     string `js:"fillStyle"`
1918	StrokeStyle   string `js:"strokeStyle"`
1919	ShadowColor   string `js:"shadowColor"`
1920	ShadowBlur    int    `js:"shadowBlur"`
1921	ShadowOffsetX int    `js:"shadowOffsetX"`
1922	ShadowOffsetY int    `js:"shadowOffsetY"`
1923
1924	// Line Styles
1925
1926	LineCap    string `js:"lineCap"`
1927	LineJoin   string `js:"lineJoin"`
1928	LineWidth  int    `js:"lineWidth"`
1929	MiterLimit int    `js:"miterLimit"`
1930
1931	// Text
1932
1933	Font         string `js:"font"`
1934	TextAlign    string `js:"textAlign"`
1935	TextBaseline string `js:"textBaseline"`
1936
1937	// Compositing
1938
1939	GlobalAlpha              float64 `js:"globalAlpha"`
1940	GlobalCompositeOperation string  `js:"globalCompositeOperation"`
1941}
1942
1943type ImageData struct {
1944	*js.Object
1945
1946	Width  int        `js:"width"`
1947	Height int        `js:"height"`
1948	Data   *js.Object `js:"data"`
1949}
1950
1951func (m *ImageData) ColorModel() color.Model { return color.NRGBAModel }
1952
1953func (m *ImageData) Bounds() image.Rectangle {
1954	return image.Rect(0, 0, m.Width, m.Height)
1955}
1956
1957func (m *ImageData) At(x, y int) color.Color {
1958	return m.NRGBAAt(x, y)
1959}
1960
1961func (m *ImageData) NRGBAAt(x, y int) color.NRGBA {
1962	if x < 0 || x >= m.Width ||
1963		y < 0 || y >= m.Height {
1964		return color.NRGBA{}
1965	}
1966	i := (y*m.Width + x) * 4
1967	return color.NRGBA{
1968		R: uint8(m.Data.Index(i + 0).Int()),
1969		G: uint8(m.Data.Index(i + 1).Int()),
1970		B: uint8(m.Data.Index(i + 2).Int()),
1971		A: uint8(m.Data.Index(i + 3).Int()),
1972	}
1973}
1974
1975func (m *ImageData) Set(x, y int, c color.Color) {
1976	if x < 0 || x >= m.Width ||
1977		y < 0 || y >= m.Height {
1978		return
1979	}
1980	c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
1981	i := (y*m.Width + x) * 4
1982	m.Data.SetIndex(i+0, c1.R)
1983	m.Data.SetIndex(i+1, c1.G)
1984	m.Data.SetIndex(i+2, c1.B)
1985	m.Data.SetIndex(i+3, c1.A)
1986}
1987
1988func (m *ImageData) SetNRGBA(x, y int, c color.NRGBA) {
1989	if x < 0 || x >= m.Width ||
1990		y < 0 || y >= m.Height {
1991		return
1992	}
1993	i := (y*m.Width + x) * 4
1994	m.Data.SetIndex(i+0, c.R)
1995	m.Data.SetIndex(i+1, c.G)
1996	m.Data.SetIndex(i+2, c.B)
1997	m.Data.SetIndex(i+3, c.A)
1998}
1999
2000// CanvasGradient represents an opaque object describing a gradient.
2001// It is returned by the methods CanvasRenderingContext2D.CreateLinearGradient
2002// or CanvasRenderingContext2D.CreateRadialGradient.
2003//
2004// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient.
2005type CanvasGradient struct {
2006	*js.Object
2007}
2008
2009// AddColorStop adds a new stop, defined by an offset and a color, to the gradient.
2010// It panics with *js.Error if the offset is not between 0 and 1, or if the color
2011// can't be parsed as a CSS <color>.
2012//
2013// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient/addColorStop.
2014func (cg *CanvasGradient) AddColorStop(offset float64, color string) {
2015	cg.Call("addColorStop", offset, color)
2016}
2017
2018// CanvasPattern represents an opaque object describing a pattern.
2019// It is based on an image, a canvas or a video, created by the
2020// CanvasRenderingContext2D.CreatePattern method.
2021//
2022// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern.
2023type CanvasPattern struct {
2024	*js.Object
2025}
2026
2027type TextMetrics struct {
2028	*js.Object
2029
2030	Width                    float64 `js:"width"`
2031	ActualBoundingBoxLeft    float64 `js:"actualBoundingBoxLeft"`
2032	ActualBoundingBoxRight   float64 `js:"actualBoundingBoxRight"`
2033	FontBoundingBoxAscent    float64 `js:"fontBoundingBoxAscent"`
2034	FontBoundingBoxDescent   float64 `js:"fontBoundingBoxDescent"`
2035	ActualBoundingBoxAscent  float64 `js:"actualBoundingBoxAscent"`
2036	ActualBoundingBoxDescent float64 `js:"actualBoundingBoxDescent"`
2037	EmHeightAscent           float64 `js:"emHeightAscent"`
2038	EmHeightDescent          float64 `js:"emHeightDescent"`
2039	HangingBaseline          float64 `js:"hangingBaseline"`
2040	AlphabeticBaseline       float64 `js:"alphabeticBaseline"`
2041	IdeographicBaseline      float64 `js:"ideographicBaseline"`
2042}
2043
2044// Creating canvas 2d context
2045
2046func (e *HTMLCanvasElement) GetContext2d() *CanvasRenderingContext2D {
2047	ctx := e.GetContext("2d")
2048	return &CanvasRenderingContext2D{Object: ctx}
2049}
2050
2051func (e *HTMLCanvasElement) GetContext(param string) *js.Object {
2052	return e.Call("getContext", param)
2053}
2054
2055// Drawing Rectangles
2056
2057func (ctx *CanvasRenderingContext2D) ClearRect(x, y, width, height float64) {
2058	ctx.Call("clearRect", x, y, width, height)
2059}
2060
2061func (ctx *CanvasRenderingContext2D) FillRect(x, y, width, height float64) {
2062	ctx.Call("fillRect", x, y, width, height)
2063}
2064
2065func (ctx *CanvasRenderingContext2D) StrokeRect(x, y, width, height float64) {
2066	ctx.Call("strokeRect", x, y, width, height)
2067}
2068
2069// Drawing Text
2070
2071// FillText fills a given text at the given (x, y) position.
2072// If the optional maxWidth parameter is not -1,
2073// the text will be scaled to fit that width.
2074func (ctx *CanvasRenderingContext2D) FillText(text string, x, y, maxWidth float64) {
2075	if maxWidth == -1 {
2076		ctx.Call("fillText", text, x, y)
2077		return
2078	}
2079
2080	ctx.Call("fillText", text, x, y, maxWidth)
2081}
2082
2083// StrokeText strokes a given text at the given (x, y) position.
2084// If the optional maxWidth parameter is not -1,
2085// the text will be scaled to fit that width.
2086func (ctx *CanvasRenderingContext2D) StrokeText(text string, x, y, maxWidth float64) {
2087	if maxWidth == -1 {
2088		ctx.Call("strokeText", text, x, y)
2089		return
2090	}
2091
2092	ctx.Call("strokeText", text, x, y, maxWidth)
2093}
2094func (ctx *CanvasRenderingContext2D) MeasureText(text string) *TextMetrics {
2095	textMetrics := ctx.Call("measureText", text)
2096	return &TextMetrics{Object: textMetrics}
2097}
2098
2099// Line styles
2100
2101func (ctx *CanvasRenderingContext2D) GetLineDash() []float64 {
2102	var dashes []float64
2103	for _, dash := range ctx.Call("getLineDash").Interface().([]interface{}) {
2104		dashes = append(dashes, dash.(float64))
2105	}
2106	return dashes
2107}
2108
2109func (ctx *CanvasRenderingContext2D) SetLineDash(dashes []float64) {
2110	ctx.Call("setLineDash", dashes)
2111}
2112
2113// Gradients and patterns
2114
2115// CreateLinearGradient creates a linear gradient along the line given
2116// by the coordinates represented by the parameters.
2117//
2118// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createLinearGradient.
2119func (ctx *CanvasRenderingContext2D) CreateLinearGradient(x0, y0, x1, y1 float64) *CanvasGradient {
2120	return &CanvasGradient{Object: ctx.Call("createLinearGradient", x0, y0, x1, y1)}
2121}
2122
2123// CreateRadialGradient creates a radial gradient given by the coordinates of the two circles
2124// represented by the parameters.
2125//
2126// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient.
2127func (ctx *CanvasRenderingContext2D) CreateRadialGradient(x0, y0, r0, x1, y1, r1 float64) *CanvasGradient {
2128	return &CanvasGradient{Object: ctx.Call("createRadialGradient", x0, y0, r0, x1, y1, r1)}
2129}
2130
2131// CreatePattern creates a pattern using the specified image (a CanvasImageSource).
2132// It repeats the source in the directions specified by the repetition argument.
2133//
2134// Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern.
2135func (ctx *CanvasRenderingContext2D) CreatePattern(image Element, repetition string) *CanvasPattern {
2136	return &CanvasPattern{Object: ctx.Call("createPattern", image, repetition)}
2137}
2138
2139// Paths
2140
2141func (ctx *CanvasRenderingContext2D) BeginPath() {
2142	ctx.Call("beginPath")
2143}
2144
2145func (ctx *CanvasRenderingContext2D) ClosePath() {
2146	ctx.Call("closePath")
2147}
2148
2149func (ctx *CanvasRenderingContext2D) MoveTo(x, y float64) {
2150	ctx.Call("moveTo", x, y)
2151}
2152
2153func (ctx *CanvasRenderingContext2D) LineTo(x, y float64) {
2154	ctx.Call("lineTo", x, y)
2155}
2156
2157func (ctx *CanvasRenderingContext2D) BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y float64) {
2158	ctx.Call("bezierCurveTo", cp1x, cp1y, cp2x, cp2y, x, y)
2159}
2160
2161func (ctx *CanvasRenderingContext2D) QuadraticCurveTo(cpx, cpy, x, y float64) {
2162	ctx.Call("quadraticCurveTo", cpx, cpy, x, y)
2163}
2164
2165func (ctx *CanvasRenderingContext2D) Arc(x, y, r, sAngle, eAngle float64, counterclockwise bool) {
2166	ctx.Call("arc", x, y, r, sAngle, eAngle, counterclockwise)
2167}
2168
2169func (ctx *CanvasRenderingContext2D) ArcTo(x1, y1, x2, y2, r float64) {
2170	ctx.Call("arcTo", x1, y1, x2, y2, r)
2171}
2172
2173func (ctx *CanvasRenderingContext2D) Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64, anticlockwise bool) {
2174	ctx.Call("ellipse", x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
2175}
2176
2177func (ctx *CanvasRenderingContext2D) Rect(x, y, width, height float64) {
2178	ctx.Call("rect", x, y, width, height)
2179}
2180
2181// Drawing paths
2182
2183func (ctx *CanvasRenderingContext2D) Fill() {
2184	ctx.Call("fill")
2185}
2186
2187func (ctx *CanvasRenderingContext2D) Stroke() {
2188	ctx.Call("stroke")
2189}
2190
2191func (ctx *CanvasRenderingContext2D) DrawFocusIfNeeded(element HTMLElement, path *js.Object) {
2192	ctx.Call("drawFocusIfNeeded", element, path)
2193}
2194
2195func (ctx *CanvasRenderingContext2D) ScrollPathIntoView(path *js.Object) {
2196	ctx.Call("scrollPathIntoView", path)
2197}
2198
2199func (ctx *CanvasRenderingContext2D) Clip() {
2200	ctx.Call("clip")
2201}
2202
2203func (ctx *CanvasRenderingContext2D) IsPointInPath(x, y float64) bool {
2204	return ctx.Call("isPointInPath", x, y).Bool()
2205}
2206
2207func (ctx *CanvasRenderingContext2D) IsPointInStroke(path *js.Object, x, y float64) bool {
2208	return ctx.Call("isPointInStroke", path, x, y).Bool()
2209}
2210
2211// Transformations
2212
2213func (ctx *CanvasRenderingContext2D) Rotate(angle float64) {
2214	ctx.Call("rotate", angle)
2215}
2216
2217func (ctx *CanvasRenderingContext2D) Scale(scaleWidth, scaleHeight float64) {
2218	ctx.Call("scale", scaleWidth, scaleHeight)
2219}
2220
2221func (ctx *CanvasRenderingContext2D) Translate(x, y float64) {
2222	ctx.Call("translate", x, y)
2223}
2224
2225func (ctx *CanvasRenderingContext2D) Transform(a, b, c, d, e, f float64) {
2226	ctx.Call("transform", a, b, c, d, e, f)
2227}
2228
2229func (ctx *CanvasRenderingContext2D) SetTransform(a, b, c, d, e, f float64) {
2230	ctx.Call("setTransform", a, b, c, d, e, f)
2231}
2232
2233func (ctx *CanvasRenderingContext2D) ResetTransform() {
2234	ctx.Call("resetTransform")
2235}
2236
2237// Drawing images
2238
2239func (ctx *CanvasRenderingContext2D) DrawImage(image Element, dx, dy float64) {
2240	ctx.Call("drawImage", image, dx, dy)
2241}
2242
2243func (ctx *CanvasRenderingContext2D) DrawImageWithDst(image Element, dx, dy, dWidth, dHeight float64) {
2244	ctx.Call("drawImage", image, dx, dy, dWidth, dHeight)
2245}
2246
2247func (ctx *CanvasRenderingContext2D) DrawImageWithSrcAndDst(image Element, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight float64) {
2248	ctx.Call("drawImage", image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
2249}
2250
2251// Pixel manipulation
2252
2253func (ctx *CanvasRenderingContext2D) CreateImageData(width, height int) *ImageData {
2254	return &ImageData{Object: ctx.Call("createImageData", width, height)}
2255}
2256
2257func (ctx *CanvasRenderingContext2D) GetImageData(sx, sy, sw, sh int) *ImageData {
2258	return &ImageData{Object: ctx.Call("getImageData", sx, sy, sw, sh)}
2259}
2260
2261func (ctx *CanvasRenderingContext2D) PutImageData(imageData *ImageData, dx, dy float64) {
2262	ctx.Call("putImageData", imageData, dx, dy)
2263}
2264
2265func (ctx *CanvasRenderingContext2D) PutImageDataDirty(imageData *ImageData, dx, dy float64, dirtyX, dirtyY, dirtyWidth, dirtyHeight int) {
2266	ctx.Call("putImageData", imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
2267}
2268
2269// State
2270
2271func (ctx *CanvasRenderingContext2D) Save() {
2272	ctx.Call("save")
2273}
2274
2275func (ctx *CanvasRenderingContext2D) Restore() {
2276	ctx.Call("restore")
2277}
2278
2279// TODO Hit regions:
2280// addHitRegion
2281// removeHitRegion
2282// clearHitRegions
2283
2284type HTMLDListElement struct{ *BasicHTMLElement }
2285
2286type HTMLDataElement struct {
2287	*BasicHTMLElement
2288	Value string `js:"value"`
2289}
2290
2291type HTMLDataListElement struct{ *BasicHTMLElement }
2292
2293func (e *HTMLDataListElement) Options() []*HTMLOptionElement {
2294	return getOptions(e.Object, "options")
2295}
2296
2297type HTMLDirectoryElement struct{ *BasicHTMLElement }
2298type HTMLDivElement struct{ *BasicHTMLElement }
2299
2300type HTMLEmbedElement struct {
2301	*BasicHTMLElement
2302	Src   string `js:"src"`
2303	Type  string `js:"type"`
2304	Width string `js:"width"`
2305}
2306
2307type HTMLFieldSetElement struct {
2308	*BasicHTMLElement
2309	Disabled          bool   `js:"disabled"`
2310	Name              string `js:"name"`
2311	Type              string `js:"type"`
2312	ValidationMessage string `js:"validationMessage"`
2313	WillValidate      bool   `js:"willValidate"`
2314}
2315
2316func (e *HTMLFieldSetElement) Elements() []HTMLElement {
2317	return nodeListToHTMLElements(e.Get("elements"))
2318}
2319
2320func (e *HTMLFieldSetElement) Form() *HTMLFormElement {
2321	return getForm(e.Object)
2322}
2323
2324func (e *HTMLFieldSetElement) Validity() *ValidityState {
2325	// TODO replace with a field once GopherJS supports that
2326	return &ValidityState{Object: e.Get("validity")}
2327}
2328
2329func (e *HTMLFieldSetElement) CheckValidity() bool {
2330	return e.Call("checkValidity").Bool()
2331}
2332
2333func (e *HTMLFieldSetElement) SetCustomValidity(s string) {
2334	e.Call("setCustomValidity", s)
2335}
2336
2337type HTMLFontElement struct{ *BasicHTMLElement }
2338
2339type HTMLFormElement struct {
2340	*BasicHTMLElement
2341	AcceptCharset string `js:"acceptCharset"`
2342	Action        string `js:"action"`
2343	Autocomplete  string `js:"autocomplete"`
2344	Encoding      string `js:"encoding"`
2345	Enctype       string `js:"enctype"`
2346	Length        int    `js:"length"`
2347	Method        string `js:"method"`
2348	Name          string `js:"name"`
2349	NoValidate    bool   `js:"noValidate"`
2350	Target        string `js:"target"`
2351}
2352
2353func (e *HTMLFormElement) Elements() []HTMLElement {
2354	return nodeListToHTMLElements(e.Get("elements"))
2355}
2356
2357func (e *HTMLFormElement) CheckValidity() bool {
2358	return e.Call("checkValidity").Bool()
2359}
2360
2361func (e *HTMLFormElement) Submit() {
2362	e.Call("submit")
2363}
2364
2365func (e *HTMLFormElement) Reset() {
2366	e.Call("reset")
2367}
2368
2369func (e *HTMLFormElement) Item(index int) HTMLElement {
2370	return wrapHTMLElement(e.Call("item", index))
2371}
2372
2373func (e *HTMLFormElement) NamedItem(name string) HTMLElement {
2374	return wrapHTMLElement(e.Call("namedItem", name))
2375}
2376
2377type HTMLFrameElement struct{ *BasicHTMLElement }
2378type HTMLFrameSetElement struct{ *BasicHTMLElement }
2379type HTMLHRElement struct{ *BasicHTMLElement }
2380type HTMLHeadElement struct{ *BasicHTMLElement }
2381type HTMLHeadingElement struct{ *BasicHTMLElement }
2382type HTMLHtmlElement struct{ *BasicHTMLElement }
2383
2384type HTMLIFrameElement struct {
2385	*BasicHTMLElement
2386	Width    string `js:"width"`
2387	Height   string `js:"height"`
2388	Name     string `js:"name"`
2389	Src      string `js:"src"`
2390	SrcDoc   string `js:"srcdoc"`
2391	Seamless bool   `js:"seamless"`
2392	// TODO sandbox attribute
2393}
2394
2395func (e *HTMLIFrameElement) ContentDocument() Document {
2396	return wrapDocument(e.Get("contentDocument"))
2397}
2398
2399func (e *HTMLIFrameElement) ContentWindow() Window {
2400	return &window{e.Get("contentWindow")}
2401}
2402
2403type HTMLImageElement struct {
2404	*BasicHTMLElement
2405	Complete      bool   `js:"complete"`
2406	CrossOrigin   string `js:"crossOrigin"`
2407	Height        int    `js:"height"`
2408	IsMap         bool   `js:"isMap"`
2409	NaturalHeight int    `js:"naturalHeight"`
2410	NaturalWidth  int    `js:"naturalWidth"`
2411	Src           string `js:"src"`
2412	UseMap        string `js:"useMap"`
2413	Width         int    `js:"width"`
2414	// TODO constructor
2415}
2416
2417type HTMLInputElement struct {
2418	*BasicHTMLElement
2419	Accept             string    `js:"accept"`
2420	Alt                string    `js:"alt"`
2421	Autocomplete       string    `js:"autocomplete"`
2422	Autofocus          bool      `js:"autofocus"`
2423	Checked            bool      `js:"checked"`
2424	DefaultChecked     bool      `js:"defaultChecked"`
2425	DefaultValue       string    `js:"defaultValue"`
2426	DirName            string    `js:"dirName"`
2427	Disabled           bool      `js:"disabled"`
2428	FormAction         string    `js:"formAction"`
2429	FormEncType        string    `js:"formEncType"`
2430	FormMethod         string    `js:"formMethod"`
2431	FormNoValidate     bool      `js:"formNoValidate"`
2432	FormTarget         string    `js:"formTarget"`
2433	Height             string    `js:"height"`
2434	Indeterminate      bool      `js:"indeterminate"`
2435	Max                string    `js:"max"`
2436	MaxLength          int       `js:"maxLength"`
2437	Min                string    `js:"min"`
2438	Multiple           bool      `js:"multiple"`
2439	Name               string    `js:"name"`
2440	Pattern            string    `js:"pattern"`
2441	Placeholder        string    `js:"placeholder"`
2442	ReadOnly           bool      `js:"readOnly"`
2443	Required           bool      `js:"required"`
2444	SelectionDirection string    `js:"selectionDirection"`
2445	SelectionEnd       int       `js:"selectionEnd"`
2446	SelectionStart     int       `js:"selectionStart"`
2447	Size               int       `js:"size"`
2448	Src                string    `js:"src"`
2449	Step               string    `js:"step"`
2450	TabIndex           int       `js:"tabIndex"`
2451	Type               string    `js:"type"`
2452	ValidationMessage  string    `js:"validationMessage"`
2453	Value              string    `js:"value"`
2454	ValueAsDate        time.Time `js:"valueAsDate"`
2455	ValueAsNumber      float64   `js:"valueAsNumber"`
2456	Width              string    `js:"width"`
2457	WillValidate       bool      `js:"willValidate"`
2458}
2459
2460// File represents files as can be obtained from file choosers or drag
2461// and drop. The dom package does not define any methods on File nor
2462// does it provide access to the blob or a way to read it.
2463type File struct {
2464	*js.Object
2465}
2466
2467func (e *HTMLInputElement) Files() []*File {
2468	files := e.Get("files")
2469	out := make([]*File, files.Get("length").Int())
2470	for i := range out {
2471		out[i] = &File{files.Call("item", i)}
2472	}
2473	return out
2474}
2475
2476func (e *HTMLInputElement) List() *HTMLDataListElement {
2477	list := wrapHTMLElement(e.Get("list"))
2478	if list == nil {
2479		return nil
2480	}
2481	return list.(*HTMLDataListElement)
2482}
2483
2484func (e *HTMLInputElement) Labels() []*HTMLLabelElement {
2485	return getLabels(e.Object)
2486}
2487
2488func (e *HTMLInputElement) Form() *HTMLFormElement {
2489	return getForm(e.Object)
2490}
2491
2492func (e *HTMLInputElement) Validity() *ValidityState {
2493	// TODO replace with a field once GopherJS supports that
2494	return &ValidityState{Object: e.Get("validity")}
2495}
2496
2497func (e *HTMLInputElement) CheckValidity() bool {
2498	return e.Call("checkValidity").Bool()
2499}
2500
2501func (e *HTMLInputElement) SetCustomValidity(s string) {
2502	e.Call("setCustomValidity", s)
2503}
2504
2505func (e *HTMLInputElement) Select() {
2506	e.Call("select")
2507}
2508
2509func (e *HTMLInputElement) SetSelectionRange(start, end int, direction string) {
2510	e.Call("setSelectionRange", start, end, direction)
2511}
2512
2513func (e *HTMLInputElement) StepDown(n int) error {
2514	return callRecover(e.Object, "stepDown", n)
2515}
2516
2517func (e *HTMLInputElement) StepUp(n int) error {
2518	return callRecover(e.Object, "stepUp", n)
2519}
2520
2521type HTMLKeygenElement struct {
2522	*BasicHTMLElement
2523	Autofocus         bool   `js:"autofocus"`
2524	Challenge         string `js:"challenge"`
2525	Disabled          bool   `js:"disabled"`
2526	Keytype           string `js:"keytype"`
2527	Name              string `js:"name"`
2528	Type              string `js:"type"`
2529	ValidationMessage string `js:"validationMessage"`
2530	WillValidate      bool   `js:"willValidate"`
2531}
2532
2533func (e *HTMLKeygenElement) Form() *HTMLFormElement {
2534	return getForm(e.Object)
2535}
2536
2537func (e *HTMLKeygenElement) Labels() []*HTMLLabelElement {
2538	return getLabels(e.Object)
2539}
2540
2541func (e *HTMLKeygenElement) Validity() *ValidityState {
2542	// TODO replace with a field once GopherJS supports that
2543	return &ValidityState{Object: e.Get("validity")}
2544}
2545
2546func (e *HTMLKeygenElement) CheckValidity() bool {
2547	return e.Call("checkValidity").Bool()
2548}
2549
2550func (e *HTMLKeygenElement) SetCustomValidity(s string) {
2551	e.Call("setCustomValidity", s)
2552}
2553
2554type HTMLLIElement struct {
2555	*BasicHTMLElement
2556	Value int `js:"value"`
2557}
2558
2559type HTMLLabelElement struct {
2560	*BasicHTMLElement
2561	For string `js:"htmlFor"`
2562}
2563
2564func (e *HTMLLabelElement) Control() HTMLElement {
2565	return wrapHTMLElement(e.Get("control"))
2566}
2567
2568func (e *HTMLLabelElement) Form() *HTMLFormElement {
2569	return getForm(e.Object)
2570}
2571
2572type HTMLLegendElement struct{ *BasicHTMLElement }
2573
2574func (e *HTMLLegendElement) Form() *HTMLFormElement {
2575	return getForm(e.Object)
2576}
2577
2578type HTMLLinkElement struct {
2579	*BasicHTMLElement
2580	Disabled bool   `js:"disabled"`
2581	Href     string `js:"href"`
2582	HrefLang string `js:"hrefLang"`
2583	Media    string `js:"media"`
2584	Type     string `js:"type"`
2585}
2586
2587func (e *HTMLLinkElement) Rel() *TokenList {
2588	return &TokenList{dtl: e.Get("relList"), o: e.Object, sa: "rel"}
2589}
2590
2591func (e *HTMLLinkElement) Sizes() *TokenList {
2592	return &TokenList{dtl: e.Get("sizes"), o: e.Object}
2593}
2594
2595func (e *HTMLLinkElement) Sheet() StyleSheet {
2596	// FIXME implement
2597	panic("not implemented")
2598}
2599
2600type HTMLMapElement struct {
2601	*BasicHTMLElement
2602	Name string `js:"name"`
2603}
2604
2605func (e *HTMLMapElement) Areas() []*HTMLAreaElement {
2606	areas := nodeListToElements(e.Get("areas"))
2607	out := make([]*HTMLAreaElement, len(areas))
2608	for i, area := range areas {
2609		out[i] = area.(*HTMLAreaElement)
2610	}
2611	return out
2612}
2613
2614func (e *HTMLMapElement) Images() []HTMLElement {
2615	return nodeListToHTMLElements(e.Get("areas"))
2616}
2617
2618type HTMLMediaElement struct {
2619	*BasicHTMLElement
2620	Paused bool `js:"paused"`
2621}
2622
2623func (e *HTMLMediaElement) Play() {
2624	e.Call("play")
2625}
2626
2627func (e *HTMLMediaElement) Pause() {
2628	e.Call("pause")
2629}
2630
2631type HTMLMenuElement struct{ *BasicHTMLElement }
2632
2633type HTMLMetaElement struct {
2634	*BasicHTMLElement
2635	Content   string `js:"content"`
2636	HTTPEquiv string `js:"httpEquiv"`
2637	Name      string `js:"name"`
2638}
2639
2640type HTMLMeterElement struct {
2641	*BasicHTMLElement
2642	High    float64 `js:"high"`
2643	Low     float64 `js:"low"`
2644	Max     float64 `js:"max"`
2645	Min     float64 `js:"min"`
2646	Optimum float64 `js:"optimum"`
2647}
2648
2649func (e HTMLMeterElement) Labels() []*HTMLLabelElement {
2650	return getLabels(e.Object)
2651}
2652
2653type HTMLModElement struct {
2654	*BasicHTMLElement
2655	Cite     string `js:"cite"`
2656	DateTime string `js:"dateTime"`
2657}
2658
2659type HTMLOListElement struct {
2660	*BasicHTMLElement
2661	Reversed bool   `js:"reversed"`
2662	Start    int    `js:"start"`
2663	Type     string `js:"type"`
2664}
2665
2666type HTMLObjectElement struct {
2667	*BasicHTMLElement
2668	Data              string `js:"data"`
2669	Height            string `js:"height"`
2670	Name              string `js:"name"`
2671	TabIndex          int    `js:"tabIndex"`
2672	Type              string `js:"type"`
2673	TypeMustMatch     bool   `js:"typeMustMatch"`
2674	UseMap            string `js:"useMap"`
2675	ValidationMessage string `js:"validationMessage"`
2676	With              string `js:"with"`
2677	WillValidate      bool   `js:"willValidate"`
2678}
2679
2680func (e *HTMLObjectElement) Form() *HTMLFormElement {
2681	return getForm(e.Object)
2682}
2683
2684func (e *HTMLObjectElement) ContentDocument() Document {
2685	return wrapDocument(e.Get("contentDocument"))
2686}
2687
2688func (e *HTMLObjectElement) ContentWindow() Window {
2689	return &window{e.Get("contentWindow")}
2690}
2691
2692func (e *HTMLObjectElement) Validity() *ValidityState {
2693	// TODO replace with a field once GopherJS supports that
2694	return &ValidityState{Object: e.Get("validity")}
2695}
2696
2697func (e *HTMLObjectElement) CheckValidity() bool {
2698	return e.Call("checkValidity").Bool()
2699}
2700
2701func (e *HTMLObjectElement) SetCustomValidity(s string) {
2702	e.Call("setCustomValidity", s)
2703}
2704
2705type HTMLOptGroupElement struct {
2706	*BasicHTMLElement
2707	Disabled bool   `js:"disabled"`
2708	Label    string `js:"label"`
2709}
2710
2711type HTMLOptionElement struct {
2712	*BasicHTMLElement
2713	DefaultSelected bool   `js:"defaultSelected"`
2714	Disabled        bool   `js:"disabled"`
2715	Index           int    `js:"index"`
2716	Label           string `js:"label"`
2717	Selected        bool   `js:"selected"`
2718	Text            string `js:"text"`
2719	Value           string `js:"value"`
2720}
2721
2722func (e *HTMLOptionElement) Form() *HTMLFormElement {
2723	return getForm(e.Object)
2724}
2725
2726type HTMLOutputElement struct {
2727	*BasicHTMLElement
2728	DefaultValue      string `js:"defaultValue"`
2729	Name              string `js:"name"`
2730	Type              string `js:"type"`
2731	ValidationMessage string `js:"validationMessage"`
2732	Value             string `js:"value"`
2733	WillValidate      bool   `js:"willValidate"`
2734}
2735
2736func (e *HTMLOutputElement) Form() *HTMLFormElement {
2737	return getForm(e.Object)
2738}
2739
2740func (e *HTMLOutputElement) Labels() []*HTMLLabelElement {
2741	return getLabels(e.Object)
2742}
2743
2744func (e *HTMLOutputElement) Validity() *ValidityState {
2745	// TODO replace with a field once GopherJS supports that
2746	return &ValidityState{Object: e.Get("validity")}
2747}
2748
2749func (e *HTMLOutputElement) For() *TokenList {
2750	return &TokenList{dtl: e.Get("htmlFor"), o: e.Object}
2751}
2752
2753func (e *HTMLOutputElement) CheckValidity() bool {
2754	return e.Call("checkValidity").Bool()
2755}
2756
2757func (e *HTMLOutputElement) SetCustomValidity(s string) {
2758	e.Call("setCustomValidity", s)
2759}
2760
2761type HTMLParagraphElement struct{ *BasicHTMLElement }
2762
2763type HTMLParamElement struct {
2764	*BasicHTMLElement
2765	Name  string `js:"name"`
2766	Value string `js:"value"`
2767}
2768
2769type HTMLPreElement struct{ *BasicHTMLElement }
2770
2771type HTMLProgressElement struct {
2772	*BasicHTMLElement
2773	Max      float64 `js:"max"`
2774	Position float64 `js:"position"`
2775	Value    float64 `js:"value"`
2776}
2777
2778func (e HTMLProgressElement) Labels() []*HTMLLabelElement {
2779	return getLabels(e.Object)
2780}
2781
2782type HTMLQuoteElement struct {
2783	*BasicHTMLElement
2784	Cite string `js:"cite"`
2785}
2786
2787type HTMLScriptElement struct {
2788	*BasicHTMLElement
2789	Type    string `js:"type"`
2790	Src     string `js:"src"`
2791	Charset string `js:"charset"`
2792	Async   bool   `js:"async"`
2793	Defer   bool   `js:"defer"`
2794	Text    string `js:"text"`
2795}
2796
2797type HTMLSelectElement struct {
2798	*BasicHTMLElement
2799	Autofocus         bool   `js:"autofocus"`
2800	Disabled          bool   `js:"disabled"`
2801	Length            int    `js:"length"`
2802	Multiple          bool   `js:"multiple"`
2803	Name              string `js:"name"`
2804	Required          bool   `js:"required"`
2805	SelectedIndex     int    `js:"selectedIndex"`
2806	Size              int    `js:"size"`
2807	Type              string `js:"type"`
2808	ValidationMessage string `js:"validationMessage"`
2809	Value             string `js:"value"`
2810	WillValidate      bool   `js:"willValidate"`
2811}
2812
2813func (e *HTMLSelectElement) Labels() []*HTMLLabelElement {
2814	return getLabels(e.Object)
2815}
2816
2817func (e *HTMLSelectElement) Form() *HTMLFormElement {
2818	return getForm(e.Object)
2819}
2820
2821func (e *HTMLSelectElement) Options() []*HTMLOptionElement {
2822	return getOptions(e.Object, "options")
2823}
2824
2825func (e *HTMLSelectElement) SelectedOptions() []*HTMLOptionElement {
2826	return getOptions(e.Object, "selectedOptions")
2827}
2828
2829func (e *HTMLSelectElement) Item(index int) *HTMLOptionElement {
2830	el := wrapHTMLElement(e.Call("item", index))
2831	if el == nil {
2832		return nil
2833	}
2834	return el.(*HTMLOptionElement)
2835}
2836
2837func (e *HTMLSelectElement) NamedItem(name string) *HTMLOptionElement {
2838	el := wrapHTMLElement(e.Call("namedItem", name))
2839	if el == nil {
2840		return nil
2841	}
2842	return el.(*HTMLOptionElement)
2843}
2844
2845// TODO(dominikh): Not implementing Add or Remove for now. For one,
2846// Add with "before" behaves weird when dealing with optgroups. Also,
2847// there's already InsertBefore and RemoveChild which can be used
2848// instead.
2849
2850func (e *HTMLSelectElement) Validity() *ValidityState {
2851	return &ValidityState{Object: e.Get("validity")}
2852}
2853
2854func (e *HTMLSelectElement) CheckValidity() bool {
2855	return e.Call("checkValidity").Bool()
2856}
2857
2858func (e *HTMLSelectElement) SetCustomValidity(s string) {
2859	e.Call("setCustomValidity", s)
2860}
2861
2862type HTMLSourceElement struct {
2863	*BasicHTMLElement
2864	Media string `js:"media"`
2865	Src   string `js:"src"`
2866	Type  string `js:"type"`
2867}
2868
2869type HTMLSpanElement struct{ *BasicHTMLElement }
2870type HTMLStyleElement struct{ *BasicHTMLElement }
2871type HTMLTableCaptionElement struct{ *BasicHTMLElement }
2872
2873type HTMLTableCellElement struct {
2874	*BasicHTMLElement
2875	ColSpan   int `js:"colSpan"`
2876	RowSpan   int `js:"rowSpan"`
2877	CellIndex int `js:"cellIndex"`
2878	// TODO headers
2879}
2880
2881type HTMLTableColElement struct {
2882	*BasicHTMLElement
2883	Span int `js:"span"`
2884}
2885
2886type HTMLTableDataCellElement struct{ *BasicHTMLElement }
2887type HTMLTableElement struct{ *BasicHTMLElement }
2888
2889type HTMLTableHeaderCellElement struct {
2890	*BasicHTMLElement
2891	Abbr  string `js:"abbr"`
2892	Scope string `js:"scope"`
2893}
2894
2895type HTMLTableRowElement struct {
2896	*BasicHTMLElement
2897	RowIndex        int `js:"rowIndex"`
2898	SectionRowIndex int `js:"sectionRowIndex"`
2899}
2900
2901func (e *HTMLTableRowElement) Cells() []*HTMLTableCellElement {
2902	cells := nodeListToElements(e.Get("cells"))
2903	out := make([]*HTMLTableCellElement, len(cells))
2904	for i, cell := range cells {
2905		out[i] = cell.(*HTMLTableCellElement)
2906	}
2907	return out
2908}
2909
2910func (e *HTMLTableRowElement) InsertCell(index int) *HTMLTableCellElement {
2911	return wrapHTMLElement(e.Call("insertCell", index)).(*HTMLTableCellElement)
2912}
2913
2914func (e *HTMLTableRowElement) DeleteCell(index int) {
2915	// FIXME exception handling/check that index is in bounds
2916	e.Call("deleteCell", index)
2917}
2918
2919type HTMLTableSectionElement struct{ *BasicHTMLElement }
2920
2921func (e *HTMLTableSectionElement) Rows() []*HTMLTableRowElement {
2922	rows := nodeListToElements(e.Get("rows"))
2923	out := make([]*HTMLTableRowElement, len(rows))
2924	for i, row := range rows {
2925		out[i] = row.(*HTMLTableRowElement)
2926	}
2927	return out
2928}
2929
2930func (e *HTMLTableSectionElement) DeleteRow(index int) {
2931	// FIXME exception handling/check that index is in bounds
2932	e.Call("deleteRow", index)
2933}
2934
2935func (e *HTMLTableSectionElement) InsertRow(index int) *HTMLTableRowElement {
2936	return wrapHTMLElement(e.Call("insertRow", index)).(*HTMLTableRowElement)
2937}
2938
2939type HTMLTextAreaElement struct {
2940	*BasicHTMLElement
2941	Autocomplete       string `js:"autocomplete"`
2942	Autofocus          bool   `js:"autofocus"`
2943	Cols               int    `js:"cols"`
2944	DefaultValue       string `js:"defaultValue"`
2945	DirName            string `js:"dirName"`
2946	Disabled           bool   `js:"disabled"`
2947	MaxLength          int    `js:"maxLength"`
2948	Name               string `js:"name"`
2949	Placeholder        string `js:"placeholder"`
2950	ReadOnly           bool   `js:"readOnly"`
2951	Required           bool   `js:"required"`
2952	Rows               int    `js:"rows"`
2953	SelectionDirection string `js:"selectionDirection"`
2954	SelectionStart     int    `js:"selectionStart"`
2955	SelectionEnd       int    `js:"selectionEnd"`
2956	TabIndex           int    `js:"tabIndex"`
2957	TextLength         int    `js:"textLength"`
2958	Type               string `js:"type"`
2959	ValidationMessage  string `js:"validationMessage"`
2960	Value              string `js:"value"`
2961	WillValidate       bool   `js:"willValidate"`
2962	Wrap               string `js:"wrap"`
2963}
2964
2965func (e *HTMLTextAreaElement) Form() *HTMLFormElement {
2966	return getForm(e.Object)
2967}
2968
2969func (e *HTMLTextAreaElement) Labels() []*HTMLLabelElement {
2970	return getLabels(e.Object)
2971}
2972
2973func (e *HTMLTextAreaElement) Validity() *ValidityState {
2974	// TODO replace with a field once GopherJS supports that
2975	return &ValidityState{Object: e.Get("validity")}
2976}
2977
2978func (e *HTMLTextAreaElement) CheckValidity() bool {
2979	return e.Call("checkValidity").Bool()
2980}
2981
2982func (e *HTMLTextAreaElement) SetCustomValidity(s string) {
2983	e.Call("setCustomValidity", s)
2984}
2985
2986func (e *HTMLTextAreaElement) Select() {
2987	e.Call("select")
2988}
2989
2990func (e *HTMLTextAreaElement) SetSelectionRange(start, end int, direction string) {
2991	e.Call("setSelectionRange", start, end, direction)
2992}
2993
2994type HTMLTimeElement struct {
2995	*BasicHTMLElement
2996	DateTime string `js:"dateTime"`
2997}
2998
2999type HTMLTitleElement struct {
3000	*BasicHTMLElement
3001	Text string `js:"text"`
3002}
3003
3004// TextTrack represents text track data for <track> elements. It does
3005// not currently provide any methods or attributes and it hasn't been
3006// decided yet whether they will be added to this package or a
3007// separate package.
3008type TextTrack struct{ *js.Object }
3009
3010type HTMLTrackElement struct {
3011	*BasicHTMLElement
3012	Kind       string `js:"kind"`
3013	Src        string `js:"src"`
3014	Srclang    string `js:"srclang"`
3015	Label      string `js:"label"`
3016	Default    bool   `js:"default"`
3017	ReadyState int    `js:"readyState"`
3018}
3019
3020func (e *HTMLTrackElement) Track() *TextTrack {
3021	return &TextTrack{e.Get("track")}
3022}
3023
3024type HTMLUListElement struct{ *BasicHTMLElement }
3025type HTMLUnknownElement struct{ *BasicHTMLElement }
3026
3027type HTMLVideoElement struct{ *HTMLMediaElement }
3028
3029type ValidityState struct {
3030	*js.Object
3031	CustomError     bool `js:"customError"`
3032	PatternMismatch bool `js:"patternMismatch"`
3033	RangeOverflow   bool `js:"rangeOverflow"`
3034	RangeUnderflow  bool `js:"rangeUnderflow"`
3035	StepMismatch    bool `js:"stepMismatch"`
3036	TooLong         bool `js:"tooLong"`
3037	TypeMismatch    bool `js:"typeMismatch"`
3038	Valid           bool `js:"valid"`
3039	ValueMissing    bool `js:"valueMissing"`
3040}
3041
3042type CSSStyleDeclaration struct{ *js.Object }
3043
3044func (css *CSSStyleDeclaration) ToMap() map[string]string {
3045	m := make(map[string]string)
3046	N := css.Get("length").Int()
3047	for i := 0; i < N; i++ {
3048		name := css.Call("item", i).String()
3049		value := css.Call("getPropertyValue", name).String()
3050		m[name] = value
3051	}
3052
3053	return m
3054}
3055
3056func (css *CSSStyleDeclaration) RemoveProperty(name string) {
3057	css.Call("removeProperty", name)
3058}
3059
3060func (css *CSSStyleDeclaration) GetPropertyValue(name string) string {
3061	return toString(css.Call("getPropertyValue", name))
3062}
3063
3064func (css *CSSStyleDeclaration) GetPropertyPriority(name string) string {
3065	return toString(css.Call("getPropertyPriority", name))
3066}
3067
3068func (css *CSSStyleDeclaration) SetProperty(name, value, priority string) {
3069	css.Call("setProperty", name, value, priority)
3070}
3071
3072func (css *CSSStyleDeclaration) Index(idx int) string {
3073	return css.Call("index", idx).String()
3074}
3075
3076func (css *CSSStyleDeclaration) Length() int {
3077	return css.Get("length").Int()
3078}
3079
3080type Text struct {
3081	*BasicNode
3082}
3083