datastar/sdk/go/execute-script-sugar.go

180 lines
4.4 KiB
Go

package datastar
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
func (sse *ServerSentEventGenerator) ConsoleLog(msg string, opts ...ExecuteScriptOption) error {
call := fmt.Sprintf("console.log(%q)", msg)
return sse.ExecuteScript(call, opts...)
}
func (sse *ServerSentEventGenerator) ConsoleLogf(format string, args ...any) error {
return sse.ConsoleLog(fmt.Sprintf(format, args...))
}
func (sse *ServerSentEventGenerator) ConsoleError(err error, opts ...ExecuteScriptOption) error {
call := fmt.Sprintf("console.error(%q)", err.Error())
return sse.ExecuteScript(call, opts...)
}
func (sse *ServerSentEventGenerator) Redirectf(format string, args ...any) error {
url := fmt.Sprintf(format, args...)
return sse.Redirect(url)
}
func (sse *ServerSentEventGenerator) Redirect(url string, opts ...ExecuteScriptOption) error {
js := fmt.Sprintf("setTimeout(() => window.location.href = %q)", url)
return sse.ExecuteScript(js, opts...)
}
type DispatchCustomEventOptions struct {
EventID string
RetryDuration time.Duration
Selector string
Bubbles bool
Cancelable bool
Composed bool
}
type DispatchCustomEventOption func(*DispatchCustomEventOptions)
func WithDispatchCustomEventEventID(id string) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.EventID = id
}
}
func WithDispatchCustomEventRetryDuration(retryDuration time.Duration) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.RetryDuration = retryDuration
}
}
func WithDispatchCustomEventSelector(selector string) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.Selector = selector
}
}
func WithDispatchCustomEventBubbles(bubbles bool) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.Bubbles = bubbles
}
}
func WithDispatchCustomEventCancelable(cancelable bool) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.Cancelable = cancelable
}
}
func WithDispatchCustomEventComposed(composed bool) DispatchCustomEventOption {
return func(o *DispatchCustomEventOptions) {
o.Composed = composed
}
}
func (sse *ServerSentEventGenerator) DispatchCustomEvent(eventName string, detail any, opts ...DispatchCustomEventOption) error {
if eventName == "" {
return fmt.Errorf("eventName is required")
}
detailsJSON, err := json.Marshal(detail)
if err != nil {
return fmt.Errorf("failed to marshal detail: %w", err)
}
const defaultSelector = "document"
options := DispatchCustomEventOptions{
EventID: "",
RetryDuration: DefaultSseRetryDuration,
Selector: defaultSelector,
Bubbles: true,
Cancelable: true,
Composed: true,
}
for _, opt := range opts {
opt(&options)
}
elementsJS := `[document]`
if options.Selector != "" && options.Selector != defaultSelector {
elementsJS = fmt.Sprintf(`document.querySelectorAll(%q)`, options.Selector)
}
js := fmt.Sprintf(`
const elements = %s
const event = new CustomEvent(%q, {
bubbles: %t,
cancelable: %t,
composed: %t,
detail: %s,
});
elements.forEach((element) => {
element.dispatchEvent(event);
});
`,
elementsJS,
eventName,
options.Bubbles,
options.Cancelable,
options.Composed,
string(detailsJSON),
)
executeOptions := make([]ExecuteScriptOption, 0)
if options.EventID != "" {
executeOptions = append(executeOptions, WithExecuteScriptEventID(options.EventID))
}
if options.RetryDuration != 0 {
executeOptions = append(executeOptions, WithExecuteScriptRetryDuration(options.RetryDuration))
}
return sse.ExecuteScript(js, executeOptions...)
}
func (sse *ServerSentEventGenerator) ReplaceURL(u url.URL, opts ...ExecuteScriptOption) error {
js := fmt.Sprintf(`window.history.replaceState({}, "", %q)`, u.String())
return sse.ExecuteScript(js, opts...)
}
func (sse *ServerSentEventGenerator) ReplaceURLQuerystring(r *http.Request, values url.Values, opts ...ExecuteScriptOption) error {
u := *r.URL
u.RawQuery = values.Encode()
return sse.ReplaceURL(u, opts...)
}
func (sse *ServerSentEventGenerator) Prefetch(urls ...string) error {
wrappedURLs := make([]string, len(urls))
for i, url := range urls {
wrappedURLs[i] = fmt.Sprintf(`"%s"`, url)
}
script := fmt.Sprintf(`
{
"prefetch": [
{
"source": "list",
"urls": [
%s
]
}
]
}
`, strings.Join(wrappedURLs, ",\n\t\t\t\t"))
return sse.ExecuteScript(
script,
WithExecuteScriptAutoRemove(false),
WithExecuteScriptAttributes("type speculationrules"),
)
}