| 319 | } |
| 320 | |
| 321 | func Bind(htmlStr string, params map[string]any) *VDomElem { |
| 322 | htmlStr = processWhitespace(htmlStr) |
| 323 | r := strings.NewReader(htmlStr) |
| 324 | iter := htmltoken.NewTokenizer(r) |
| 325 | var elemStack []*VDomElem |
| 326 | elemStack = append(elemStack, &VDomElem{Tag: FragmentTag}) |
| 327 | var tokenErr error |
| 328 | outer: |
| 329 | for { |
| 330 | tokenType := iter.Next() |
| 331 | token := iter.Token() |
| 332 | switch tokenType { |
| 333 | case htmltoken.StartTagToken: |
| 334 | if token.Data == Html_BindTagName || token.Data == Html_BindParamTagName { |
| 335 | tokenErr = errors.New("bind tags must be self closing") |
| 336 | break outer |
| 337 | } |
| 338 | elem := tokenToElem(token, params) |
| 339 | elemStack = pushElemStack(elemStack, elem) |
| 340 | case htmltoken.EndTagToken: |
| 341 | if token.Data == Html_BindTagName || token.Data == Html_BindParamTagName { |
| 342 | tokenErr = errors.New("bind tags must be self closing") |
| 343 | break outer |
| 344 | } |
| 345 | if len(elemStack) <= 1 { |
| 346 | tokenErr = fmt.Errorf("end tag %q without start tag", token.Data) |
| 347 | break outer |
| 348 | } |
| 349 | if curElemTag(elemStack) != token.Data { |
| 350 | tokenErr = fmt.Errorf("end tag %q does not match start tag %q", token.Data, curElemTag(elemStack)) |
| 351 | break outer |
| 352 | } |
| 353 | elemStack = popElemStack(elemStack) |
| 354 | case htmltoken.SelfClosingTagToken: |
| 355 | if token.Data == Html_BindParamTagName { |
| 356 | keyAttr := getAttrString(token, "key") |
| 357 | dataVal := params[keyAttr] |
| 358 | elemList := partToElems(dataVal) |
| 359 | for _, elem := range elemList { |
| 360 | appendChildToStack(elemStack, &elem) |
| 361 | } |
| 362 | continue |
| 363 | } |
| 364 | if token.Data == Html_BindTagName { |
| 365 | keyAttr := getAttrString(token, "key") |
| 366 | binding := &VDomBinding{Type: ObjectType_Binding, Bind: keyAttr} |
| 367 | appendChildToStack(elemStack, &VDomElem{Tag: WaveTextTag, Props: map[string]any{"text": binding}}) |
| 368 | continue |
| 369 | } |
| 370 | elem := tokenToElem(token, params) |
| 371 | appendChildToStack(elemStack, elem) |
| 372 | case htmltoken.TextToken: |
| 373 | if token.Data == "" { |
| 374 | continue |
| 375 | } |
| 376 | textStr := processTextStr(token.Data) |
| 377 | if textStr == "" { |
| 378 | continue |