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

reconcile.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. "errors"
  8. "honnef.co/go/js/dom"
  9. )
  10. const (
  11. SetNodeAttributeAction = iota
  12. RemoveNodeAttributeAction
  13. RemoveNodeAction
  14. ReplaceNodeAction
  15. AppendChildNodeAction
  16. )
  17. type ReconcileParams struct {
  18. }
  19. type Reconciler struct {
  20. ActionType int
  21. ParentNode *DOMNode
  22. ChildNode *DOMNode
  23. ExistingNode *DOMNode
  24. NewNode *DOMNode
  25. AttributeName string
  26. AttributeValue string
  27. }
  28. func (r *Reconciler) ApplyChange(rootElement dom.Element) error {
  29. switch r.ActionType {
  30. case SetNodeAttributeAction:
  31. r.SetNodeAttribute(rootElement)
  32. case RemoveNodeAttributeAction:
  33. r.RemoveNodeAttribute(rootElement)
  34. case RemoveNodeAction:
  35. r.RemoveNode(rootElement)
  36. case ReplaceNodeAction:
  37. r.ReplaceNode(rootElement)
  38. case AppendChildNodeAction:
  39. r.AppendChildNode(rootElement)
  40. default:
  41. return errors.New("Unknown action")
  42. }
  43. return nil
  44. }
  45. type Changes []Reconciler
  46. func (r *Reconciler) AppendChildNode(rootElement dom.Element) {
  47. var parent dom.Node
  48. if r.ParentNode != nil {
  49. parent = r.ParentNode.Locate(rootElement)
  50. } else {
  51. parent = rootElement
  52. }
  53. child := r.ChildNode.Create()
  54. parent.AppendChild(child)
  55. }
  56. func (r *Reconciler) ReplaceNode(rootElement dom.Element) {
  57. var parent dom.Node
  58. if r.ExistingNode.ParentNode != nil {
  59. parent = r.ExistingNode.ParentNode.Locate(rootElement)
  60. } else {
  61. parent = rootElement
  62. }
  63. existingNode := r.ExistingNode.Locate(rootElement)
  64. newNode := r.NewNode.Create()
  65. parent.ReplaceChild(newNode, existingNode)
  66. }
  67. func (r *Reconciler) RemoveNode(rootElement dom.Element) {
  68. var parent dom.Node
  69. if r.ExistingNode.ParentNode != nil {
  70. parent = r.ExistingNode.ParentNode.Locate(rootElement)
  71. } else {
  72. parent = rootElement
  73. }
  74. self := r.ExistingNode.Locate(rootElement)
  75. parent.RemoveChild(self)
  76. if r.ExistingNode.ParentNode != nil {
  77. lastIndex := r.ExistingNode.Position[len(r.ExistingNode.Position)-1]
  78. for _, sibling := range r.ExistingNode.ParentNode.ChildNodes[lastIndex:] {
  79. switch sibling.NodeType {
  80. case ElementNodeType:
  81. sibling.Position[len(sibling.Position)-1] = sibling.Position[len(sibling.Position)-1] - 1
  82. case TextNodeType:
  83. sibling.Position[len(sibling.Position)-1] = sibling.Position[len(sibling.Position)-1] - 1
  84. case CommentNodeType:
  85. sibling.Position[len(sibling.Position)-1] = sibling.Position[len(sibling.Position)-1] - 1
  86. default:
  87. panic("Undetermined Node Type!")
  88. }
  89. }
  90. }
  91. }
  92. func (r *Reconciler) RemoveNodeAttribute(rootElement dom.Element) {
  93. self := r.ExistingNode.Locate(rootElement).(dom.Element)
  94. self.RemoveAttribute(r.AttributeName)
  95. }
  96. func (r *Reconciler) SetNodeAttribute(rootElement dom.Element) {
  97. self := r.ExistingNode.Locate(rootElement).(dom.Element)
  98. self.SetAttribute(r.AttributeName, r.AttributeValue)
  99. }
  100. func (c Changes) ApplyChanges(rootElement dom.Element) {
  101. for _, reconciler := range c {
  102. reconciler.ApplyChange(rootElement)
  103. }
  104. }