2024-06-06 00:13:12 +03:00
|
|
|
package htmlx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/d5/tengo/v2"
|
|
|
|
"strings"
|
|
|
|
"html"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
const RawTag = "raw"
|
|
|
|
|
|
|
|
// The type implements basic
|
|
|
|
// way to structrize HTML elements.
|
|
|
|
type Element struct {
|
|
|
|
tengo.ObjectImpl
|
|
|
|
Tag string
|
|
|
|
Attr map[string] string
|
|
|
|
Children []*Element
|
|
|
|
// The value makes sense only if
|
|
|
|
// the tag is the "raw"
|
|
|
|
Content string
|
2024-06-09 19:42:20 +03:00
|
|
|
Final bool
|
2024-06-06 00:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (el *Element) TypeName() string {
|
|
|
|
return "*HTMLElement"
|
|
|
|
}
|
|
|
|
|
|
|
|
// The method renders the element to it's
|
|
|
|
// HTML representation.
|
|
|
|
func (el *Element) String() string {
|
|
|
|
if el.Tag == RawTag {
|
|
|
|
return html.EscapeString(el.Content)
|
|
|
|
}
|
|
|
|
|
|
|
|
var b strings.Builder
|
|
|
|
|
|
|
|
fmt.Fprintf(&b, "<%s", el.Tag)
|
|
|
|
for k, v := range el.Attr {
|
|
|
|
fmt.Fprintf(&b, " %s=%q", k, v)
|
|
|
|
}
|
|
|
|
fmt.Fprint(&b, ">")
|
|
|
|
|
2024-06-09 19:42:20 +03:00
|
|
|
if el.Final {
|
|
|
|
return b.String()
|
|
|
|
}
|
|
|
|
|
2024-06-06 00:13:12 +03:00
|
|
|
for _, child := range el.Children {
|
|
|
|
if child == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fmt.Fprint(&b, child.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(&b, "</%s>", el.Tag)
|
|
|
|
return b.String()
|
|
|
|
}
|
|
|
|
|
2024-06-09 19:42:20 +03:00
|
|
|
func MakeElements(args ...tengo.Object) ([]*Element, error) {
|
|
|
|
s := []*Element{}
|
|
|
|
for _, arg := range args {
|
|
|
|
el, ok := arg.(*Element)
|
|
|
|
if !ok {
|
|
|
|
str, ok := tengo.ToString(arg)
|
2024-06-09 19:47:30 +03:00
|
|
|
if ok {
|
|
|
|
s = append(s, &Element{
|
|
|
|
Tag: RawTag,
|
|
|
|
Content: str,
|
|
|
|
})
|
2024-06-09 19:42:20 +03:00
|
|
|
}
|
2024-06-09 19:47:30 +03:00
|
|
|
continue
|
2024-06-09 19:42:20 +03:00
|
|
|
}
|
|
|
|
s = append(s, el)
|
|
|
|
}
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (el *Element) SetBody(
|
|
|
|
args ...tengo.Object,
|
|
|
|
) (tengo.Object, error) {
|
|
|
|
els, err := MakeElements(args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-06-06 00:13:12 +03:00
|
|
|
el.Children = els
|
2024-06-09 19:42:20 +03:00
|
|
|
return el, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (el *Element) Add(
|
|
|
|
args ...tengo.Object,
|
|
|
|
) (tengo.Object, error) {
|
|
|
|
s, err := MakeElements(args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
el.Children = append(el.Children, s...)
|
|
|
|
return el, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (el *Element) SetFinal(
|
|
|
|
args ...tengo.Object,
|
|
|
|
) (tengo.Object, error) {
|
|
|
|
if len(args) > 0 {
|
|
|
|
return nil, tengo.ErrWrongNumArguments
|
|
|
|
}
|
|
|
|
el.Final = true
|
|
|
|
return el, nil
|
2024-06-06 00:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (el *Element) IndexGet(
|
|
|
|
index tengo.Object,
|
|
|
|
) (tengo.Object, error) {
|
|
|
|
arg, ok := tengo.ToString(index)
|
|
|
|
if !ok {
|
|
|
|
return nil, tengo.ErrInvalidIndexValueType
|
|
|
|
}
|
|
|
|
|
|
|
|
switch arg {
|
|
|
|
case "body" :
|
|
|
|
return &tengo.UserFunction{
|
2024-06-09 19:42:20 +03:00
|
|
|
Name: "element.body",
|
|
|
|
Value: el.SetBody,
|
|
|
|
}, nil
|
|
|
|
case "final" :
|
|
|
|
return &tengo.UserFunction{
|
|
|
|
Name: "element.final",
|
|
|
|
Value: el.SetFinal,
|
|
|
|
}, nil
|
|
|
|
case "add" :
|
|
|
|
return &tengo.UserFunction{
|
|
|
|
Name: "element.add",
|
|
|
|
Value: el.Add,
|
2024-06-06 00:13:12 +03:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|