All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
NthChildMatch.h
Go to the documentation of this file.
1 // Copyright 2015 Thomas Trapp
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef HEXT_NTH_CHILD_MATCH_H_INCLUDED
16 #define HEXT_NTH_CHILD_MATCH_H_INCLUDED
17 
18 /// @file
19 /// Declares hext::NthChildMatch
20 
21 #include "hext/Cloneable.h"
22 #include "hext/Match.h"
23 #include "hext/HtmlTag.h"
24 
25 #include <utility>
26 
27 #include <gumbo.h>
28 
29 
30 namespace hext {
31 
32 
33 /// Matches HTML nodes having a certain position within their parent HTML
34 /// element.
35 ///
36 /// The intent is to mimic the following CSS pseudo-classes:
37 /// nth-child, nth-of-type, nth-last-of-type, first-of-type, last-of-type,
38 /// first-child, last-child, nth-last-child, nth-last-of-type
39 ///
40 /// See https://developer.mozilla.org/en-US/docs/Web/CSS/%3Anth-child for a
41 /// detailed explanation.
42 ///
43 /// @par Example:
44 /// ~~~~~~~~~~~~~
45 /// // Assume first, second, third are children of the following <ul> element:
46 /// // <ul><li>1</li><li>2</li><li>3</li></ul>
47 /// const GumboNode * first = ...;
48 /// const GumboNode * second = ...;
49 /// const GumboNode * third = ...;
50 ///
51 /// NthChildMatch m_even(2, 0); // :nth-child(2n)
52 /// NthChildMatch m_odd (2, 1); // :nth-child(2n+1)
53 ///
54 /// assert(!m_even.matches(first));
55 /// assert( m_even.matches(second));
56 /// assert(!m_even.matches(third));
57 ///
58 /// assert( m_odd.matches(first));
59 /// assert(!m_odd.matches(second));
60 /// assert( m_odd.matches(third));
61 /// ~~~~~~~~~~~~~
62 ///
63 /// @par last-of-type Example:
64 /// ~~~~~~~~~~~~~~~~~~~~~~~~~~
65 /// // Assume first, second, third are children of the following <a> element:
66 /// // <a>
67 /// // <b>1</b>
68 /// // <u>2</u>
69 /// // <b>3</b>
70 /// // </a>
71 /// const GumboNode * first = ...;
72 /// const GumboNode * second = ...;
73 /// const GumboNode * third = ...;
74 ///
75 /// NthChildMatch m_last_of_type(
76 /// 0, // no repetition
77 /// 1, // last element
78 /// NthChildMatch::Last | // count following siblings and
79 /// NthChildMatch::OfType // only count elements with
80 /// // same tag.
81 /// );
82 ///
83 /// assert(!m_last_of_type.matches(first));
84 /// assert( m_last_of_type.matches(second));
85 /// assert( m_last_of_type.matches(third));
86 /// ~~~~~~~~~~~~~~~~~~~~~~~~~~
87 class NthChildMatch final : public Cloneable<NthChildMatch, Match>
88 {
89 public:
90  /// NthChildMatch's options.
91  enum Option
92  {
93  /// Count preceding siblings (:nth-child).
94  First = 1 << 1,
95 
96  /// Count following siblings (:nth-last-child).
97  Last = 1 << 2,
98 
99  /// Only count siblings of the same type (:nth-of-type).
100  OfType = 1 << 3
101  };
102 
103  /// Constructs an NthChildMatch with the pattern <step * n + shift>.
104  ///
105  /// @param step: The step of the pattern.
106  /// @param shift: The shift of the pattern.
107  /// @param options: See NthChildMatch::Option.
108  /// Default: Count any preceding HTML element.
109  NthChildMatch(int step,
110  int shift,
111  Option options = Option::First) noexcept;
112 
113  /// Construct an NthChildMatch with step and shift given as std::pair.
114  /// Constructs an NthChildMatch with the pattern <step * n + shift>, where
115  /// step and shift is given as a std::pair.
116  ///
117  /// @param step_and_shift: The step and shift of the pattern.
118  /// @param options: See NthChildMatch::Option.
119  /// Default: Count any preceding HTML element.
120  explicit NthChildMatch(std::pair<int, int> step_and_shift,
121  Option options = Option::First) noexcept;
122 
123  /// Returns true if HTML node matches pattern <step * n + shift>.
124  ///
125  /// @param node: A pointer to a GumboNode.
126  bool matches(const GumboNode * node) const noexcept override;
127 
128 private:
129  /// Count preceding siblings of an HTML node.
130  ///
131  /// @param node: A pointer to a GumboNode.
132  /// @param count_tag: If given any value other than HtmlTag::ANY, only count
133  /// siblings having this HtmlTag.
134  int count_preceding_siblings(const GumboNode * node,
135  HtmlTag count_tag) const noexcept;
136 
137  /// Count following siblings of an HTML node.
138  ///
139  /// @param node: A pointer to a GumboNode.
140  /// @param count_tag: If given any value other than HtmlTag::ANY, only count
141  /// siblings having this HtmlTag.
142  int count_following_siblings(const GumboNode * node,
143  HtmlTag count_tag) const noexcept;
144 
145  /// The step in the pattern <step * n + shift>
146  int step_;
147 
148  /// The shift in the pattern <step * n + shift>
149  int shift_;
150 
151  /// See NthChildMatch::Option.
152  Option options_;
153 };
154 
155 
156 /// Applies Bitwise-OR to NthChildMatch::Option.
157 inline NthChildMatch::Option
158 operator|(NthChildMatch::Option left, NthChildMatch::Option right) noexcept
159 {
160  return static_cast<NthChildMatch::Option>(static_cast<int>(left) |
161  static_cast<int>(right));
162 }
163 
164 
165 /// Applies Bitwise-AND to NthChildMatch::Option.
168 {
169  return static_cast<NthChildMatch::Option>(static_cast<int>(left) &
170  static_cast<int>(right));
171 }
172 
173 
174 } // namespace hext
175 
176 
177 #endif // HEXT_NTH_CHILD_MATCH_H_INCLUDED
178 
HtmlTag
An enum containing all valid HTML tags.
Definition: HtmlTag.h:28
Matches HTML nodes having a certain position within their parent HTML element.
Definition: NthChildMatch.h:87
All valid HTML tags.
Only count siblings of the same type (:nth-of-type).
Option
NthChildMatch's options.
Definition: NthChildMatch.h:91
NthChildMatch::Option operator&(NthChildMatch::Option left, NthChildMatch::Option right) noexcept
Applies Bitwise-AND to NthChildMatch::Option.
Count preceding siblings (:nth-child).
Definition: NthChildMatch.h:94
Curiously recurring template pattern that extends a base class to provide a virtual method Cloneable:...
Definition: Cloneable.h:34
Count following siblings (:nth-last-child).
Definition: NthChildMatch.h:97
Declares hext::Match.
Defines template hext::Cloneable.
NthChildMatch(int step, int shift, Option options=Option::First) noexcept
Constructs an NthChildMatch with the pattern .
bool matches(const GumboNode *node) const noexceptoverride
Returns true if HTML node matches pattern .