maxence-charriere / go-app

A package to build progressive web apps with Go programming language and WebAssembly.

Home Page:https://go-app.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Demos needed for dealing UI components from event handler

suntong opened this issue · comments

Please take a look at
https://github.com/suntong/go-app-demos/tree/master/0B2A-codecopy
unfinished refactor from the last good version.

What I want to achieve is to have two code blocks and be able to do code-copy from either of them. Unfinished because I'm not too sure how to move forward, in achieving so.

Moreover, please give demo code how to deal with the UI components from the event handler, of the following scenarios in onButtonClicked():

  • Just for the showcase, try get the code from the html UI, instead of directly using m.code[i]
  • Change the text of the clicked button from "Copy code" to "Copied", after 2 seconds, change it back.
  • And/or, force show tooltip to the clicked button as "Copied", after 2 seconds, force remove the tooltip.

I tried to see from the reference how to access the UI components from the event handler myself but no luck. Please help.

Demo code..

// DisplaySample replaces your (m *codeBlockModel) Render()
func DisplaySample() app.UI {
	codeSamples := []string{`
                    // Code block 1
                    function helloWorld() {
                        console.log("Hello, world!");
                    }
`,
		`
                    // Code block 2
                    for (let i = 0; i < 5; i++) {
                        console.log(i);
                    }
`}

	return app.Div().Class("code-container").Body(
		app.Range(codeSamples).Slice(func(i int) app.UI {
			return &CodeBlock{code: codeSamples[i], id: fmt.Sprintf("codeBlock%02d", i+1)}
		}),
	)

}

type CodeBlock struct {
	app.Compo
	id   string
	code string
}

func (m *CodeBlock) Render() app.UI {
	return app.Div().Class("code-block").Body(
		copySVG(),
		&CopyButton{text: "Copy code", from: m},
		app.Pre().Body(
			app.Code().ID(m.id).Text(m.code),
		),
	)
}

// original svg markup had two "class" attributes.  in this one they are merged
func copySVG() app.UI {
	return app.Raw(`<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="copy-svg h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>`)
}

type CopyButton struct {
	app.Compo
	from *CodeBlock
	text string
}

func (cb *CopyButton) Render() app.UI {
	return app.Button().Class("copy-button").Text(cb.text).OnClick(cb.onClick)
}

func (cb *CopyButton) onClick(ctx app.Context, e app.Event) {
	// using go
	log.Println("copy via go\n", cb.from.code)

	// using element id
	val := app.Window().GetElementByID(cb.from.id).Get("innerHTML")
	log.Println("copy via dom\n", val.String())

	app.Window().Get("navigator").Get("clipboard").Call("writeText", val)
	cb.text = "Copied"
	ctx.After(2*time.Second, cb.revertText)
}

func (cb *CopyButton) revertText(ctx app.Context) {
	cb.text = "Copy code"
}

Demo code..

Wow, thanks a million.

I've incoporated everything into
https://github.com/suntong/go-app-demos/blob/master/0B2A-codecopy/main.go
(I'm keeping m.code[i] as that would where my data come from in my realworld app)

The // using go and // using element id are both working fine, however, it is the next line that causes my browser panic, the line of app.Window().Get("navigator").Get("clipboard").Call("writeText", val), and the panic errors are:

2023/08/14 14:16:58 copy via dom
               // Code block 1
                    function helloWorld() {
                        console.log("Hello, world!");
                    }

wasm_exec.js:22 panic: syscall/js: call of Value.Call on undefined [recovered]
wasm_exec.js:22 	panic: syscall/js: call of Value.Call on undefined
wasm_exec.js:22 
wasm_exec.js:22 goroutine 1 [running]:
wasm_exec.js:22 github.com/maxence-charriere/go-app/v9/pkg/app.RunWhenOnBrowser.func1()
wasm_exec.js:22 	/.../Go/pkg/mod/github.com/maxence-charriere/go-app/v9@v9.7.3/pkg/app/app.go:109 +0x4
wasm_exec.js:22 panic({0x65540, 0x80a3f0})
wasm_exec.js:22 	/usr/lib/go-1.19/src/runtime/panic.go:890 +0x33
wasm_exec.js:22 syscall/js.Value.Call({{}, 0x0, 0x0}, {0xcf08b, 0x9}, {0x81df60, 0x1, 0x1})
wasm_exec.js:22 	/usr/lib/go-1.19/src/syscall/js/js.go:384 +0x35
wasm_exec.js:22 github.com/maxence-charriere/go-app/v9/pkg/app.value.Call({{{}, 0x0, 0x0}}, {0xcf08b, 0x9}, {0x81df60, 0x1, 0x1})               // Code block 1
                    function helloWorld() {
                        console.log("Hello, world!");
                    }

wasm_exec.js:22 panic: syscall/js: call of Value.Call on undefined [recovered]
wasm_exec.js:22 	panic: syscall/js: call of Value.Call on undefined
wasm_exec.js:22 
wasm_exec.js:22 goroutine 1 [running]:
wasm_exec.js:22 github.com/maxence-charriere/go-app/v9/pkg/app.RunWhenOnBrowser.func1()
wasm_exec.js:22 	/.../Go/pkg/mod/github.com/maxence-charriere/go-app/v9@v9.7.3/pkg/app/app.go:109 +0x4
wasm_exec.js:22 panic({0x65540, 0x80a3f0})
wasm_exec.js:22 	/usr/lib/go-1.19/src/runtime/panic.go:890 +0x33
wasm_exec.js:22 syscall/js.Value.Call({{}, 0x0, 0x0}, {0xcf08b, 0x9}, {0x81df60, 0x1, 0x1})
wasm_exec.js:22 	/usr/lib/go-1.19/src/syscall/js/js.go:384 +0x35
wasm_exec.js:22 github.com/maxence-charriere/go-app/v9/pkg/app.value.Call({{{}, 0x0, 0x0}}, {0xcf08b, 0x9}, {0x81df60, 0x1, 0x1})
wasm_exec.js:22 panic: syscall/js: call of Value.Call on undefined [recovered]
wasm_exec.js:22 	panic: syscall/js: call of Value.Call on undefined
wasm_exec.js:22 
wasm_exec.js:22 goroutine 1 [running]:
wasm_exec.js:22 github.com/maxence-charriere/go-app/v9/pkg/app.RunWhenOnBrowser.func1()
wasm_exec.js:22 	...

This is most likely the cause of why the clipboard code example not working as it uses the same window.navigator.clipboard path.

What does your JS console reveal for typing in the following:

window
window.navigator
window.navigator.clipboard
navigator

Here's mine:

image

Oh,
It turns out that, it's a problem of me not having/providing https service from my test server, as pointed out from here:

This requires a secure origin — either HTTPS or localhost (or disabled by running Chrome with a flag).

Thank you for getting to the bottom of it.