page_injector.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package web
  2. import (
  3. "fmt"
  4. h "github.com/theplant/htmlgo"
  5. )
  6. type headKey int
  7. const (
  8. titleKey headKey = iota
  9. )
  10. type MetaKey string
  11. type keyComp struct {
  12. key interface{}
  13. comp h.HTMLComponent
  14. }
  15. type PageInjector struct {
  16. skipDefaultSetting bool
  17. comps map[injectPosition][]*keyComp
  18. lang string
  19. }
  20. type injectPosition int
  21. const (
  22. head injectPosition = iota
  23. tail
  24. extra
  25. )
  26. func (b *PageInjector) putComp(key interface{}, comp h.HTMLComponent, pos injectPosition, replace bool) {
  27. if b.comps == nil {
  28. b.comps = make(map[injectPosition][]*keyComp)
  29. }
  30. for _, h := range b.comps[pos] {
  31. if h.key == key {
  32. if !replace {
  33. return
  34. }
  35. h.comp = comp
  36. return
  37. }
  38. }
  39. b.comps[pos] = append(b.comps[pos], &keyComp{key: key, comp: comp})
  40. }
  41. func (b *PageInjector) getComp(key interface{}, pos injectPosition) *keyComp {
  42. for _, h := range b.comps[pos] {
  43. if h.key == key {
  44. return h
  45. }
  46. }
  47. return nil
  48. }
  49. // SkipDefaultSetting skips the setting of default nodes
  50. func (b *PageInjector) SkipDefaultSetting() {
  51. b.skipDefaultSetting = true
  52. }
  53. func (b *PageInjector) setDefault(pageTitle string) {
  54. if b.skipDefaultSetting {
  55. return
  56. }
  57. if !b.HasTitle() && len(pageTitle) > 0 {
  58. b.Title(pageTitle)
  59. }
  60. if b.getComp(MetaKey("charset"), head) == nil {
  61. b.Meta(MetaKey("charset"), "charset", "utf8")
  62. }
  63. if b.getComp(MetaKey("viewport"), head) == nil {
  64. b.MetaNameContent("viewport", "width=device-width, initial-scale=1, shrink-to-fit=no")
  65. }
  66. }
  67. func (b *PageInjector) Title(title string) {
  68. b.addNode(h.Title(""), titleKey, true, title)
  69. return
  70. }
  71. func (b *PageInjector) HasTitle() (r bool) {
  72. return b.getComp(titleKey, head) != nil
  73. }
  74. func (b *PageInjector) MetaNameContent(name, content string) {
  75. b.Meta(MetaKey(name), "name", name, "content", content)
  76. return
  77. }
  78. func (b *PageInjector) Meta(key interface{}, attrs ...string) {
  79. b.addNode(h.Meta(), key, true, "", attrs...)
  80. return
  81. }
  82. func (b *PageInjector) TailHTML(v string) {
  83. b.TailHTMLComponent(v, h.RawHTML(v), true)
  84. return
  85. }
  86. func (b *PageInjector) TailHTMLComponent(key interface{}, comp h.HTMLComponent, replace bool) {
  87. b.putComp(key, comp, tail, replace)
  88. return
  89. }
  90. func (b *PageInjector) Clear() (r *PageInjector) {
  91. b.comps = make(map[injectPosition][]*keyComp)
  92. return b
  93. }
  94. func (b *PageInjector) HeadHTML(v string) {
  95. b.HeadHTMLComponent(v, h.RawHTML(v), true)
  96. return
  97. }
  98. func (b *PageInjector) HeadHTMLComponent(key interface{}, comp h.HTMLComponent, replace bool) {
  99. b.putComp(key, comp, head, replace)
  100. return
  101. }
  102. func toHTMLComponent(list []*keyComp) h.HTMLComponent {
  103. var r []h.HTMLComponent
  104. for _, h := range list {
  105. r = append(r, h.comp)
  106. }
  107. return h.Components(r...)
  108. }
  109. func (b *PageInjector) GetHeadHTMLComponent() h.HTMLComponent {
  110. return toHTMLComponent(b.comps[head])
  111. }
  112. func (b *PageInjector) GetTailHTMLComponent() h.HTMLComponent {
  113. return toHTMLComponent(b.comps[tail])
  114. }
  115. func (b *PageInjector) GetExtraHTMLComponent() h.HTMLComponent {
  116. return toHTMLComponent(b.comps[extra])
  117. }
  118. func (b *PageInjector) HTMLLang(lang string) {
  119. b.lang = lang
  120. return
  121. }
  122. func (b *PageInjector) GetHTMLLang() string {
  123. return b.lang
  124. }
  125. func (b *PageInjector) addNode(tag *h.HTMLTagBuilder, key interface{}, replace bool, body string, attrs ...string) {
  126. l := len(attrs)
  127. if l%2 != 0 {
  128. panic(fmt.Sprintf("attrs should be pairs: %+v, length: %d", attrs, l))
  129. }
  130. for i := 0; i < l; i = i + 2 {
  131. tag.Attr(attrs[i], attrs[i+1])
  132. }
  133. if len(body) > 0 {
  134. tag.Text(body)
  135. }
  136. b.putComp(key, tag, head, replace)
  137. }