diff --git a/FUTURE-CHANGELOG.md b/FUTURE-CHANGELOG.md index 37b8e50..41f8769 100644 --- a/FUTURE-CHANGELOG.md +++ b/FUTURE-CHANGELOG.md @@ -1,9 +1,6 @@ ## v0.0.0-beta.3 <- current ## v0.0.0 -Delete deletes the node without connecting sibling nodes. -* Delete - QuerySelector takes attribute name and regexp for the value and returns the first node that matches the regexp. * QuerySelector @@ -13,29 +10,10 @@ QuerySelectorAll takes two regexps and returns all nodes that matches the regexp Closest returns the closest node that matches the className. * Closest -## v0.0.1 -AddClass add the given class name to the node. -* AddClass - -RemoveClass removes the specified class name from the node. -* RemoveClass - -HasClass returns a boolean value specifying whether the node has the specified class name or not. -* HasClass - -GetClassList returns a map of class names in the specified node. -* GetClassList - ## v0.0.2 * GetElementById * GetElementByClassName * GetElementByTagName * GetElementsById * GetElementsByClassName -* GetElementsByTagName - -## v0.0.3 -DecodeHeader only serializes only up to head. And return a node with only head and it's child nodes. -* DecodeOnly -* DecodeOnlyByClassName -* DecodeHeader \ No newline at end of file +* GetElementsByTagName \ No newline at end of file diff --git a/classList.go b/classList.go new file mode 100644 index 0000000..c8f7ed3 --- /dev/null +++ b/classList.go @@ -0,0 +1,91 @@ +package GoHtml + +import ( + "strings" + "sync" +) + +type ClassList struct { + classes map[string]struct{} + rwMutex *sync.Mutex +} + +// NewClassList returns a new empty ClassList. +func NewClassList() ClassList { + classList := ClassList{ + classes: make(map[string]struct{}), + rwMutex: &sync.Mutex{}, + } + + return classList +} + +// AppendClass append className to classList. className that contains multiple classes is also a valid className. +func (classList ClassList) AppendClass(className string) { + classList.rwMutex.Lock() + defer classList.rwMutex.Unlock() + + classes := strings.SplitSeq(className, " ") + for v := range classes { + classList.classes[strings.TrimSpace(v)] = struct{}{} + } +} + +// SetClass append classes in the node to classList. +func (classList ClassList) SetClass(node *Node) { + if node == nil { + return + } + classes, _ := node.GetAttribute("class") + classList.AppendClass(classes) +} + +// Contains returns whether the className exists or not. +func (classList ClassList) Contains(className string) bool { + classList.rwMutex.Lock() + defer classList.rwMutex.Unlock() + + classes := strings.SplitSeq(className, " ") + for v := range classes { + _, ok := classList.classes[strings.TrimSpace(v)] + if !ok { + return false + } + } + + return true +} + +// DeleteClass deletes the specified classes in className. +func (classList ClassList) DeleteClass(className string) { + classList.rwMutex.Lock() + defer classList.rwMutex.Unlock() + + classes := strings.SplitSeq(className, " ") + for v := range classes { + delete(classList.classes, strings.TrimSpace(v)) + } +} + +// Encode returns the full className. +func (classList ClassList) Encode() string { + classList.rwMutex.Lock() + defer classList.rwMutex.Unlock() + + classes := "" + for v := range classList.classes { + if classes != ""{ + classes+=" " + } + classes+=v + } + return classes +} + +// EncodeTo encode className for the node. +func (classList ClassList) EncodeTo(node *Node){ + if node == nil { + return + } + node.SetAttribute("class", classList.Encode()) +} \ No newline at end of file diff --git a/classList_test.go b/classList_test.go new file mode 100644 index 0000000..ad9fc39 --- /dev/null +++ b/classList_test.go @@ -0,0 +1,37 @@ +package GoHtml_test + +import( + "testing" + "github.com/udan-jayanith/GoHTML" +) + +func TestClasses(t *testing.T){ + node := GoHtml.CreateNode("div") + node.SetAttribute("class", "div-container main") + + classList := GoHtml.NewClassList() + classList.SetClass(node) + if !classList.Contains("main"){ + t.Fatal("") + return + } + classList.DeleteClass("main") + if classList.Contains("main"){ + t.Fatal("") + return + } + + classList.AppendClass("main-div") + if !classList.Contains("main-div"){ + t.Fatal("") + return + } + + classList.EncodeTo(node) + + className, _ := node.GetAttribute("class") + if className != classList.Encode(){ + t.Fatal("") + return + } +} \ No newline at end of file diff --git a/main.go b/main.go index ae20325..f2105d0 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,10 @@ func DeepCloneNode(node *Node) *Node{ attributes := node.attributes node.rwMutex.Unlock() + if node == nil { + return node + } + newNode := Node{ childNode: node.GetChildNode(), tagName: node.GetTagName(), diff --git a/node-tree.go b/node-tree.go index 559f19a..67fe170 100644 --- a/node-tree.go +++ b/node-tree.go @@ -229,6 +229,7 @@ func (node *Node) RemoveNode() { node.previousNode = nil node.nextNode = nil + node.parentNode = nil node.rwMutex.Unlock() @@ -239,9 +240,13 @@ func (node *Node) RemoveNode() { nextNode.SetPreviousNode(previousNode) } - if nextNode != nil{ + if nextNode != nil && previousNode == nil{ nextNode.setParentNode(parentNode) } + + if parentNode != nil{ + parentNode.childNode = nextNode + } } // IsTextNode returns a boolean value indicating node is a text node or not. diff --git a/node-tree_test.go b/node-tree_test.go index 3f06a61..df0a850 100644 --- a/node-tree_test.go +++ b/node-tree_test.go @@ -86,4 +86,30 @@ func TestAppendTextAndInnerText(t *testing.T){ t.Fatal(body.GetInnerText(), " != ", h1.GetChildNode().GetText() + p.GetChildNode().GetText()) } +} + +func TestRemoveNode(t *testing.T){ + article := GoHtml.CreateNode("article") + + h1 := GoHtml.CreateNode("h1") + h1.AppendText("This is a heading.") + article.AppendChild(h1) + + article.AppendChild(GoHtml.CreateNode(GoHtml.Br)) + + p := GoHtml.CreateNode("p") + p.AppendText("this is a paragraph.") + article.AppendChild(p) + + h1.RemoveNode() + + if article.GetChildNode().GetTagName() != GoHtml.Br{ + t.Fatal("Unexpected tag. ", article.GetChildNode().GetTagName()) + return + }else if p.GetParent() != article { + t.Fatal("Unexpected parent.") + } + + //p.RemoveNode() + //t.Log(GoHtml.NodeTreeToHTML(article)) } \ No newline at end of file