jsonscript.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package templ
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. )
  8. var _ Component = JSONScriptElement{}
  9. // JSONScript renders a JSON object inside a script element.
  10. // e.g. <script type="application/json">{"foo":"bar"}</script>
  11. func JSONScript(id string, data any) JSONScriptElement {
  12. return JSONScriptElement{
  13. ID: id,
  14. Type: "application/json",
  15. Data: data,
  16. Nonce: GetNonce,
  17. }
  18. }
  19. // WithType sets the value of the type attribute of the script element.
  20. func (j JSONScriptElement) WithType(t string) JSONScriptElement {
  21. j.Type = t
  22. return j
  23. }
  24. // WithNonceFromString sets the value of the nonce attribute of the script element to the given string.
  25. func (j JSONScriptElement) WithNonceFromString(nonce string) JSONScriptElement {
  26. j.Nonce = func(context.Context) string {
  27. return nonce
  28. }
  29. return j
  30. }
  31. // WithNonceFrom sets the value of the nonce attribute of the script element to the value returned by the given function.
  32. func (j JSONScriptElement) WithNonceFrom(f func(context.Context) string) JSONScriptElement {
  33. j.Nonce = f
  34. return j
  35. }
  36. type JSONScriptElement struct {
  37. // ID of the element in the DOM.
  38. ID string
  39. // Type of the script element, defaults to "application/json".
  40. Type string
  41. // Data that will be encoded as JSON.
  42. Data any
  43. // Nonce is a function that returns a CSP nonce.
  44. // Defaults to CSPNonceFromContext.
  45. // See https://content-security-policy.com/nonce for more information.
  46. Nonce func(ctx context.Context) string
  47. }
  48. func (j JSONScriptElement) Render(ctx context.Context, w io.Writer) (err error) {
  49. if _, err = io.WriteString(w, "<script"); err != nil {
  50. return err
  51. }
  52. if j.ID != "" {
  53. if _, err = fmt.Fprintf(w, " id=\"%s\"", EscapeString(j.ID)); err != nil {
  54. return err
  55. }
  56. }
  57. if j.Type != "" {
  58. if _, err = fmt.Fprintf(w, " type=\"%s\"", EscapeString(j.Type)); err != nil {
  59. return err
  60. }
  61. }
  62. if nonce := j.Nonce(ctx); nonce != "" {
  63. if _, err = fmt.Fprintf(w, " nonce=\"%s\"", EscapeString(nonce)); err != nil {
  64. return err
  65. }
  66. }
  67. if _, err = io.WriteString(w, ">"); err != nil {
  68. return err
  69. }
  70. if err = json.NewEncoder(w).Encode(j.Data); err != nil {
  71. return err
  72. }
  73. if _, err = io.WriteString(w, "</script>"); err != nil {
  74. return err
  75. }
  76. return nil
  77. }