191 lines
6.6 KiB
Go
191 lines
6.6 KiB
Go
package datastar
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/valyala/bytebufferpool"
|
|
)
|
|
|
|
// ValidFragmentMergeTypes is a list of valid fragment merge modes.
|
|
var ValidFragmentMergeTypes = []FragmentMergeMode{
|
|
FragmentMergeModeMorph,
|
|
FragmentMergeModeInner,
|
|
FragmentMergeModeOuter,
|
|
FragmentMergeModePrepend,
|
|
FragmentMergeModeAppend,
|
|
FragmentMergeModeBefore,
|
|
FragmentMergeModeAfter,
|
|
FragmentMergeModeUpsertAttributes,
|
|
}
|
|
|
|
// FragmentMergeTypeFromString converts a string to a [FragmentMergeMode].
|
|
func FragmentMergeTypeFromString(s string) (FragmentMergeMode, error) {
|
|
switch s {
|
|
case "morph":
|
|
return FragmentMergeModeMorph, nil
|
|
case "inner":
|
|
return FragmentMergeModeInner, nil
|
|
case "outer":
|
|
return FragmentMergeModeOuter, nil
|
|
case "prepend":
|
|
return FragmentMergeModePrepend, nil
|
|
case "append":
|
|
return FragmentMergeModeAppend, nil
|
|
case "before":
|
|
return FragmentMergeModeBefore, nil
|
|
case "after":
|
|
return FragmentMergeModeAfter, nil
|
|
case "upsertAttributes":
|
|
return FragmentMergeModeUpsertAttributes, nil
|
|
default:
|
|
return "", fmt.Errorf("invalid fragment merge type: %s", s)
|
|
}
|
|
}
|
|
|
|
// WithMergeMorph creates a MergeFragmentOption that merges fragments using the morph mode.
|
|
func WithMergeMorph() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeMorph)
|
|
}
|
|
|
|
// WithMergeInner creates a MergeFragmentOption that merges fragments using the inner mode.
|
|
func WithMergeInner() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeInner)
|
|
}
|
|
|
|
// WithMergeOuter creates a MergeFragmentOption that merges fragments using the outer mode.
|
|
func WithMergeOuter() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeOuter)
|
|
}
|
|
|
|
// WithMergePrepend creates a MergeFragmentOption that merges fragments using the prepend mode.
|
|
func WithMergePrepend() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModePrepend)
|
|
}
|
|
|
|
// WithMergeAppend creates a MergeFragmentOption that merges fragments using the append mode.
|
|
func WithMergeAppend() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeAppend)
|
|
}
|
|
|
|
// WithMergeBefore creates a MergeFragmentOption that merges fragments using the before mode.
|
|
func WithMergeBefore() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeBefore)
|
|
}
|
|
|
|
// WithMergeAfter creates a MergeFragmentOption that merges fragments using the after mode.
|
|
func WithMergeAfter() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeAfter)
|
|
}
|
|
|
|
// WithMergeUpsertAttributes creates a MergeFragmentOption that merges fragments using the upsert attributes mode.
|
|
func WithMergeUpsertAttributes() MergeFragmentOption {
|
|
return WithMergeMode(FragmentMergeModeUpsertAttributes)
|
|
}
|
|
|
|
// WithSelectorID is a convenience wrapper for [WithSelector] option
|
|
// equivalent to calling `WithSelector("#"+id)`.
|
|
func WithSelectorID(id string) MergeFragmentOption {
|
|
return WithSelector("#" + id)
|
|
}
|
|
|
|
// WithViewTransitions enables the use of view transitions when merging fragments.
|
|
func WithViewTransitions() MergeFragmentOption {
|
|
return func(o *mergeFragmentOptions) {
|
|
o.UseViewTransitions = true
|
|
}
|
|
}
|
|
|
|
// WithoutViewTransitions disables the use of view transitions when merging fragments.
|
|
func WithoutViewTransitions() MergeFragmentOption {
|
|
return func(o *mergeFragmentOptions) {
|
|
o.UseViewTransitions = false
|
|
}
|
|
}
|
|
|
|
// MergeFragmentf is a convenience wrapper for [MergeFragments] option
|
|
// equivalent to calling `MergeFragments(fmt.Sprintf(format, args...))`.
|
|
func (sse *ServerSentEventGenerator) MergeFragmentf(format string, args ...any) error {
|
|
return sse.MergeFragments(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// TemplComponent satisfies the component rendering interface for HTML template engine [Templ].
|
|
// This separate type ensures compatibility with [Templ] without imposing a dependency requirement
|
|
// on those who prefer to use a different template engine.
|
|
//
|
|
// [Templ]: https://templ.guide/
|
|
type TemplComponent interface {
|
|
Render(ctx context.Context, w io.Writer) error
|
|
}
|
|
|
|
// MergeFragmentTempl is a convenience adaptor of [sse.MergeFragments] for [TemplComponent].
|
|
func (sse *ServerSentEventGenerator) MergeFragmentTempl(c TemplComponent, opts ...MergeFragmentOption) error {
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
if err := c.Render(sse.Context(), buf); err != nil {
|
|
return fmt.Errorf("failed to merge fragment: %w", err)
|
|
}
|
|
if err := sse.MergeFragments(buf.String(), opts...); err != nil {
|
|
return fmt.Errorf("failed to merge fragment: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GoStarElementRenderer satisfies the component rendering interface for HTML template engine [GoStar].
|
|
// This separate type ensures compatibility with [GoStar] without imposing a dependency requirement
|
|
// on those who prefer to use a different template engine.
|
|
//
|
|
// [GoStar]: https://github.com/delaneyj/gostar
|
|
type GoStarElementRenderer interface {
|
|
Render(w io.Writer) error
|
|
}
|
|
|
|
// MergeFragmentGostar is a convenience adaptor of [sse.MergeFragments] for [GoStarElementRenderer].
|
|
func (sse *ServerSentEventGenerator) MergeFragmentGostar(child GoStarElementRenderer, opts ...MergeFragmentOption) error {
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
if err := child.Render(buf); err != nil {
|
|
return fmt.Errorf("failed to render: %w", err)
|
|
}
|
|
if err := sse.MergeFragments(buf.String(), opts...); err != nil {
|
|
return fmt.Errorf("failed to merge fragment: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetSSE is a convenience method for generating Datastar backend [get] action attribute.
|
|
//
|
|
// [get]: https://data-star.dev/reference/action_plugins#get
|
|
func GetSSE(urlFormat string, args ...any) string {
|
|
return fmt.Sprintf(`@get('%s')`, fmt.Sprintf(urlFormat, args...))
|
|
}
|
|
|
|
// PostSSE is a convenience method for generating Datastar backend [post] action attribute.
|
|
//
|
|
// [post]: https://data-star.dev/reference/action_plugins#post
|
|
func PostSSE(urlFormat string, args ...any) string {
|
|
return fmt.Sprintf(`@post('%s')`, fmt.Sprintf(urlFormat, args...))
|
|
}
|
|
|
|
// PutSSE is a convenience method for generating Datastar backend [put] action attribute.
|
|
//
|
|
// [put]: https://data-star.dev/reference/action_plugins#put
|
|
func PutSSE(urlFormat string, args ...any) string {
|
|
return fmt.Sprintf(`@put('%s')`, fmt.Sprintf(urlFormat, args...))
|
|
}
|
|
|
|
// PatchSSE is a convenience method for generating Datastar backend [patch] action attribute.
|
|
//
|
|
// [patch]: https://data-star.dev/reference/action_plugins#patch
|
|
func PatchSSE(urlFormat string, args ...any) string {
|
|
return fmt.Sprintf(`@patch('%s')`, fmt.Sprintf(urlFormat, args...))
|
|
}
|
|
|
|
// DeleteSSE is a convenience method for generating Datastar backend [delete] action attribute.
|
|
//
|
|
// [delete]: https://data-star.dev/reference/action_plugins#delete
|
|
func DeleteSSE(urlFormat string, args ...any) string {
|
|
return fmt.Sprintf(`@delete('%s')`, fmt.Sprintf(urlFormat, args...))
|
|
}
|