The reconcile package is used for DOM reconcilation in Isomorphic Go web applications.

domnode.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // The UXToolkit Project
  2. // Copyright (c) Wirecog, LLC. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license, which can be found in the LICENSE file.
  5. package reconcile
  6. import (
  7. "html"
  8. "strconv"
  9. "honnef.co/go/js/dom"
  10. )
  11. const (
  12. ElementNodeType = iota
  13. CommentNodeType
  14. TextNodeType
  15. )
  16. type Positions struct {
  17. startPosition int
  18. innerStartPosition int
  19. endPosition int
  20. innerEndPosition int
  21. }
  22. type Attribute struct {
  23. Name string
  24. Value string
  25. }
  26. type DOMNode struct {
  27. Positions
  28. NodeType int
  29. Position []int
  30. ParentNode *DOMNode
  31. ChildNodes []*DOMNode
  32. Contents []byte
  33. Name string
  34. Value []byte
  35. IsSelfClosing bool
  36. Attributes []Attribute
  37. tree *ParseTree
  38. }
  39. func NewDOMNode(nodeType int) *DOMNode {
  40. result := &DOMNode{}
  41. result.innerEndPosition = -1
  42. if nodeType == ElementNodeType {
  43. result.NodeType = ElementNodeType
  44. } else if nodeType == CommentNodeType {
  45. result.NodeType = CommentNodeType
  46. } else if nodeType == TextNodeType {
  47. result.NodeType = TextNodeType
  48. }
  49. return result
  50. }
  51. func (dn *DOMNode) Create() dom.Node {
  52. var result dom.Node = nil
  53. d := dom.GetWindow().Document()
  54. if dn.NodeType == CommentNodeType {
  55. element := d.Underlying().Call("createComment", string(dn.Value))
  56. result = dom.WrapNode(element)
  57. } else if dn.NodeType == TextNodeType {
  58. result = d.CreateTextNode(string(dn.Value))
  59. } else if dn.NodeType == ElementNodeType {
  60. element := d.CreateElement(dn.Name)
  61. for _, attribute := range dn.Attributes {
  62. element.SetAttribute(attribute.Name, attribute.Value)
  63. }
  64. element.SetInnerHTML(string(dn.GetHTMLContents(true)))
  65. result = element
  66. }
  67. return result
  68. }
  69. func (dn *DOMNode) Locate(rootElement dom.Element) dom.Node {
  70. result := rootElement.ChildNodes()[dn.Position[0]]
  71. for _, index := range dn.Position[1:] {
  72. result = result.ChildNodes()[index]
  73. }
  74. return result
  75. }
  76. func (dn *DOMNode) IsEqual(b DOMNode) bool {
  77. if dn.NodeType != b.NodeType {
  78. return false
  79. }
  80. if dn.NodeType == TextNodeType || dn.NodeType == CommentNodeType {
  81. if string(dn.Value) != string(b.Value) {
  82. return false
  83. } else {
  84. return true
  85. }
  86. }
  87. if dn.NodeType == ElementNodeType {
  88. if dn.Name != b.Name {
  89. return false
  90. }
  91. attrs := dn.Attributes
  92. otherAttrs := b.Attributes
  93. if len(attrs) != len(otherAttrs) {
  94. return false
  95. }
  96. for i, attr := range attrs {
  97. otherAttr := otherAttrs[i]
  98. if attr != otherAttr {
  99. return false
  100. }
  101. }
  102. return true
  103. }
  104. return false
  105. }
  106. func (dn *DOMNode) GetHTMLContents(innerContentsOnly bool) []byte {
  107. if dn.IsSelfClosing == true {
  108. return nil
  109. } else {
  110. contents := string(dn.tree.src[dn.innerStartPosition:dn.innerEndPosition])
  111. return []byte(html.UnescapeString(contents))
  112. }
  113. }
  114. func (dn *DOMNode) AttributesMap() map[string]string {
  115. var result map[string]string
  116. if dn.NodeType == ElementNodeType {
  117. result = make(map[string]string)
  118. for _, attribute := range dn.Attributes {
  119. result[attribute.Name] = attribute.Value
  120. }
  121. } else {
  122. result = nil
  123. }
  124. return result
  125. }
  126. func (dn *DOMNode) String() string {
  127. s := "### DOMNODE ###\n"
  128. s += "name: " + dn.Name + "\n"
  129. s += "innerStartPosition: " + strconv.Itoa(dn.innerStartPosition) + "\n"
  130. s += "innerEndPosition: " + strconv.Itoa(dn.innerEndPosition) + "\n"
  131. return s
  132. }