htmgo/framework/h/lifecycle.go

317 lines
7.9 KiB
Go
Raw Normal View History

package h
import (
"fmt"
2024-09-21 03:59:07 +00:00
"github.com/maddalax/htmgo/framework/hx"
2024-09-22 15:46:38 +00:00
"github.com/maddalax/htmgo/framework/internal/util"
2024-09-22 16:53:41 +00:00
"strings"
)
type LifeCycle struct {
2024-09-21 03:59:07 +00:00
handlers map[hx.Event][]Command
}
func NewLifeCycle() *LifeCycle {
return &LifeCycle{
2024-09-21 03:59:07 +00:00
handlers: make(map[hx.Event][]Command),
}
}
2024-09-21 03:59:07 +00:00
func validateCommands(cmds []Command) {
for _, cmd := range cmds {
switch t := cmd.(type) {
2024-09-22 15:46:38 +00:00
case SimpleJsCommand:
break
case ComplexJsCommand:
2024-09-21 03:59:07 +00:00
break
2024-09-30 17:39:48 +00:00
case *AttributeMapOrdered:
2024-09-21 03:59:07 +00:00
break
case *Element:
panic(fmt.Sprintf("element is not allowed in lifecycle events. Got: %v", t))
default:
panic(fmt.Sprintf("type is not allowed in lifecycle events. Got: %v", t))
}
}
}
func (l *LifeCycle) OnEvent(event hx.Event, cmd ...Command) *LifeCycle {
validateCommands(cmd)
2024-09-22 16:53:41 +00:00
if strings.HasPrefix(event, "htmx:") {
event = event[5:]
event = util.ConvertCamelToDash(fmt.Sprintf("hx-on::%s", event))
}
if l.handlers[event] == nil {
2024-09-21 03:59:07 +00:00
l.handlers[event] = []Command{}
}
2024-09-21 03:59:07 +00:00
l.handlers[event] = append(l.handlers[event], cmd...)
return l
}
func OnLoad(cmd ...Command) *LifeCycle {
return NewLifeCycle().OnEvent(hx.LoadDomEvent, cmd...)
}
func (l *LifeCycle) HxBeforeRequest(cmd ...Command) *LifeCycle {
2024-09-21 03:59:07 +00:00
l.OnEvent(hx.BeforeRequestEvent, cmd...)
return l
}
func (l *LifeCycle) HxBeforeWsSend(cmd ...Command) *LifeCycle {
l.OnEvent(hx.BeforeWsSendEvent, cmd...)
return l
}
func (l *LifeCycle) HxAfterWsSend(cmd ...Command) *LifeCycle {
l.OnEvent(hx.AfterWsSendEvent, cmd...)
return l
}
func HxOnLoad(cmd ...Command) *LifeCycle {
2024-09-21 03:59:07 +00:00
return NewLifeCycle().OnEvent(hx.LoadEvent, cmd...)
}
func HxOnAfterSwap(cmd ...Command) *LifeCycle {
2024-09-21 03:59:07 +00:00
return NewLifeCycle().OnEvent(hx.AfterSwapEvent, cmd...)
}
func OnClick(cmd ...Command) *LifeCycle {
return NewLifeCycle().OnEvent(hx.ClickEvent, cmd...)
}
func OnEvent(event hx.Event, cmd ...Command) *LifeCycle {
return NewLifeCycle().OnEvent(event, cmd...)
}
func HxBeforeWsSend(cmd ...Command) *LifeCycle {
return NewLifeCycle().HxBeforeWsSend(cmd...)
}
func HxAfterWsSend(cmd ...Command) *LifeCycle {
return NewLifeCycle().HxAfterWsSend(cmd...)
}
func HxBeforeRequest(cmd ...Command) *LifeCycle {
return NewLifeCycle().HxBeforeRequest(cmd...)
}
func HxAfterRequest(cmd ...Command) *LifeCycle {
return NewLifeCycle().HxAfterRequest(cmd...)
}
func HxOnMutationError(cmd ...Command) *LifeCycle {
return NewLifeCycle().HxOnMutationError(cmd...)
}
func (l *LifeCycle) HxAfterRequest(cmd ...Command) *LifeCycle {
2024-09-21 03:59:07 +00:00
l.OnEvent(hx.AfterRequestEvent, cmd...)
return l
}
func (l *LifeCycle) HxOnMutationError(cmd ...Command) *LifeCycle {
2024-09-21 03:59:07 +00:00
l.OnEvent(hx.OnMutationErrorEvent, cmd...)
return l
}
2024-09-21 03:59:07 +00:00
type Command = Ren
2024-09-22 15:46:38 +00:00
type SimpleJsCommand struct {
Command string
}
2024-09-22 15:46:38 +00:00
type ComplexJsCommand struct {
Command string
TempFuncName string
2024-09-21 03:59:07 +00:00
}
func NewComplexJsCommand(command string) ComplexJsCommand {
name := fmt.Sprintf("__eval_%s", util.RandSeq(6))
return ComplexJsCommand{Command: command, TempFuncName: name}
}
2024-09-22 15:46:38 +00:00
func SetText(text string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.innerText = '%s'", text)}
}
2024-09-29 13:21:58 +00:00
func SetTextOnChildren(selector, text string) ComplexJsCommand {
// language=JavaScript
return EvalJs(fmt.Sprintf(`
var children = self.querySelectorAll('%s');
children.forEach(function(child) {
child.innerText = '%s';
});
`, selector, text))
}
2024-09-22 15:46:38 +00:00
func Increment(amount int) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.innerText = parseInt(this.innerText) + %d", amount)}
}
2024-09-22 15:46:38 +00:00
func SetInnerHtml(r Ren) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", Render(r))}
}
2024-09-22 15:46:38 +00:00
func SetOuterHtml(r Ren) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", Render(r))}
}
2024-09-22 15:46:38 +00:00
func AddAttribute(name, value string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.setAttribute('%s', '%s')", name, value)}
}
2024-09-22 15:46:38 +00:00
func SetDisabled(disabled bool) SimpleJsCommand {
if disabled {
return AddAttribute("disabled", "true")
} else {
return RemoveAttribute("disabled")
}
}
2024-09-22 15:46:38 +00:00
func RemoveAttribute(name string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.removeAttribute('%s')", name)}
}
2024-09-22 15:46:38 +00:00
func AddClass(class string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.classList.add('%s')", class)}
}
2024-09-22 15:46:38 +00:00
func RemoveClass(class string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.classList.remove('%s')", class)}
}
2024-09-22 15:46:38 +00:00
func ToggleClass(class string) SimpleJsCommand {
2024-09-19 23:11:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("this.classList.toggle('%s')", class)}
}
2024-09-22 15:46:38 +00:00
func ToggleClassOnElement(selector, class string) ComplexJsCommand {
// language=JavaScript
return EvalJs(fmt.Sprintf(`
var el = document.querySelector('%s');
if(el) { el.classList.toggle('%s'); }`,
2024-09-22 16:25:18 +00:00
selector, class,
2024-09-22 15:46:38 +00:00
))
}
2024-09-20 20:15:12 +00:00
func EvalJsOnParent(js string) ComplexJsCommand {
2024-09-29 13:21:58 +00:00
// language=JavaScript
return EvalJs(fmt.Sprintf(`
if(!self.parentElement) { return; }
let element = self.parentElement;
%s
`, js))
2024-09-29 13:21:58 +00:00
}
func EvalJsOnChildren(selector, js string) ComplexJsCommand {
2024-09-29 13:21:58 +00:00
// language=JavaScript
return EvalJs(fmt.Sprintf(`
let children = self.querySelectorAll('%s');
children.forEach(function(element) {
%s
2024-09-29 13:21:58 +00:00
});
`, selector, js))
2024-09-29 13:21:58 +00:00
}
func EvalJsOnSibling(selector, js string) ComplexJsCommand {
2024-09-29 13:21:58 +00:00
// language=JavaScript
return EvalJs(fmt.Sprintf(`
if(!self.parentElement) { return; }
let siblings = self.parentElement.querySelectorAll('%s');
siblings.forEach(function(element) {
%s
2024-09-29 13:21:58 +00:00
});
`, selector, js))
}
2024-09-29 16:50:30 +00:00
func SetClassOnParent(class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnParent(fmt.Sprintf("element.classList.add('%s')", class))
}
func RemoveClassOnParent(class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnParent(fmt.Sprintf("element.classList.remove('%s')", class))
}
func SetClassOnChildren(selector, class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnChildren(selector, fmt.Sprintf("element.classList.add('%s')", class))
}
func SetClassOnSibling(selector, class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnSibling(selector, fmt.Sprintf("element.classList.add('%s')", class))
}
func RemoveClassOnSibling(selector, class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnSibling(selector, fmt.Sprintf("element.classList.remove('%s')", class))
2024-09-29 13:21:58 +00:00
}
func RemoveClassOnChildren(selector, class string) ComplexJsCommand {
// language=JavaScript
return EvalJsOnChildren(selector, fmt.Sprintf("element.classList.remove('%s')", class))
2024-09-29 13:21:58 +00:00
}
2024-09-22 15:46:38 +00:00
func Alert(text string) SimpleJsCommand {
2024-09-20 20:15:12 +00:00
// language=JavaScript
2024-09-22 15:46:38 +00:00
return SimpleJsCommand{Command: fmt.Sprintf("alert('%s')", text)}
}
2024-09-26 14:23:22 +00:00
func Remove() SimpleJsCommand {
// language=JavaScript
return SimpleJsCommand{Command: "this.remove()"}
}
2024-09-22 15:46:38 +00:00
func EvalJs(js string) ComplexJsCommand {
return NewComplexJsCommand(js)
2024-09-22 15:46:38 +00:00
}
func SetValue(value string) SimpleJsCommand {
// language=JavaScript
return SimpleJsCommand{Command: fmt.Sprintf("this.value = '%s'", value)}
}
2024-09-29 13:47:39 +00:00
func SubmitFormOnEnter() ComplexJsCommand {
// language=JavaScript
return EvalJs(`
if (event.code === 'Enter') {
self.form.dispatchEvent(new Event('submit', { cancelable: true }));
}
`)
}
2024-09-22 15:46:38 +00:00
func InjectScript(src string) ComplexJsCommand {
// language=JavaScript
return NewComplexJsCommand(fmt.Sprintf(`
2024-09-20 20:15:12 +00:00
var script = document.createElement('script');
script.src = '%s';
script.async = true;
2024-09-20 20:15:12 +00:00
document.head.appendChild(script);
`, src))
2024-09-20 20:15:12 +00:00
}
2024-09-22 15:46:38 +00:00
func InjectScriptIfNotExist(src string) ComplexJsCommand {
// language=JavaScript
return EvalJs(fmt.Sprintf(`
if(!document.querySelector('script[src="%s"]')) {
var script = document.createElement('script');
script.src = '%s';
script.async = true;
document.head.appendChild(script);
}
`, src, src))
}