Coder Social home page Coder Social logo

go-js-dom's People

Contributors

arvitaly avatar dmitshur avatar dominikh avatar inchingforward avatar influx6 avatar inkeliz avatar inliquid avatar josedonizetti avatar luckcolors avatar neelance avatar orrche avatar siongui avatar slon avatar taruti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-js-dom's Issues

Consider adding a Bytes []byte method to File (or documenting an example of how it can be achieved).

Currently, we have:

go-js-dom/dom.go

Lines 2460 to 2465 in 662b7b8

// File represents files as can be obtained from file choosers or drag
// and drop. The dom package does not define any methods on File nor
// does it provide access to the blob or a way to read it.
type File struct {
*js.Object
}

It might be helpful and worth considering changing it to have a Bytes() []byte method:

// File represents files as can be obtained from file choosers or drag
// and drop.
//
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/File.
type File struct { 
	*js.Object 
}

// Bytes reads the file f and returns its contents as a []byte.
func (f *File) Bytes() []byte {
	b := make(chan []byte)
	fr := js.Global.Get("FileReader").New()
	fr.Set("onload", func() {
		b <- js.Global.Get("Uint8Array").New(fr.Get("result")).Interface().([]byte)
	})
	fr.Call("readAsArrayBuffer", f.Object)
	return <-b
}

(Extracted from gopherjs/gopherjs#776 and #32. /cc @inkeliz)

WheelEvent inherits MouseEvent

Problem:
I am implementing "Mac trackpad" pan and zoom. Mac the way to tell the difference between a pan or zoom is to check ctrlKey or metaKey on the WheelEvent. Furthermore - for a zoom, I need to know the offsetX and offsetY to calculate the exact point to zoom about. Even though I should, I am not able to accomplish that with this library. The MDN docs suggest that a WheelEvent is a MouseEvent.

Suggested Solution:
Simply embed MouseEvent in WheelEvent - I think this solves all my problems.

type WheelEvent struct {
    *MouseEvent
    DeltaX    float64 `js:"deltaX"`
    DeltaY    float64 `js:"deltaY"`
    DeltaZ    float64 `js:"deltaZ"`
    DeltaMode int     `js:"deltaMode"`
}

Add Options() to HTMLSelectElement.

I think it would be useful if HTMLSelectElement had Options() just like HTMLDataListElement does (which is where I copied the code from):

diff --git a/dom.go b/dom.go
index 78f3e2e..a2fa6e7 100644
--- a/dom.go
+++ b/dom.go
@@ -2401,6 +2401,15 @@ type HTMLScriptElement struct {

 type HTMLSelectElement struct{ *BasicHTMLElement }

+func (e *HTMLSelectElement) Options() []*HTMLOptionElement {
+   options := nodeListToElements(e.Get("options"))
+   out := make([]*HTMLOptionElement, len(options))
+   for i, option := range options {
+       out[i] = option.(*HTMLOptionElement)
+   }
+   return out
+}
+
 type HTMLSourceElement struct {
    *BasicHTMLElement
    Media string `js:"media"`

Add documentation

We will want to document all of the public methods and types. For the majority, we should be able to copy existing documentation (for example from the MDN), as long as it's licensed in an acceptable way.

Some methods have behaviour specific to our bindings, which will need handwritten documentation.

This is a long-term goal. It won't happen now, and it doesn't have to happen all at once.

v2: CreateTextNode() panics

I am trying to use CreateTextNode() with GOOS=js GOARCH=wasm and go1.13.9.

// +build js
package main

import "honnef.co/go/js/dom/v2"

func main() {
	d := dom.GetWindow().Document().(dom.HTMLDocument)
	_ = d.CreateTextNode("foobar")
}

The above code panics with:

panic: interface conversion: dom.Node is dom.Text, not *dom.Text wasm_exec.js:41:14
<empty string> wasm_exec.js:41:14
goroutine 1 [running]: wasm_exec.js:41:14
honnef.co/go/js/dom/v2.document.CreateTextNode(0xc1e018, 0xbade2, 0x6, 0x108be48) wasm_exec.js:41:14
	/go/pkg/mod/honnef.co/go/js/dom/[email protected]/dom.go:803 +0x9 wasm_exec.js:41:14
main.main() wasm_exec.js:41:14
	/tmp/godomtest/main.go:10 +0xc wasm_exec.js:41:14
exit code: 2 wasm_exec.js:106:14

Where is document.readyState property?

Thanks for the great job!) Today I started to play around with your package and couldn't get it work. The first thing what I did is include compiled main.js file into <head> tag. However whatever selector I use (dom.GetWindow().Document().querySelector("...")) - it returned nil. The problem was I need to include the file before body close tag!) So where is DOM's readyState property?

Do not truncate accuracy of values for various positions/dimension methods.

Motivation

Using int for those x/y positions/widths/heights truncates the accuracy of returned values (to nearest int). This is not acceptable in some situations. Consider that browsers may have their zoom level set to something like 90% or 125%, so positions/widths may often end up being non-integer even if they are integer in source HTML.

This fixes a real/testable bug in my code where getting the current window position and restoring it later resulted in a minor drift. Switching to float64 fixes it.

I see some APIs already use float64, like OffsetTop(), OffsetWidth(). I propose all other similar APIs should be changed from int to float64.

Sample Patch

This is a sample patch that I used to test if this would work. It did work. It's an MVP patch that doesn't change all similar APIs, only the ones I needed to run my trial.

From 87d66042d174ce83a0c2a5984c17e8e55965dd75 Mon Sep 17 00:00:00 2001
From: Dmitri Shuralyov <[email protected]>
Date: Sun, 19 Apr 2015 21:57:54 -0700
Subject: [PATCH] WIP: Try out float64 precision for positions and dimensions.

This is an MVP test to see if it makes a difference in fixing slight
drift when saving/restoring window scroll position, etc.

---
 dom.go | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/dom.go b/dom.go
index 7ed4e42..18f3200 100644
--- a/dom.go
+++ b/dom.go
@@ -809,14 +809,14 @@ type Window interface {
    Location() *Location
    Name() string
    SetName(string)
-   InnerHeight() int
-   InnerWidth() int
+   InnerHeight() float64
+   InnerWidth() float64
    Length() int
    Opener() Window
    OuterHeight() int
    OuterWidth() int
-   ScrollX() int
-   ScrollY() int
+   ScrollX() float64
+   ScrollY() float64
    Parent() Window
    ScreenX() int
    ScreenY() int
@@ -852,7 +852,7 @@ type Window interface {
    Scroll(x, y int)
    ScrollBy(dx, dy int)
    ScrollByLines(int)
-   ScrollTo(x, y int)
+   ScrollTo(x, y float64)
    SetCursor(name string)
    SetInterval(fn func(), delay int) int
    SetTimeout(fn func(), delay int) int
@@ -890,12 +890,12 @@ func (w *window) SetName(s string) {
    w.Set("name", s)
 }

-func (w *window) InnerHeight() int {
-   return w.Get("innerHeight").Int()
+func (w *window) InnerHeight() float64 {
+   return w.Get("innerHeight").Float()
 }

-func (w *window) InnerWidth() int {
-   return w.Get("innerWidth").Int()
+func (w *window) InnerWidth() float64 {
+   return w.Get("innerWidth").Float()
 }

 func (w *window) Length() int {
@@ -914,12 +914,12 @@ func (w *window) OuterWidth() int {
    return w.Get("outerWidth").Int()
 }

-func (w *window) ScrollX() int {
-   return w.Get("scrollX").Int()
+func (w *window) ScrollX() float64 {
+   return w.Get("scrollX").Float()
 }

-func (w *window) ScrollY() int {
-   return w.Get("scrollY").Int()
+func (w *window) ScrollY() float64 {
+   return w.Get("scrollY").Float()
 }

 func (w *window) Parent() Window {
@@ -1065,7 +1065,7 @@ func (w *window) ScrollByLines(i int) {
    w.Call("scrollByLines", i)
 }

-func (w *window) ScrollTo(x, y int) {
+func (w *window) ScrollTo(x, y float64) {
    w.Call("scrollTo", x, y)
 }

-- 
2.3.2 (Apple Git-55)

Feature Request: Element.SetOuterHTML.

The Element interface has InnerHTML and SetInnerHTML but no equivalents for outerHTML.

https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML

Is there a reason? Is outerHTML not a first class citizen or is there another reason why it should not be supported unlike innerHTML?

If there's no reason to avoid adding it, I think it'd be useful. I've been doing:

e.Underlying().Set("outerHTML", html)

One time I accidentally used the wrong variable (type int rather than string), and the static type check didn't catch it because js.Object.Set accepts interface{}. If I could've used SetOuterHTML, it'd be caught and save me time (and other people who might make a mistake of this class in the future).

Add an Error type

Add a type Error, which acts as a combination of DOMException and DOMError. It should be returned from methods such as (*HTMLInputElement).StepDown, which are documented to throw exceptions in case of abnormal conditions.

When we catch an exception that isn't of type DOMException¹, we should throw it again, as it's of a different nature.

We should also consider adding one variable per possible error type (e.g. InvalidStateError), so that one can check directly against those, instead of requiring more constants and comparing fields of Error to those.

Finally, find out whether all modern browsers have the name property, or if we need to implement a fallback that looks at code instead.

¹: Only DOMException will actually be thrown, DOMError is some internal name.
²: https://developer.mozilla.org/en-US/docs/Web/API/DOMError and https://developer.mozilla.org/en/docs/Web/API/DOMException will serve as guidance.

Missing `Children` method on `dom.Element`

For reference, I'm using dom/v2 with go1.16.6 to build WASM client for a web project.

I have a case when I parse some arbitrary HTML from the server and add individual elements to DOM based on this. I call SetInnerHTML on some temporary element and then add children one by one. However HTML has whitespaces in it, so returned node may be a text one.

...
newCommentsList := dom.GetWindow().Document().CreateElement("div")
newCommentsList.SetInnerHTML(resp.HTML)
...
for _, commentNode := range newCommentsList.ChildNodes() {
    if _, ok := commentNode.(*dom.Text); ok {
    //if commentNode.NodeType() == 3 { // or like this
        continue
    }
    ...
    commentsTop.ParentElement().InsertBefore(commentNode, commentsTop.NextElementSibling())
}
...

I could have avoided checking against node type if I had Children method:
https://developer.mozilla.org/en-US/docs/Web/API/Element/children. Other *Element methods, such as ParentElement or NextElementSibling works fine for this purpose.

Uncaught TypeError: a.Object.index is not a function calling ToMap

The following code gives Uncaught TypeError: a.Object.index is not a function

d := dom.GetWindow().Document()
ufoEl := d.GetElementByID("ufo").(*dom.HTMLParagraphElement)
ufoEl.Style().SetProperty("left", "300px", "")
fmt.Println(ufoEl.Style())
fmt.Println(ufoEl.Style().ToMap())

Using HTML5 history gives a nil reference error

When I run

println(dom.GetWindow().History().Length())

I get the error

Uncaught Error: runtime error: invalid memory address or nil pointer dereference

but if I use

println(js.Global.Get("history").Get("length"))

the output is "2", as expected, both running in Chrome Version 66.0.3359.181 (Official Build) (64-bit), the latest version.

v2 does not compile with go1.14

When building a v2-based program with go1.14:

# honnef.co/go/js/dom/v2
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:121:7: invalid operation: o == js.Null() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:121:25: invalid operation: o == js.Undefined() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:144:27: invalid operation: n != js.Undefined() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:160:26: invalid operation: o.Get("constructor") == js.Global().Get("Array") (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:218:2: cannot switch on elementConstructor(o) (type js.Value) (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:227:2: cannot switch on elementConstructor(o) (type js.Value) (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:235:7: invalid operation: o == js.Null() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:235:25: invalid operation: o == js.Undefined() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:238:2: cannot switch on elementConstructor(o) (type js.Value) (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:248:7: invalid operation: o == js.Null() (struct containing [0]func() cannot be compared)
..\..\..\..\..\..\pkg\mod\honnef.co\go\js\dom\[email protected]\dom.go:248:7: too many errors

Adding event type strings to use with `AddEventListener`

For documentation and ease of use, event types could be added to aid users with available event types (these are hard to come across in a complete list on the internet)

const (
    EventClick = "click"
    EventLoad = "load"
    EventAbort = "abort"
    // ...
)
Example of what I mean
package main

// UI events.
const (
	// The load event fires when the webpage finishes loading.
	// It can also fire on nodes of elements like images, scripts, or objects.
	EventLoad = "load"
	// Fires when a user leaves the page. Usually because they click on a link.
	EventUnload = "unload"
	// This event fires when the browser encounters a JavaScript error or an asset that doesn’t exist.
	EventError = "error"
	// It fires when we resize the browser window. But browsers repeatedly fire this event,
	// so avoid using this event to trigger complicated code; it might make the page less responsive.
	EventResize = "resize"
	// This event fires when the user scrolls up/down on the browser window.
	// It can relate to the entire page or a specific element on the page.
	EventScroll = "scroll"
)

// Focus and blur events.
const (
	// This event fires, for a specific DOM node, when an element gains focus.
	EventFocus = "focus"
	// This fires, for a specific DOM node, when an element loses focus.
	EventBlur = "blur"
)

// Human interface device input events.
const (
	// Mouse events or touchpad
	// This event fires when the user clicks on the primary mouse button (usually the left button).
	// This event also fires if the user presses the Enter key on the keyboard when an element has focus.
	// Touch-screen: A tap on the screen acts like a single primary mouse button click.
	EventClick = "click"
	// It fires when the user clicks down on any mouse button.
	EventMouseDown, EventTouchstart = "mousedown", "touchstart"

	// We have separate mousedown and mouseup events to add drag-and-drop functionality
	// or controls in game development. Don’t forget a click event is the combination
	// of mousedown and mouseup events.

	// It fires when the user releases a mouse button.
	EventMouseUp = "mouseup"
	// It fires when the user moves the cursor, which was inside an element before, outside the element.
	// We can say that it fires when the cursor moves off the element.
	EventMouseOut = "mouseout"
	// It fires when the user moves the cursor, which was outside an element before, inside the element.
	// We can say that it fires when we move the cursor over the element.
	EventMouseOver = "mouseover"
	// It fires when the user moves the cursor around the element. This event is frequently triggered.
	EventMouseMove = "mousemove"

	// Keyboard events

	// The keydown and keypress events fire before a character appears on the screen,
	// the keyup fires after it shows. To know the key pressed when you use the
	// keydown and keypress events, the event object has a keyCode property.
	// This property, instead of returning the letter for that key, returns
	// the ASCII code of the lowercase for that key.

	// The keyup event fires when the user releases a key on the keyboard.
	EventKeyUp = "keyup"
	// It fires when the user presses any key in the keyboard.
	// If the user holds down the key, this event fires repeatedly.
	EventKeyDown = "keydown"
	// It fires when the user presses a key that results in printing a character on the screen.
	// This event fires repeatedly if the user holds down the key.
	// This event will not fire for the enter, tab, or arrow keys; the keydown event would.
	EventKeyPress = "keypress"

	// This event fires when the user clicks the primary mouse button, in quick succession, twice.
	EventDoubleClick = "dblclick"
)

// Form events
const (
	// This event fires on the node representing the <form> element when a user submits a form.
	EventSubmit = "submit"
	// It fires when the status of various form elements change.
	// This is a better option than using the click event because clicking is not the only way users interact with the form.
	EventChange = "change"
	// This event fires when the value of an <input> or a <textarea> changes
	// (doesn’t fire for deleting in IE9). You can use keydown as a fallback in older browsers.
	EventInput = "input"
)

// HTML5 events.
const (
	// This event triggers when the DOM tree forms i.e. the script is loading.
	// Scripts start to run before all the resources like images, CSS, and JavaScript loads.
	// You can attach this event either to the window or the document objects.
	EventDOMContentLoaded = "DOMContentLoaded"
	// It fires when the URL hash changes without refreshing the entire window.
	// Hashes (#) link specific parts (known as anchors) within a page.
	//  It works on the window object; the event object contains both the oldURL
	// and the newURL properties holding the URLs before and after the hashchange.
	EventHashChange = "hashchange"
	// This event fires on the window object just before the page unloads.
	// This event should only be helpful for the user,
	// not encouraging them to stay on the page.
	// You can add a dialog box to your event, showing a message alerting the users like their changes are not saved.
	EventBeforeUnload = "beforeunload"
)

Issue with interaction between methods that accept nil and return nil.

This is one such occurrence that I ran into, but there may be more instances. So we'll want a general solution.

According to https://developer.mozilla.org/en-US/docs/Web/API/Node.insertBefore:

If referenceElement is null, or undefined, newElement is inserted at the end of the list of child nodes.

So it's valid to write the following JavaScript code:

TargetDiv.parentNode.insertBefore(NewDiv, TargetDiv.nextSibling); // Insert after.

Because nextSibling returns null if the specified node is the last node in that list.

When we directly translate that to Go with dom package:

TargetDiv.ParentNode().InsertBefore(NewDiv, TargetDiv.NextSibling()) // Insert after.

What happens is TargetDiv.NextSibling() returns (Node)(nil) because of wrapNode(). Then InsertBefore tries to call Underlying() on it and we get Uncaught TypeError: undefined is not a function error.

One solution I can think of, without modifying InsertBefore specifically, since we'd want this situation to be handled okay in other similar cases, would be something like this:

diff --git a/dom.go b/dom.go
index a789bb0..8df66eb 100644
--- a/dom.go
+++ b/dom.go
@@ -164,7 +164,7 @@ func wrapDocument(o js.Object) Document {

 func wrapNode(o js.Object) Node {
    if o.IsNull() || o.IsUndefined() {
-       return nil
+       return &BasicNode{nil}
    }
    switch o.Get("constructor") {
    // TODO all the non-element cases
@@ -1217,6 +1217,9 @@ type BasicNode struct {
 }

 func (n *BasicNode) Underlying() js.Object {
+   if n == nil {
+       return nil
+   }
    return n.Object
 }

But I'm not sure if that would cause other unintended side-effects (probably not... but please confirm). Is there a better way or is this the best way? If we use this approach, we'll probably want to apply it to other similar wrap* funcs.

Uncaught RangeError: Maximum call stack size exceeded

I have: Go 1.7.1, GopherJS 1.7-1.
Can't figure out why i'm receiving: Uncaught RangeError: Maximum call stack size exceeded.
Is it a bug somewhere?

package main

import "honnef.co/go/js/dom"

func main() {
    d := dom.GetWindow().Document()
    h := d.GetElementByID("app")

    h.AddEventListener("click", false, func(event dom.Event) {
        event.PreventDefault()
        h.SetInnerHTML("I am Clicked")
        println("This message is printed in browser console")
    })
}

It's the $internalize function producing this error by repeatedly calling the searchJsObject function.

Accessing Values From Input Forms

Based on documentation it looks be that you would have to use HTML input events to gather information from input fields. Is there no golang alternative to using a .value in JS terms?

v2: unable to DrawImage

This is my code:

// +build js

package main

import (
	"time"

	dom "honnef.co/go/js/dom/v2"
)

var window = dom.GetWindow()
var qs = window.Document().QuerySelector
var canvas *dom.HTMLCanvasElement
var ctx *dom.CanvasRenderingContext2D
var lock = false
var currentPuzzle *Puzzle

// Puzzle contains all information about one puzzle and its state
type Puzzle struct {
	image *dom.HTMLImageElement
}

func main() {
	canvas = qs("#screen").(*dom.HTMLCanvasElement)
	ctx = canvas.GetContext2d()

	loadImage("assets/puzzles/niagara.jpg", func(img *dom.HTMLImageElement) {
		currentPuzzle = &Puzzle{img}
		redraw()
	})

	window.AddEventListener("resize", false, func(e dom.Event) { resize() })
	resize()
}

func resize() {
	rect := qs("#container").GetBoundingClientRect()
	canvas.SetWidth(int(rect.Width()))
	canvas.SetHeight(int(rect.Height()))
	redraw()
}

func draw(t time.Duration, puzzle *Puzzle) {
	ctx.SetFillStyle("#f00")
	ctx.FillRect(0, 0, 100, 100)
	if puzzle != nil {
		ctx.DrawImage(puzzle.image, 0, 0)
	}
}

func redraw() {
	if !lock {
		lock = true
		window.RequestAnimationFrame(func(d time.Duration) {
			lock = false
			draw(d, currentPuzzle)
		})
	}
}

func loadImage(src string, callback func(img *dom.HTMLImageElement)) {
	img := window.Document().CreateElement("img").(*dom.HTMLImageElement)
	img.AddEventListener("load", false, func(e dom.Event) { callback(img) })
	img.SetSrc(src)
}

On Firefox it gives me: Error: invalid arg: *dom.HTMLImageElement with the stack trace pointing to convertArgs js.go:174.

createShadowRoot() and WebComponent

Hi,

Is it possible to use createShadowRoot()? If not, do you plan to bind createShadowRoot and everything related to Web components? That would be great and useful for the comunity I guess.

HTMLTemplateElement is missing?

The <template> have a "attribute" of content for read the content of the template itself.

It's possible to do using:

template := t.template.QuerySelector("template")
content := dom.WrapDocumentFragment( template.Underlying().Get("content") )

But, the go-js-dom have a bunch of elements, like HTMLAnchorElement, HTMLAudioElement and so on. But actually, don't have seems to have a HTMLTemplateElement.

Add a way to extract what key was pressed to KeyboardEvent.

I need to be able to get extract what key was pressed (looking for Escape, Enter keys).

I've just looked into the various docs [1][2][3], and they seem to suggest that:

The KeyboardEvent was briefly (from 2003-2010) defined to have keyIdentifier and keyLocation attributes, but these were removed in favor of the current key and location attributes. These attributes were not widely implemented.

But when using the latest stable Chrome and Safari, I'm seeing the opposite. key is not present at all, but keyIdentifier is set. With this test page,

<html><body><input onkeydown="console.log(event);"></body></html>

This is what I'm seeing:

image

The only two fields that I see to identify which key was pressed are keyCode and keyIdentifier.

Can you please add one of them? Or if I'm mistaken, suggest how I can determine if Escape or Enter were pressed using existing API.

I think I would prefer keyIdentifier (over keyCode) if it indeed is the current "standard". But I'm not opposed to you adding both.

[1] https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
[2] http://www.w3.org/TR/DOM-Level-3-Events/
[3] http://unixpapa.com/js/key.html

Get underlying *js.Object from Event

Hi,

First of all, thanks for a great library.

I often find my self needing the underlying *js.Object from an event (to add state information and retrieve the corresponding information if other handlers for the same event). As is the the event interface does not allow me to do this in a type safe way since I do not know the concrete type of the event (may be one f several) I in each function needs to have a large type switch which effectively tests all the event types (and what if more are added, that would lead to a panic/not working).

Thus, my uggestion would be to add a:

Underlying() *js.Object

method to the Event interface.

Any thoughts?

moving under gopherjs organization?

Heya @dominikh ! This is a really broad open-ended question (feel free to ignore / close if you like).. just wondering if you've considered placing this project under e.g. github.com/gopherjs/dom or something? I think that would help with discovery a bit, as the first place I looked for this was in that organization.

If you dislike the idea / it's already been discussed etc. then I apologize for bringing it up -- I just think it's a nice project and really central to the needs of most gopherjs users and wondered if you'd considered it before or not. (obviously I can't speak for gopherjs maintainers either).

Either way, great package! Cheers!

v2: RequestAnimationFrame callback argument type misleading

The current arguments expects a time.Duration which is an int64 that should measure time deltas in nanoseconds. However requestAnimationFrame is said to give millisecond time points relative to some variable time origin. Perhaps it is better to change the type into int (or whatever is best compatible with JS).

Cannot load honnef.co/go/js/dom/v2: no Go source files

Hello, I'm trying to get this project for the first time. I used go mod for my project.

It's success to get the package mentioned using go get honnef.co/go/js/dom/v2 and when I check the folder it's exist with the following tree :

.
├── honnef.co
│   └── go
│       └── js
│           └── dom
│               └── v2
│                   ├── LICENSE
│                   ├── dom.go
│                   ├── events.go
│                   └── go.mod

But when I import it on my simple project it says

build command-line-arguments: cannot load honnef.co/go/js/dom/v2: no Go source files

This is my code

package main

import (
	"fmt"
	"honnef.co/go/js/dom/v2"
)

func main() {
	el := dom.GetWindow().Document().QuerySelector("#number1")
	htmlEl := el.(dom.HTMLElement)
	pEl := el.(*dom.HTMLParagraphElement)
	fmt.Println("Hello", pEl)
}

DispatchEvent of "Click"/"Change"

Using this library is possible to listen the Click or Change, like el.AddEventListener("change", false, func(...)).

However, how can I use the DispatchEvent? I mean, how I can el.DispatchEvent("change") to trigger the listener?

Improve SetClass situation.

Currently, the documentation has this example:

d := dom.GetWindow().Document()
e1 := d.GetElementByID("#my-element")
e2 := d.GetElementByID("#my-element")

e1.SetClass("some-class")
println(e1.Class().String() == e2.Class().String())

That will not compile because Element interface does not have SetClass method exposed. So, to access the SetClass method of BasicElement struct, one needs to go the long way:

var e dom.HTMLDivElement
e.BasicHTMLElement.BasicElement.SetClass()

Or, if you only have an interface like HTMLElement given to you, getting to SetClass is impossible without lots of type assertions.

The example should be rewritten to use correct code that works, for example:

d := dom.GetWindow().Document()
e1 := d.GetElementByID("#my-element")
e2 := d.GetElementByID("#my-element")

e1.Class().SetString("some-class")
println(e1.Class().String() == e2.Class().String())

And since the SetClass method of BasicElement struct is redundant, and effectively unusable, it might as well be removed.


Separately, the interface of TokenList can be improved. Currently, it offers separate methods to set a single string and set a slice:

Set(s []string)
SetString(s string)

I would suggest you consider changing/adding a method with the signature:

Set(s ...string)

It's shorter, one method, and can be used in all situations:

e.Set("single-class")
e.Set("class-a", "class-b", "class-c")

var classes = []string{"foo", "bar"}
e.Set(classes...)

Summary

  • Fix documentation by providing valid code.
  • Remove unnecessary SetClass() method.
  • Consider a better signature for setting TokenList values.

Adding examples to the repository

Hi, is there appetite to add an examples folder to the repo? Or are there already examples of using the package elsewhere that I have missed?

Installing on Ubuntu with 512MB Ram Crashes

When trying to run "go get honnef.co/go/js/dom" the process crashes with a "signal: killed" message.

Here is the output of "free -m" to show the memory available prior to install and then "go get honnef.co/go/js/dom":

root@recall:~# free -m
total       used       free     shared    buffers     cached
Mem:           490         87        402          0         10         37
-/+ buffers/cache:         39        450
Swap:            0          0          0

root@recall:~# go get honnef.co/go/js/dom
go build honnef.co/go/js/dom: /usr/local/go/pkg/tool/linux_amd64/6g: signal: killed

When looking up the "signal: killed" error related to 6g, a couple go bug reports say that "What causes the compiler to consume a lot of memory is large static initaliser blocks", eventually getting the process killed (https://code.google.com/p/go/issues/detail?id=6251).

Any way to get around this?

Thanks!

No nice way to set CanvasRenderingContext2D.FillStyle to gradient, pattern.

This is an API design issue.

The fillStyle property of CanvasRenderingContext2D interface can be assigned any of 3 different types, according to https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle:

image

However, CanvasRenderingContext2D.FillStyle field is defined as a string:

go-js-dom/dom.go

Line 1915 in 790c789

FillStyle string `js:"fillStyle"`

So the following code will fail to compile:

gradient := ctx.CreateRadialGradient(0, 0, 8*1.75, 0, 0, 0)
gradient.AddColorStop(0, "rgba(0, 0, 0, 0)")
gradient.AddColorStop(1, "rgba(0, 0, 0, 0.3)")
ctx.FillStyle = gradient
cannot use gradient (variable of type *honnef.co/go/js/dom.CanvasGradient) as string value in assignment

I can think of some solutions, but I'm not sure which one we should pick. They all have trade-offs.

Possible solution 1

Don't do anything special. Let users do use *js.Object API:

ctx.Set("fillStyle", gradient)

This works, but perhaps it's not as nice as one could wish for.

(I'm using this as my current workaround.)

Possible solution 2

One potential solution is to change FillStyle type to interface{}:

FillStyle interface{} `js:"fillStyle"` // Can be assigned one of string, *CanvasGradient, *CanvasPattern.

Then all these are possible:

ctx.FillStyle = "rgb(255, 0, 0)"
ctx.FillStyle = gradient
ctx.FillStyle = pattern

This works, but interface{} isn't great for APIs. Any other type can be assigned too, and when querying the value of FillStyle, you get an interface{} which isn't nice either.

Possible solution 3

Define 3 fields of 3 different types, all mapping to JS property fillStyle:

FillStyle         string          `js:"fillStyle"`
FillStyleGradient *CanvasGradient `js:"fillStyle"`
FillStylePattern  *CanvasPattern  `js:"fillStyle"`

Then all these are possible:

ctx.FillStyle = "rgb(255, 0, 0)"
ctx.FillStyleGradient = gradient
ctx.FillStylePattern = pattern

This works, but now there are 3 fields for one field... Which may be confusing and creates bloat.

/cc @luckcolors FYI, in case you have ideas on this.

Add a method to access the File content.

Is it possible to add a method to retrieve the content of a File object to be able to send it with a POST method to the server ?

fileSelect := d.GetElementByID("import-file").(*dom.HTMLInputElement)
file := fileSelect.Files()[0]
...
resp, err := http.Post("/import/", "multipart/form-data", [the-file-content])
...

I currently do this in Javascript with:

var file = fileSelect.files[0];
var formData = new FormData();
formData.append('importFile', file, file.name);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/import/', true);
...

Or any way to do this with another method?
Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.