diff --git a/manipulation.go b/manipulation.go index a74c415..fdf045a 100644 --- a/manipulation.go +++ b/manipulation.go @@ -13,7 +13,7 @@ import ( // If one of the matched elements in the selection is not currently in the // document, it's impossible to insert nodes after it, so it will be ignored. // -// This follows the same rules outlined in Selection.Append. +// This follows the same rules as Selection.Append. func (s *Selection) After(selector string) *Selection { return s.AfterMatcher(cascadia.MustCompile(selector)) } @@ -24,7 +24,7 @@ func (s *Selection) After(selector string) *Selection { // If one of the matched elements in the selection is not currently in the // document, it's impossible to insert nodes after it, so it will be ignored. // -// This follows the same rules outlined in Selection.Append. +// This follows the same rules as Selection.Append. func (s *Selection) AfterMatcher(m Matcher) *Selection { return s.AfterNodes(m.MatchAll(s.document.rootNode)...) } @@ -32,21 +32,21 @@ func (s *Selection) AfterMatcher(m Matcher) *Selection { // AfterSelection inserts the elements in the selection after each element in the set of matched // elements. // -// This follows the same rules outlined in Selection.Append. +// This follows the same rules as Selection.Append. func (s *Selection) AfterSelection(sel *Selection) *Selection { return s.AfterNodes(sel.Nodes...) } // AfterHtml parses the html and inserts it after the set of matched elements. // -// This follows the same rules outlined in Selection.Append. +// This follows the same rules as Selection.Append. func (s *Selection) AfterHtml(html string) *Selection { return s.AfterNodes(parseHtml(html)...) } // AfterNodes inserts the nodes after each element in the set of matched elements. // -// This follows the same rules outlined in Selection.Append. +// This follows the same rules as Selection.Append. func (s *Selection) AfterNodes(ns ...*html.Node) *Selection { return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) { if sn.Parent != nil { @@ -237,6 +237,9 @@ func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection { // It returns the original selection. func (s *Selection) Unwrap() *Selection { s.Parent().Each(func(i int, ss *Selection) { + // For some reason, jquery allows unwrap to remove the element, so + // allowing it here too. Same for . Why it allows those elements to + // be unwrapped while not allowing body is a mystery to me. if ss.Nodes[0].Data != "body" { ss.ReplaceWithSelection(ss.Contents()) } @@ -248,6 +251,7 @@ func (s *Selection) Unwrap() *Selection { // Wrap wraps each element in the set of matched elements inside the first // element matched by the given selector. The matched child is cloned before // being inserted into the document. +// // It returns the original set of elements. func (s *Selection) Wrap(selector string) *Selection { return s.WrapMatcher(cascadia.MustCompile(selector)) @@ -256,6 +260,7 @@ func (s *Selection) Wrap(selector string) *Selection { // WrapMatcher wraps each element in the set of matched elements inside the // first element matched by the given matcher. The matched child is cloned // before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapMatcher(m Matcher) *Selection { return s.wrapNodes(m.MatchAll(s.document.rootNode)...) @@ -264,6 +269,7 @@ func (s *Selection) WrapMatcher(m Matcher) *Selection { // WrapSelection wraps each element in the set of matched elements inside the // first element in the given Selection. The element is cloned before being // inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapSelection(sel *Selection) *Selection { return s.wrapNodes(sel.Nodes...) @@ -271,6 +277,7 @@ func (s *Selection) WrapSelection(sel *Selection) *Selection { // WrapHtml wraps each element in the set of matched elements inside the inner- // most child of the given HTML. +// // It returns the original set of elements. func (s *Selection) WrapHtml(html string) *Selection { return s.wrapNodes(parseHtml(html)...) @@ -279,6 +286,7 @@ func (s *Selection) WrapHtml(html string) *Selection { // WrapNode wraps each element in the set of matched elements inside the inner- // most child of the given node. The given node is copied before being inserted // into the document. +// // It returns the original set of elements. func (s *Selection) WrapNode(n *html.Node) *Selection { return s.wrapNodes(n) @@ -293,32 +301,36 @@ func (s *Selection) wrapNodes(ns ...*html.Node) *Selection { } // WrapAll wraps a single HTML structure, matched by the given selector, around -// each element in the set of matched elements. The matched child is cloned +// all elements in the set of matched elements. The matched child is cloned // before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapAll(selector string) *Selection { return s.WrapAllMatcher(cascadia.MustCompile(selector)) } // WrapAllMatcher wraps a single HTML structure, matched by the given Matcher, -// around each element in the set of matched elements. The matched child is +// around all elements in the set of matched elements. The matched child is // cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapAllMatcher(m Matcher) *Selection { return s.wrapAllNodes(m.MatchAll(s.document.rootNode)...) } // WrapAllSelection wraps a single HTML structure, the first node of the given -// Selection, around each element in the set of matched elements. The matched +// Selection, around all elements in the set of matched elements. The matched // child is cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapAllSelection(sel *Selection) *Selection { return s.wrapAllNodes(sel.Nodes...) } -// WrapAllHtml wraps the given HTML structure around each element in the set of +// WrapAllHtml wraps the given HTML structure around all elements in the set of // matched elements. The matched child is cloned before being inserted into the // document. +// // It returns the original set of elements. func (s *Selection) WrapAllHtml(html string) *Selection { return s.wrapAllNodes(parseHtml(html)...) @@ -334,6 +346,7 @@ func (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection { // WrapAllNode wraps the given node around the first element in the Selection, // making all other nodes in the Selection children of the given node. The node // is cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapAllNode(n *html.Node) *Selection { if s.Size() == 0 { @@ -360,6 +373,7 @@ func (s *Selection) WrapAllNode(n *html.Node) *Selection { // WrapInner wraps an HTML structure, matched by the given selector, around the // content of element in the set of matched elements. The matched child is // cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapInner(selector string) *Selection { return s.WrapInnerMatcher(cascadia.MustCompile(selector)) @@ -368,6 +382,7 @@ func (s *Selection) WrapInner(selector string) *Selection { // WrapInnerMatcher wraps an HTML structure, matched by the given selector, // around the content of element in the set of matched elements. The matched // child is cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapInnerMatcher(m Matcher) *Selection { return s.wrapInnerNodes(m.MatchAll(s.document.rootNode)...) @@ -376,6 +391,7 @@ func (s *Selection) WrapInnerMatcher(m Matcher) *Selection { // WrapInnerSelection wraps an HTML structure, matched by the given selector, // around the content of element in the set of matched elements. The matched // child is cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapInnerSelection(sel *Selection) *Selection { return s.wrapInnerNodes(sel.Nodes...) @@ -384,6 +400,7 @@ func (s *Selection) WrapInnerSelection(sel *Selection) *Selection { // WrapInnerHtml wraps an HTML structure, matched by the given selector, around // the content of element in the set of matched elements. The matched child is // cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapInnerHtml(html string) *Selection { return s.wrapInnerNodes(parseHtml(html)...) @@ -392,19 +409,24 @@ func (s *Selection) WrapInnerHtml(html string) *Selection { // WrapInnerNode wraps an HTML structure, matched by the given selector, around // the content of element in the set of matched elements. The matched child is // cloned before being inserted into the document. +// // It returns the original set of elements. func (s *Selection) WrapInnerNode(n *html.Node) *Selection { return s.wrapInnerNodes(n) } func (s *Selection) wrapInnerNodes(ns ...*html.Node) *Selection { + if len(ns) == 0 { + return s + } + s.Each(func(i int, s *Selection) { contents := s.Contents() if contents.Size() > 0 { contents.wrapAllNodes(ns...) } else { - s.AppendNodes(ns...) + s.AppendNodes(cloneNode(ns[0])) } }) diff --git a/manipulation_test.go b/manipulation_test.go index 16c09da..0d900ce 100644 --- a/manipulation_test.go +++ b/manipulation_test.go @@ -202,6 +202,7 @@ func TestReplaceWith(t *testing.T) { doc.Find("#nf6").ReplaceWith("#main") assertLength(t, doc.Find("#foot #main:last-child").Nodes, 1) + printSel(t, doc.Selection) doc.Find("#foot").ReplaceWith("#main") assertLength(t, doc.Find("#foot").Nodes, 0) @@ -223,7 +224,7 @@ func TestReplaceWithSelection(t *testing.T) { doc := Doc2Clone() sel := doc.Find("#nf6").ReplaceWithSelection(doc.Find("#nf5")) - assertLength(t, sel.Filter("#nf6").Nodes, 1) + assertSelectionIs(t, sel, "#nf6") assertLength(t, doc.Find("#nf6").Nodes, 0) assertLength(t, doc.Find("#nf5").Nodes, 1) @@ -235,11 +236,20 @@ func TestUnwrap(t *testing.T) { doc.Find("#nf5").Unwrap() assertLength(t, doc.Find("#foot").Nodes, 0) - assertLength(t, doc.Find("body > #nf1").Nodes, 1) assertLength(t, doc.Find("body > #nf5").Nodes, 1) printSel(t, doc.Selection) + + doc = Doc2Clone() + + doc.Find("#nf5, #n1").Unwrap() + assertLength(t, doc.Find("#foot").Nodes, 0) + assertLength(t, doc.Find("#main").Nodes, 0) + assertLength(t, doc.Find("body > #n1").Nodes, 1) + assertLength(t, doc.Find("body > #nf5").Nodes, 1) + + printSel(t, doc.Selection) } func TestUnwrapBody(t *testing.T) { @@ -252,6 +262,28 @@ func TestUnwrapBody(t *testing.T) { printSel(t, doc.Selection) } +func TestUnwrapHead(t *testing.T) { + doc := Doc2Clone() + + doc.Find("title").Unwrap() + assertLength(t, doc.Find("head").Nodes, 0) + assertLength(t, doc.Find("head > title").Nodes, 0) + assertLength(t, doc.Find("title").Nodes, 1) + + printSel(t, doc.Selection) +} + +func TestUnwrapHtml(t *testing.T) { + doc := Doc2Clone() + + doc.Find("head").Unwrap() + assertLength(t, doc.Find("html").Nodes, 0) + assertLength(t, doc.Find("html head").Nodes, 0) + assertLength(t, doc.Find("head").Nodes, 1) + + printSel(t, doc.Selection) +} + func TestWrap(t *testing.T) { doc := Doc2Clone() doc.Find("#nf1").Wrap("#nf2") @@ -280,9 +312,9 @@ func TestWrapEmpty(t *testing.T) { func TestWrapHtml(t *testing.T) { doc := Doc2Clone() - doc.Find("#nf1").WrapHtml(wrapHtml) - nf1 := doc.Find("#foot div#ins:first-child div p em b #nf1") - assertLength(t, nf1.Nodes, 1) + doc.Find(".odd").WrapHtml(wrapHtml) + nf2 := doc.Find("#ins #nf2") + assertLength(t, nf2.Nodes, 1) printSel(t, doc.Selection) } @@ -318,12 +350,36 @@ func TestWrapAllHtml(t *testing.T) { printSel(t, doc.Selection) } -func TestWrapInner(t *testing.T) { +func TestWrapInnerNoContent(t *testing.T) { doc := Doc2Clone() doc.Find(".one").WrapInner(".two") - nf1 := doc.Find("#foot #n2 ~ #nf2") - assertLength(t, nf1.Nodes, 1) + twos := doc.Find(".two") + assertLength(t, twos.Nodes, 4) + assertLength(t, doc.Find(".one .two").Nodes, 2) + + printSel(t, doc.Selection) +} + +func TestWrapInnerWithContent(t *testing.T) { + doc := Doc3Clone() + doc.Find(".one").WrapInner(".two") + + twos := doc.Find(".two") + assertLength(t, twos.Nodes, 4) + assertLength(t, doc.Find(".one .two").Nodes, 2) + + printSel(t, doc.Selection) +} + +func TestWrapInnerNoWrapper(t *testing.T) { + doc := Doc2Clone() + doc.Find(".one").WrapInner(".not-exist") + + twos := doc.Find(".two") + assertLength(t, twos.Nodes, 2) + assertLength(t, doc.Find(".one").Nodes, 2) + assertLength(t, doc.Find(".one .two").Nodes, 0) printSel(t, doc.Selection) } diff --git a/testdata/page2.html b/testdata/page2.html index 2136963..4c2f92f 100644 --- a/testdata/page2.html +++ b/testdata/page2.html @@ -3,7 +3,7 @@ Tests for siblings - +
@@ -20,5 +20,5 @@
- + diff --git a/testdata/page3.html b/testdata/page3.html new file mode 100644 index 0000000..17e8624 --- /dev/null +++ b/testdata/page3.html @@ -0,0 +1,24 @@ + + + + Tests for siblings + + +
+
hello
+
+
+
+
+
+
+ + + diff --git a/type_test.go b/type_test.go index d33140c..98ee3a6 100644 --- a/type_test.go +++ b/type_test.go @@ -12,6 +12,7 @@ import ( // Test helper functions and members var doc *Document var doc2 *Document +var doc3 *Document var docB *Document var docW *Document @@ -33,6 +34,15 @@ func Doc2() *Document { func Doc2Clone() *Document { return CloneDocument(Doc2()) } +func Doc3() *Document { + if doc3 == nil { + doc3 = loadDoc("page3.html") + } + return doc3 +} +func Doc3Clone() *Document { + return CloneDocument(Doc3()) +} func DocB() *Document { if docB == nil { docB = loadDoc("gotesting.html")