From cd8d08c0a542afb34122fc426eabf2ff0581e46f Mon Sep 17 00:00:00 2001 From: maddalax Date: Tue, 29 Oct 2024 07:08:44 -0500 Subject: [PATCH] scripting enhancements --- framework/h/lifecycle.go | 103 +++++++++++++++++- framework/h/renderer.go | 36 ++++-- framework/js/commands.go | 9 ++ htmgo-site/pages/examples/examples.go | 22 ++++ .../examples/js-hide-children-on-click.go | 10 ++ .../pages/examples/js-set-text-on-click.go | 10 ++ .../snippets/js-hide-children-on-click.go | 32 ++++++ .../partials/snippets/js-set-text-on-click.go | 18 +++ 8 files changed, 229 insertions(+), 11 deletions(-) create mode 100644 htmgo-site/pages/examples/js-hide-children-on-click.go create mode 100644 htmgo-site/pages/examples/js-set-text-on-click.go create mode 100644 htmgo-site/partials/snippets/js-hide-children-on-click.go create mode 100644 htmgo-site/partials/snippets/js-set-text-on-click.go diff --git a/framework/h/lifecycle.go b/framework/h/lifecycle.go index b1e4fee..1a31853 100644 --- a/framework/h/lifecycle.go +++ b/framework/h/lifecycle.go @@ -2,6 +2,7 @@ package h import ( "fmt" + "github.com/google/uuid" "github.com/maddalax/htmgo/framework/hx" "github.com/maddalax/htmgo/framework/internal/util" "strings" @@ -233,6 +234,54 @@ func ToggleClass(class string) SimpleJsCommand { return SimpleJsCommand{Command: fmt.Sprintf("this.classList.toggle('%s')", class)} } +// ToggleText toggles the given text on the element. +func ToggleText(text string, textTwo string) Command { + // language=JavaScript + return EvalJs(fmt.Sprintf(` + if(self.innerText === "%s") { + self.innerText = "%s"; + } else { + self.innerText = "%s"; + } + `, text, textTwo, text)) +} + +// ToggleTextOnSibling toggles the given text on the siblings of the element. +func ToggleTextOnSibling(selector, text string, textTwo string) Command { + // language=JavaScript + return EvalJsOnSibling(selector, fmt.Sprintf(` + if(element.innerText === "%s") { + element.innerText = "%s"; + } else { + element.innerText = "%s"; + } + `, text, textTwo, text)) +} + +// ToggleTextOnChildren toggles the given text on the children of the element. +func ToggleTextOnChildren(selector, text string, textTwo string) Command { + // language=JavaScript + return EvalJsOnChildren(selector, fmt.Sprintf(` + if(element.innerText === "%s") { + element.innerText = "%s"; + } else { + element.innerText = "%s"; + } + `, text, textTwo, text)) +} + +// ToggleTextOnParent toggles the given text on the parent of the element. +func ToggleTextOnParent(text string, textTwo string) Command { + // language=JavaScript + return EvalJsOnParent(fmt.Sprintf(` + if(element.innerText === "%s") { + element.innerText = "%s"; + } else { + element.innerText = "%s"; + } + `, text, textTwo, text)) +} + // ToggleClassOnElement toggles the given class on the elements returned by the selector. func ToggleClassOnElement(selector, class string) ComplexJsCommand { // language=JavaScript @@ -276,24 +325,42 @@ func EvalJsOnSibling(selector, js string) ComplexJsCommand { `, selector, js)) } -// SetClassOnParent sets the given class on the parent of the element. Reference the element using 'element'. +// SetClassOnParent sets the given class on the parent of the element. func SetClassOnParent(class string) ComplexJsCommand { // language=JavaScript return EvalJsOnParent(fmt.Sprintf("element.classList.add('%s')", class)) } -// RemoveClassOnParent removes the given class from the parent of the element. Reference the element using 'element'. +// RemoveClassOnParent removes the given class from the parent of the element. func RemoveClassOnParent(class string) ComplexJsCommand { // language=JavaScript return EvalJsOnParent(fmt.Sprintf("element.classList.remove('%s')", class)) } -// SetClassOnChildren sets the given class on the children of the element. Reference the element using 'element'. +// SetClassOnChildren sets the given class on the children of the element. func SetClassOnChildren(selector, class string) ComplexJsCommand { // language=JavaScript return EvalJsOnChildren(selector, fmt.Sprintf("element.classList.add('%s')", class)) } +// ToggleClassOnChildren toggles the given class on the children of the element. +func ToggleClassOnChildren(selector, class string) ComplexJsCommand { + // language=JavaScript + return EvalJsOnChildren(selector, fmt.Sprintf("element.classList.toggle('%s')", class)) +} + +// ToggleClassOnParent toggles the given class on the parent of the element. +func ToggleClassOnParent(class string) ComplexJsCommand { + // language=JavaScript + return EvalJsOnParent(fmt.Sprintf("element.classList.toggle('%s')", class)) +} + +// ToggleClassOnSibling toggles the given class on the siblings of the element. +func ToggleClassOnSibling(selector, class string) ComplexJsCommand { + // language=JavaScript + return EvalJsOnSibling(selector, fmt.Sprintf("element.classList.toggle('%s')", class)) +} + // SetClassOnSibling sets the given class on the siblings of the element. Reference the element using 'element'. func SetClassOnSibling(selector, class string) ComplexJsCommand { // language=JavaScript @@ -330,6 +397,36 @@ func EvalJs(js string) ComplexJsCommand { return NewComplexJsCommand(js) } +func EvalCommandsOnSelector(selector string, cmds ...Command) ComplexJsCommand { + lines := make([]string, len(cmds)) + for i, cmd := range cmds { + lines[i] = Render(cmd) + lines[i] = strings.ReplaceAll(lines[i], "this.", "self.") + // some commands set the element we need to fix it so we arent redeclaring it + lines[i] = strings.ReplaceAll(lines[i], "let element =", "element =") + } + code := strings.Join(lines, "\n") + return EvalJs(fmt.Sprintf(` + let element = document.querySelector("%s"); + + if(!element) { + return; + } + + self = element; + %s + `, selector, code)) +} + +func EvalCommands(element *Element, cmds ...Command) ComplexJsCommand { + id := strings.ReplaceAll(uuid.NewString(), "-", "") + element.AppendChildren( + Attribute("data-eval-commands-id", id), + ) + return EvalCommandsOnSelector( + fmt.Sprintf(`[data-eval-commands-id='%s']`, id), cmds...) +} + // PreventDefault prevents the default action of the event. func PreventDefault() SimpleJsCommand { // language=JavaScript diff --git a/framework/h/renderer.go b/framework/h/renderer.go index 83efa4f..b0969a9 100644 --- a/framework/h/renderer.go +++ b/framework/h/renderer.go @@ -35,9 +35,15 @@ var voidTags = map[string]bool{ "wbr": true, } +type ScriptEntry struct { + Body string + ChildOf *Element +} + type RenderContext struct { - builder *strings.Builder - scripts []string + builder *strings.Builder + scripts []ScriptEntry + currentElement *Element } func (ctx *RenderContext) AddScript(funcName string, body string) { @@ -48,7 +54,11 @@ func (ctx *RenderContext) AddScript(funcName string, body string) { %s } `, funcName, funcName, body) - ctx.scripts = append(ctx.scripts, script) + + ctx.scripts = append(ctx.scripts, ScriptEntry{ + Body: script, + ChildOf: ctx.currentElement, + }) } func (node *Element) Render(context *RenderContext) { @@ -56,6 +66,8 @@ func (node *Element) Render(context *RenderContext) { return } + context.currentElement = node + if node.tag == CachedNodeTag { meta := node.meta.(*CachedNode) meta.Render(context) @@ -147,7 +159,7 @@ func (node *Element) Render(context *RenderContext) { } if node.tag != "" { - renderScripts(context) + renderScripts(context, node) if !voidTags[node.tag] { context.builder.WriteString("