@@ -3,6 +3,7 @@ package bind
33import (
44 "errors"
55 "fmt"
6+ "html"
67 "html/template"
78
89 "github.com/linkdata/jaws"
@@ -27,6 +28,12 @@ type SetHook[T comparable] func(bind Binder[T], elem *jaws.Element, value T) (er
2728// want to call it's JawsGetLocked first.
2829type GetHook [T comparable ] func (bind Binder [T ], elem * jaws.Element ) (value T )
2930
31+ // GetHTMLHook is a function to call when JawsGetHTML() is called.
32+ //
33+ // The lock will be held before calling the function, preferring RLock over Lock, if available.
34+ // Do not lock or unlock the Binder in the function. Do not call JawsGet.
35+ type GetHTMLHook [T comparable ] func (bind Binder [T ], elem * jaws.Element ) (s template.HTML )
36+
3037// ClickedHook is a function to call when a click event is received.
3138//
3239// The Binder locks are not held when the function is called.
@@ -46,16 +53,10 @@ type ContextMenuHook[T comparable] func(bind Binder[T], elem *jaws.Element, clic
4653// no more success hooks are called.
4754type SuccessHook func (* jaws.Element ) (err error )
4855
49- type Formatter interface {
50- // Format returns a Getter[string] using fmt.Sprintf(f, JawsGet[T](elem))
51- Format (f string ) (getter Getter [string ])
52- }
53-
5456type Binder [T comparable ] interface {
5557 RWLocker
5658 Setter [T ]
5759 jtag.TagGetter
58- Formatter
5960 jaws.ClickHandler
6061 jaws.ContextMenuHandler
6162
@@ -91,8 +92,12 @@ type Binder[T comparable] interface {
9192 // * func(*Element) error
9293 Success (fn any ) (newbind Binder [T ])
9394
94- // FormatHTML returns a HTMLGetter using fmt.Sprintf(f, JawsGet[T](elem))
95- FormatHTML (f string ) (getter HTMLGetter )
95+ // GetHTML returns a Binder[T] that will call fn instead of the default
96+ // escaped fmt.Sprintf("%v", JawsGetLocked(elem)) HTML rendering.
97+ //
98+ // The lock will be held at this point, preferring RLock over Lock, if available.
99+ // Do not lock or unlock the Binder within fn. Do not call JawsGet.
100+ GetHTML (fn GetHTMLHook [T ]) (newbind Binder [T ])
96101
97102 // Clicked returns a Binder[T] that will call fn when JawsClick is invoked.
98103 //
@@ -110,7 +115,7 @@ type binder[T comparable] struct {
110115 prev * binder [T ]
111116 RWLocker
112117 ptr * T
113- hook any // one of: BindGetHook [T] BindSetHook [T] BindClickedHook [T] BindContextMenuHook [T] BindSuccessHook
118+ hook any // one of: SetHook [T] GetHook [T] GetHTMLHook [T] ClickedHook [T] ContextMenuHook[T] SuccessHook
114119}
115120
116121func (bind * binder [T ]) walk (fn func (* binder [T ]) bool ) bool {
@@ -140,6 +145,24 @@ func (bind *binder[T]) JawsGet(elem *jaws.Element) (value T) {
140145 return
141146}
142147
148+ func (bind * binder [T ]) jawsGetHTMLLocked (elem * jaws.Element ) (s template.HTML ) {
149+ if fn , ok := bind .hook .(GetHTMLHook [T ]); ok {
150+ s = fn (bind .prev , elem )
151+ } else if bind .prev != nil {
152+ s = bind .prev .jawsGetHTMLLocked (elem )
153+ } else {
154+ s = template .HTML (html .EscapeString (fmt .Sprintf ("%v" , * bind .ptr ))) // #nosec G203
155+ }
156+ return
157+ }
158+
159+ func (bind * binder [T ]) JawsGetHTML (elem * jaws.Element ) (s template.HTML ) {
160+ bind .RWLocker .RLock ()
161+ defer bind .RWLocker .RUnlock ()
162+ s = bind .jawsGetHTMLLocked (elem )
163+ return
164+ }
165+
143166func (bind * binder [T ]) JawsSetLocked (elem * jaws.Element , value T ) (err error ) {
144167 if fn , ok := bind .hook .(SetHook [T ]); ok {
145168 err = fn (bind .prev , elem , value )
@@ -241,6 +264,20 @@ func (bind *binder[T]) GetLocked(fn GetHook[T]) Binder[T] {
241264 }
242265}
243266
267+ // GetHTML returns a Binder[T] that will call fn instead of the default escaped
268+ // fmt.Sprintf("%v", JawsGetLocked(elem)) HTML rendering.
269+ //
270+ // The lock will be held at this point, preferring RLock over Lock, if available.
271+ // Do not lock or unlock the Binder within fn. Do not call JawsGet.
272+ func (bind * binder [T ]) GetHTML (fn GetHTMLHook [T ]) Binder [T ] {
273+ return & binder [T ]{
274+ prev : bind ,
275+ RWLocker : bind .RWLocker ,
276+ ptr : bind .ptr ,
277+ hook : fn ,
278+ }
279+ }
280+
244281// Clicked returns a Binder[T] that will call fn when JawsClick is invoked.
245282//
246283// The Binder locks are not held when the function is called.
@@ -283,19 +320,6 @@ func (bind *binder[T]) Success(fn any) Binder[T] {
283320 }
284321}
285322
286- // Format returns a Getter[string] using fmt.Sprintf(f, JawsGet[T](elem))
287- func (bind * binder [T ]) Format (f string ) (getter Getter [string ]) {
288- return StringGetterFunc (func (elem * jaws.Element ) (s string ) { return fmt .Sprintf (f , bind .JawsGet (elem )) }, bind )
289- }
290-
291- // FormatHTML returns a HTMLGetter using fmt.Sprintf(f, JawsGet[T](elem)).
292- // Ensure that the generated string is valid HTML.
293- func (bind * binder [T ]) FormatHTML (f string ) (getter HTMLGetter ) {
294- return HTMLGetterFunc (func (elem * jaws.Element ) (tmpl template.HTML ) {
295- return template .HTML ( /*#nosec G203*/ fmt .Sprintf (f , bind .JawsGet (elem )))
296- }, bind )
297- }
298-
299323func wrapSuccessHook (fn any ) (hook SuccessHook ) {
300324 switch fn := fn .(type ) {
301325 case func ():
0 commit comments