github.com/godaddy-x/freego@v1.0.156/goquery/manipulation.go (about)

     1  package goquery
     2  
     3  import (
     4  	"strings"
     5  
     6  	"golang.org/x/net/html"
     7  )
     8  
     9  // After applies the selector from the root document and inserts the matched elements
    10  // after the elements in the set of matched elements.
    11  //
    12  // If one of the matched elements in the selection is not currently in the
    13  // document, it's impossible to insert nodes after it, so it will be ignored.
    14  //
    15  // This follows the same rules as Selection.Append.
    16  func (s *Selection) After(selector string) *Selection {
    17  	return s.AfterMatcher(compileMatcher(selector))
    18  }
    19  
    20  // AfterMatcher applies the matcher from the root document and inserts the matched elements
    21  // after the elements in the set of matched elements.
    22  //
    23  // If one of the matched elements in the selection is not currently in the
    24  // document, it's impossible to insert nodes after it, so it will be ignored.
    25  //
    26  // This follows the same rules as Selection.Append.
    27  func (s *Selection) AfterMatcher(m Matcher) *Selection {
    28  	return s.AfterNodes(m.MatchAll(s.document.rootNode)...)
    29  }
    30  
    31  // AfterSelection inserts the elements in the selection after each element in the set of matched
    32  // elements.
    33  //
    34  // This follows the same rules as Selection.Append.
    35  func (s *Selection) AfterSelection(sel *Selection) *Selection {
    36  	return s.AfterNodes(sel.Nodes...)
    37  }
    38  
    39  // AfterHtml parses the html and inserts it after the set of matched elements.
    40  //
    41  // This follows the same rules as Selection.Append.
    42  func (s *Selection) AfterHtml(html string) *Selection {
    43  	return s.AfterNodes(parseHtml(html)...)
    44  }
    45  
    46  // AfterNodes inserts the nodes after each element in the set of matched elements.
    47  //
    48  // This follows the same rules as Selection.Append.
    49  func (s *Selection) AfterNodes(ns ...*html.Node) *Selection {
    50  	return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
    51  		if sn.Parent != nil {
    52  			sn.Parent.InsertBefore(n, sn.NextSibling)
    53  		}
    54  	})
    55  }
    56  
    57  // Append appends the elements specified by the selector to the end of each element
    58  // in the set of matched elements, following those rules:
    59  //
    60  // 1) The selector is applied to the root document.
    61  //
    62  // 2) Elements that are part of the document will be moved to the new location.
    63  //
    64  // 3) If there are multiple locations to append to, cloned nodes will be
    65  // appended to all target locations except the last one, which will be moved
    66  // as noted in (2).
    67  func (s *Selection) Append(selector string) *Selection {
    68  	return s.AppendMatcher(compileMatcher(selector))
    69  }
    70  
    71  // AppendMatcher appends the elements specified by the matcher to the end of each element
    72  // in the set of matched elements.
    73  //
    74  // This follows the same rules as Selection.Append.
    75  func (s *Selection) AppendMatcher(m Matcher) *Selection {
    76  	return s.AppendNodes(m.MatchAll(s.document.rootNode)...)
    77  }
    78  
    79  // AppendSelection appends the elements in the selection to the end of each element
    80  // in the set of matched elements.
    81  //
    82  // This follows the same rules as Selection.Append.
    83  func (s *Selection) AppendSelection(sel *Selection) *Selection {
    84  	return s.AppendNodes(sel.Nodes...)
    85  }
    86  
    87  // AppendHtml parses the html and appends it to the set of matched elements.
    88  func (s *Selection) AppendHtml(html string) *Selection {
    89  	return s.AppendNodes(parseHtml(html)...)
    90  }
    91  
    92  // AppendNodes appends the specified nodes to each node in the set of matched elements.
    93  //
    94  // This follows the same rules as Selection.Append.
    95  func (s *Selection) AppendNodes(ns ...*html.Node) *Selection {
    96  	return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
    97  		sn.AppendChild(n)
    98  	})
    99  }
   100  
   101  // Before inserts the matched elements before each element in the set of matched elements.
   102  //
   103  // This follows the same rules as Selection.Append.
   104  func (s *Selection) Before(selector string) *Selection {
   105  	return s.BeforeMatcher(compileMatcher(selector))
   106  }
   107  
   108  // BeforeMatcher inserts the matched elements before each element in the set of matched elements.
   109  //
   110  // This follows the same rules as Selection.Append.
   111  func (s *Selection) BeforeMatcher(m Matcher) *Selection {
   112  	return s.BeforeNodes(m.MatchAll(s.document.rootNode)...)
   113  }
   114  
   115  // BeforeSelection inserts the elements in the selection before each element in the set of matched
   116  // elements.
   117  //
   118  // This follows the same rules as Selection.Append.
   119  func (s *Selection) BeforeSelection(sel *Selection) *Selection {
   120  	return s.BeforeNodes(sel.Nodes...)
   121  }
   122  
   123  // BeforeHtml parses the html and inserts it before the set of matched elements.
   124  //
   125  // This follows the same rules as Selection.Append.
   126  func (s *Selection) BeforeHtml(html string) *Selection {
   127  	return s.BeforeNodes(parseHtml(html)...)
   128  }
   129  
   130  // BeforeNodes inserts the nodes before each element in the set of matched elements.
   131  //
   132  // This follows the same rules as Selection.Append.
   133  func (s *Selection) BeforeNodes(ns ...*html.Node) *Selection {
   134  	return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
   135  		if sn.Parent != nil {
   136  			sn.Parent.InsertBefore(n, sn)
   137  		}
   138  	})
   139  }
   140  
   141  // Clone creates a deep copy of the set of matched nodes. The new nodes will not be
   142  // attached to the document.
   143  func (s *Selection) Clone() *Selection {
   144  	ns := newEmptySelection(s.document)
   145  	ns.Nodes = cloneNodes(s.Nodes)
   146  	return ns
   147  }
   148  
   149  // Empty removes all children nodes from the set of matched elements.
   150  // It returns the children nodes in a new Selection.
   151  func (s *Selection) Empty() *Selection {
   152  	var nodes []*html.Node
   153  
   154  	for _, n := range s.Nodes {
   155  		for c := n.FirstChild; c != nil; c = n.FirstChild {
   156  			n.RemoveChild(c)
   157  			nodes = append(nodes, c)
   158  		}
   159  	}
   160  
   161  	return pushStack(s, nodes)
   162  }
   163  
   164  // Prepend prepends the elements specified by the selector to each element in
   165  // the set of matched elements, following the same rules as Append.
   166  func (s *Selection) Prepend(selector string) *Selection {
   167  	return s.PrependMatcher(compileMatcher(selector))
   168  }
   169  
   170  // PrependMatcher prepends the elements specified by the matcher to each
   171  // element in the set of matched elements.
   172  //
   173  // This follows the same rules as Selection.Append.
   174  func (s *Selection) PrependMatcher(m Matcher) *Selection {
   175  	return s.PrependNodes(m.MatchAll(s.document.rootNode)...)
   176  }
   177  
   178  // PrependSelection prepends the elements in the selection to each element in
   179  // the set of matched elements.
   180  //
   181  // This follows the same rules as Selection.Append.
   182  func (s *Selection) PrependSelection(sel *Selection) *Selection {
   183  	return s.PrependNodes(sel.Nodes...)
   184  }
   185  
   186  // PrependHtml parses the html and prepends it to the set of matched elements.
   187  func (s *Selection) PrependHtml(html string) *Selection {
   188  	return s.PrependNodes(parseHtml(html)...)
   189  }
   190  
   191  // PrependNodes prepends the specified nodes to each node in the set of
   192  // matched elements.
   193  //
   194  // This follows the same rules as Selection.Append.
   195  func (s *Selection) PrependNodes(ns ...*html.Node) *Selection {
   196  	return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
   197  		// sn.FirstChild may be nil, in which case this functions like
   198  		// sn.AppendChild()
   199  		sn.InsertBefore(n, sn.FirstChild)
   200  	})
   201  }
   202  
   203  // Remove removes the set of matched elements from the document.
   204  // It returns the same selection, now consisting of nodes not in the document.
   205  func (s *Selection) Remove() *Selection {
   206  	for _, n := range s.Nodes {
   207  		if n.Parent != nil {
   208  			n.Parent.RemoveChild(n)
   209  		}
   210  	}
   211  
   212  	return s
   213  }
   214  
   215  // RemoveFiltered removes the set of matched elements by selector.
   216  // It returns the Selection of removed nodes.
   217  func (s *Selection) RemoveFiltered(selector string) *Selection {
   218  	return s.RemoveMatcher(compileMatcher(selector))
   219  }
   220  
   221  // RemoveMatcher removes the set of matched elements.
   222  // It returns the Selection of removed nodes.
   223  func (s *Selection) RemoveMatcher(m Matcher) *Selection {
   224  	return s.FilterMatcher(m).Remove()
   225  }
   226  
   227  // ReplaceWith replaces each element in the set of matched elements with the
   228  // nodes matched by the given selector.
   229  // It returns the removed elements.
   230  //
   231  // This follows the same rules as Selection.Append.
   232  func (s *Selection) ReplaceWith(selector string) *Selection {
   233  	return s.ReplaceWithMatcher(compileMatcher(selector))
   234  }
   235  
   236  // ReplaceWithMatcher replaces each element in the set of matched elements with
   237  // the nodes matched by the given Matcher.
   238  // It returns the removed elements.
   239  //
   240  // This follows the same rules as Selection.Append.
   241  func (s *Selection) ReplaceWithMatcher(m Matcher) *Selection {
   242  	return s.ReplaceWithNodes(m.MatchAll(s.document.rootNode)...)
   243  }
   244  
   245  // ReplaceWithSelection replaces each element in the set of matched elements with
   246  // the nodes from the given Selection.
   247  // It returns the removed elements.
   248  //
   249  // This follows the same rules as Selection.Append.
   250  func (s *Selection) ReplaceWithSelection(sel *Selection) *Selection {
   251  	return s.ReplaceWithNodes(sel.Nodes...)
   252  }
   253  
   254  // ReplaceWithHtml replaces each element in the set of matched elements with
   255  // the parsed HTML.
   256  // It returns the removed elements.
   257  //
   258  // This follows the same rules as Selection.Append.
   259  func (s *Selection) ReplaceWithHtml(html string) *Selection {
   260  	return s.ReplaceWithNodes(parseHtml(html)...)
   261  }
   262  
   263  // ReplaceWithNodes replaces each element in the set of matched elements with
   264  // the given nodes.
   265  // It returns the removed elements.
   266  //
   267  // This follows the same rules as Selection.Append.
   268  func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection {
   269  	s.AfterNodes(ns...)
   270  	return s.Remove()
   271  }
   272  
   273  // SetHtml sets the html content of each element in the selection to
   274  // specified html string.
   275  func (s *Selection) SetHtml(html string) *Selection {
   276  	return setHtmlNodes(s, parseHtml(html)...)
   277  }
   278  
   279  // SetText sets the content of each element in the selection to specified content.
   280  // The provided text string is escaped.
   281  func (s *Selection) SetText(text string) *Selection {
   282  	return s.SetHtml(html.EscapeString(text))
   283  }
   284  
   285  // Unwrap removes the parents of the set of matched elements, leaving the matched
   286  // elements (and their siblings, if any) in their place.
   287  // It returns the original selection.
   288  func (s *Selection) Unwrap() *Selection {
   289  	s.Parent().Each(func(i int, ss *Selection) {
   290  		// For some reason, jquery allows unwrap to remove the <head> element, so
   291  		// allowing it here too. Same for <html>. Why it allows those elements to
   292  		// be unwrapped while not allowing body is a mystery to me.
   293  		if ss.Nodes[0].Data != "body" {
   294  			ss.ReplaceWithSelection(ss.Contents())
   295  		}
   296  	})
   297  
   298  	return s
   299  }
   300  
   301  // Wrap wraps each element in the set of matched elements inside the first
   302  // element matched by the given selector. The matched child is cloned before
   303  // being inserted into the document.
   304  //
   305  // It returns the original set of elements.
   306  func (s *Selection) Wrap(selector string) *Selection {
   307  	return s.WrapMatcher(compileMatcher(selector))
   308  }
   309  
   310  // WrapMatcher wraps each element in the set of matched elements inside the
   311  // first element matched by the given matcher. The matched child is cloned
   312  // before being inserted into the document.
   313  //
   314  // It returns the original set of elements.
   315  func (s *Selection) WrapMatcher(m Matcher) *Selection {
   316  	return s.wrapNodes(m.MatchAll(s.document.rootNode)...)
   317  }
   318  
   319  // WrapSelection wraps each element in the set of matched elements inside the
   320  // first element in the given Selection. The element is cloned before being
   321  // inserted into the document.
   322  //
   323  // It returns the original set of elements.
   324  func (s *Selection) WrapSelection(sel *Selection) *Selection {
   325  	return s.wrapNodes(sel.Nodes...)
   326  }
   327  
   328  // WrapHtml wraps each element in the set of matched elements inside the inner-
   329  // most child of the given HTML.
   330  //
   331  // It returns the original set of elements.
   332  func (s *Selection) WrapHtml(html string) *Selection {
   333  	return s.wrapNodes(parseHtml(html)...)
   334  }
   335  
   336  // WrapNode wraps each element in the set of matched elements inside the inner-
   337  // most child of the given node. The given node is copied before being inserted
   338  // into the document.
   339  //
   340  // It returns the original set of elements.
   341  func (s *Selection) WrapNode(n *html.Node) *Selection {
   342  	return s.wrapNodes(n)
   343  }
   344  
   345  func (s *Selection) wrapNodes(ns ...*html.Node) *Selection {
   346  	s.Each(func(i int, ss *Selection) {
   347  		ss.wrapAllNodes(ns...)
   348  	})
   349  
   350  	return s
   351  }
   352  
   353  // WrapAll wraps a single HTML structure, matched by the given selector, around
   354  // all elements in the set of matched elements. The matched child is cloned
   355  // before being inserted into the document.
   356  //
   357  // It returns the original set of elements.
   358  func (s *Selection) WrapAll(selector string) *Selection {
   359  	return s.WrapAllMatcher(compileMatcher(selector))
   360  }
   361  
   362  // WrapAllMatcher wraps a single HTML structure, matched by the given Matcher,
   363  // around all elements in the set of matched elements. The matched child is
   364  // cloned before being inserted into the document.
   365  //
   366  // It returns the original set of elements.
   367  func (s *Selection) WrapAllMatcher(m Matcher) *Selection {
   368  	return s.wrapAllNodes(m.MatchAll(s.document.rootNode)...)
   369  }
   370  
   371  // WrapAllSelection wraps a single HTML structure, the first node of the given
   372  // Selection, around all elements in the set of matched elements. The matched
   373  // child is cloned before being inserted into the document.
   374  //
   375  // It returns the original set of elements.
   376  func (s *Selection) WrapAllSelection(sel *Selection) *Selection {
   377  	return s.wrapAllNodes(sel.Nodes...)
   378  }
   379  
   380  // WrapAllHtml wraps the given HTML structure around all elements in the set of
   381  // matched elements. The matched child is cloned before being inserted into the
   382  // document.
   383  //
   384  // It returns the original set of elements.
   385  func (s *Selection) WrapAllHtml(html string) *Selection {
   386  	return s.wrapAllNodes(parseHtml(html)...)
   387  }
   388  
   389  func (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection {
   390  	if len(ns) > 0 {
   391  		return s.WrapAllNode(ns[0])
   392  	}
   393  	return s
   394  }
   395  
   396  // WrapAllNode wraps the given node around the first element in the Selection,
   397  // making all other nodes in the Selection children of the given node. The node
   398  // is cloned before being inserted into the document.
   399  //
   400  // It returns the original set of elements.
   401  func (s *Selection) WrapAllNode(n *html.Node) *Selection {
   402  	if s.Size() == 0 {
   403  		return s
   404  	}
   405  
   406  	wrap := cloneNode(n)
   407  
   408  	first := s.Nodes[0]
   409  	if first.Parent != nil {
   410  		first.Parent.InsertBefore(wrap, first)
   411  		first.Parent.RemoveChild(first)
   412  	}
   413  
   414  	for c := getFirstChildEl(wrap); c != nil; c = getFirstChildEl(wrap) {
   415  		wrap = c
   416  	}
   417  
   418  	newSingleSelection(wrap, s.document).AppendSelection(s)
   419  
   420  	return s
   421  }
   422  
   423  // WrapInner wraps an HTML structure, matched by the given selector, around the
   424  // content of element in the set of matched elements. The matched child is
   425  // cloned before being inserted into the document.
   426  //
   427  // It returns the original set of elements.
   428  func (s *Selection) WrapInner(selector string) *Selection {
   429  	return s.WrapInnerMatcher(compileMatcher(selector))
   430  }
   431  
   432  // WrapInnerMatcher wraps an HTML structure, matched by the given selector,
   433  // around the content of element in the set of matched elements. The matched
   434  // child is cloned before being inserted into the document.
   435  //
   436  // It returns the original set of elements.
   437  func (s *Selection) WrapInnerMatcher(m Matcher) *Selection {
   438  	return s.wrapInnerNodes(m.MatchAll(s.document.rootNode)...)
   439  }
   440  
   441  // WrapInnerSelection wraps an HTML structure, matched by the given selector,
   442  // around the content of element in the set of matched elements. The matched
   443  // child is cloned before being inserted into the document.
   444  //
   445  // It returns the original set of elements.
   446  func (s *Selection) WrapInnerSelection(sel *Selection) *Selection {
   447  	return s.wrapInnerNodes(sel.Nodes...)
   448  }
   449  
   450  // WrapInnerHtml wraps an HTML structure, matched by the given selector, around
   451  // the content of element in the set of matched elements. The matched child is
   452  // cloned before being inserted into the document.
   453  //
   454  // It returns the original set of elements.
   455  func (s *Selection) WrapInnerHtml(html string) *Selection {
   456  	return s.wrapInnerNodes(parseHtml(html)...)
   457  }
   458  
   459  // WrapInnerNode wraps an HTML structure, matched by the given selector, around
   460  // the content of element in the set of matched elements. The matched child is
   461  // cloned before being inserted into the document.
   462  //
   463  // It returns the original set of elements.
   464  func (s *Selection) WrapInnerNode(n *html.Node) *Selection {
   465  	return s.wrapInnerNodes(n)
   466  }
   467  
   468  func (s *Selection) wrapInnerNodes(ns ...*html.Node) *Selection {
   469  	if len(ns) == 0 {
   470  		return s
   471  	}
   472  
   473  	s.Each(func(i int, s *Selection) {
   474  		contents := s.Contents()
   475  
   476  		if contents.Size() > 0 {
   477  			contents.wrapAllNodes(ns...)
   478  		} else {
   479  			s.AppendNodes(cloneNode(ns[0]))
   480  		}
   481  	})
   482  
   483  	return s
   484  }
   485  
   486  func parseHtml(h string) []*html.Node {
   487  	// Errors are only returned when the io.Reader returns any error besides
   488  	// EOF, but strings.Reader never will
   489  	nodes, err := html.ParseFragment(strings.NewReader(h), &html.Node{Type: html.ElementNode})
   490  	if err != nil {
   491  		panic("goquery: failed to parse HTML: " + err.Error())
   492  	}
   493  	return nodes
   494  }
   495  
   496  func setHtmlNodes(s *Selection, ns ...*html.Node) *Selection {
   497  	for _, n := range s.Nodes {
   498  		for c := n.FirstChild; c != nil; c = n.FirstChild {
   499  			n.RemoveChild(c)
   500  		}
   501  		for _, c := range ns {
   502  			n.AppendChild(cloneNode(c))
   503  		}
   504  	}
   505  	return s
   506  }
   507  
   508  // Get the first child that is an ElementNode
   509  func getFirstChildEl(n *html.Node) *html.Node {
   510  	c := n.FirstChild
   511  	for c != nil && c.Type != html.ElementNode {
   512  		c = c.NextSibling
   513  	}
   514  	return c
   515  }
   516  
   517  // Deep copy a slice of nodes.
   518  func cloneNodes(ns []*html.Node) []*html.Node {
   519  	cns := make([]*html.Node, 0, len(ns))
   520  
   521  	for _, n := range ns {
   522  		cns = append(cns, cloneNode(n))
   523  	}
   524  
   525  	return cns
   526  }
   527  
   528  // Deep copy a node. The new node has clones of all the original node's
   529  // children but none of its parents or siblings.
   530  func cloneNode(n *html.Node) *html.Node {
   531  	nn := &html.Node{
   532  		Type:     n.Type,
   533  		DataAtom: n.DataAtom,
   534  		Data:     n.Data,
   535  		Attr:     make([]html.Attribute, len(n.Attr)),
   536  	}
   537  
   538  	copy(nn.Attr, n.Attr)
   539  	for c := n.FirstChild; c != nil; c = c.NextSibling {
   540  		nn.AppendChild(cloneNode(c))
   541  	}
   542  
   543  	return nn
   544  }
   545  
   546  func (s *Selection) manipulateNodes(ns []*html.Node, reverse bool,
   547  	f func(sn *html.Node, n *html.Node)) *Selection {
   548  
   549  	lasti := s.Size() - 1
   550  
   551  	// net.Html doesn't provide document fragments for insertion, so to get
   552  	// things in the correct order with After() and Prepend(), the callback
   553  	// needs to be called on the reverse of the nodes.
   554  	if reverse {
   555  		for i, j := 0, len(ns)-1; i < j; i, j = i+1, j-1 {
   556  			ns[i], ns[j] = ns[j], ns[i]
   557  		}
   558  	}
   559  
   560  	for i, sn := range s.Nodes {
   561  		for _, n := range ns {
   562  			if i != lasti {
   563  				f(sn, cloneNode(n))
   564  			} else {
   565  				if n.Parent != nil {
   566  					n.Parent.RemoveChild(n)
   567  				}
   568  				f(sn, n)
   569  			}
   570  		}
   571  	}
   572  
   573  	return s
   574  }