Class: Habaki::SubSelector

Inherits:
Node
  • Object
show all
Defined in:
lib/habaki/sub_selector.rb

Overview

part of selector (eg in p.t, p is a tag subselector and .t a class subselector)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Node

#to_s

Instance Attribute Details

#argumentString

Returns:



25
26
27
# File 'lib/habaki/sub_selector.rb', line 25

def argument
  @argument
end

#attributeQualifiedName

Returns:



21
22
23
# File 'lib/habaki/sub_selector.rb', line 21

def attribute
  @attribute
end

#matchSymbol

Returns:

  • (Symbol)


14
15
16
# File 'lib/habaki/sub_selector.rb', line 14

def match
  @match
end

#positionSourcePosition

Returns:



30
31
32
# File 'lib/habaki/sub_selector.rb', line 30

def position
  @position
end

#pseudoSymbol

Returns:

  • (Symbol)


18
19
20
# File 'lib/habaki/sub_selector.rb', line 18

def pseudo
  @pseudo
end

#selectorsSelectors

Returns:



27
28
29
# File 'lib/habaki/sub_selector.rb', line 27

def selectors
  @selectors
end

#tagQualifiedName

Returns:



16
17
18
# File 'lib/habaki/sub_selector.rb', line 16

def tag
  @tag
end

#valueString

Returns:



23
24
25
# File 'lib/habaki/sub_selector.rb', line 23

def value
  @value
end

Instance Method Details

#attribute_selector?Boolean

is this selector on attribute ?

Returns:

  • (Boolean)


34
35
36
# File 'lib/habaki/sub_selector.rb', line 34

def attribute_selector?
  @match.to_s.start_with?("attribute_")
end

#attribute_value_match?(val, specificity = nil) ⇒ Boolean

does selector match attribute value ?

Parameters:

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/habaki/sub_selector.rb', line 93

def attribute_value_match?(val, specificity = nil)
  match_with_specificity(
    case @match
    when :attribute_exact
      val == @value
    when :attribute_begin
      val.start_with?(@value)
    when :attribute_end
      val.end_with?(@value)
    when :attribute_contain
      val.include?(@value)
    when :attribute_hyphen
      val.start_with?("#{@value}-")
    else
      false
    end, specificity, 10)
end

#class_match?(name, specificity = nil) ⇒ Boolean

does selector match class ?

Parameters:

Returns:

  • (Boolean)


77
78
79
# File 'lib/habaki/sub_selector.rb', line 77

def class_match?(name, specificity = nil)
  match_with_specificity(@value == name, specificity, 10)
end

#element_match?(element, specificity = nil) ⇒ Boolean

does sub selector match Visitor::Element ?

Parameters:

Returns:

  • (Boolean)


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/habaki/sub_selector.rb', line 42

def element_match?(element, specificity = nil)
  case @match
  when :tag
    tag_match?(element.tag_name, specificity)
  when :class
    element.class_names.any?{|p_class_name| class_match?(p_class_name, specificity)}
  when :id
    id_match?(element.id_name, specificity)
  when :pseudo_class
    pseudo_class_match?(element, specificity)
  when :pseudo_element
    # TODO
    false
  else
    if attribute_selector?
      element_attr = element.attr(@attribute.local)
      (element_attr ? attribute_value_match?(element_attr, specificity) : false)
    else
      false
    end
  end
end

#id_match?(name, specificity = nil) ⇒ Boolean

does selector match id ?

Parameters:

Returns:

  • (Boolean)


85
86
87
# File 'lib/habaki/sub_selector.rb', line 85

def id_match?(name, specificity = nil)
  match_with_specificity(@value == name, specificity, 100)
end

#pseudo_class_match?(element, specificity = nil) ⇒ Boolean

does selector pseudo class match Visitor::Element ?

Parameters:

Returns:

  • (Boolean)


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/habaki/sub_selector.rb', line 115

def pseudo_class_match?(element, specificity = nil)
  match_with_specificity(
    case @pseudo
    when :root
      element.tag_name == "html"
    when :empty
      element.children.empty?
    when :first_child
      parent_element = element.parent
      parent_element&.children.first == element
    when :last_child
      parent_element = element.parent
      parent_element&.children.last == element
    when :only_child
      parent_element = element.parent
      parent_element&.children.length == 1 && parent_element&.children.first == element
    when :nth_child
      parent_element = element.parent
      arg = @argument.split("+")
      case arg[0]
      when "odd"
        ((parent_element&.children.index(element) + 1) % 2 == 1)
      when "even"
        ((parent_element&.children.index(element) + 1) % 2 == 0)
      when /^\d+$/
        parent_element&.children[@argument.to_i - 1] == element
      when "n"
        ((parent_element&.children.index(element) + 1) % 1) == (arg[1]&.to_i || 0)
      when /n$/
        ((parent_element&.children.index(element) + 1) % arg[0].sub("n", "").to_i) == (arg[1]&.to_i || 0)
      else
        # TODO "of type"
        false
      end
    when :not
      !@selectors.element_match?(element)
    when :not_parsed, :unknown
      true
    when :link
      # All a elements that have an href attribute must match one of :link and :visited.
      # for now, always match :link
      true
    else
      # TODO
      # STDERR.puts "Habaki: unsupported pseudo #{@pseudo}"
      false
    end, specificity, 10)
end

#read_from_katana(sel) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:



213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/habaki/sub_selector.rb', line 213

def read_from_katana(sel)
  @match = sel.match
  @tag = QualifiedName.read_from_katana(sel.tag) if sel.tag
  @pseudo = sel.pseudo

  @attribute = QualifiedName.read_from_katana(sel.data.attribute) if sel.data.attribute
  @value = sel.data.value
  @argument = sel.data.argument

  @selectors = Selectors.read_from_katana(sel.data.selectors) if sel.data.selectors

  @position = SourcePosition.new(sel.position.line, sel.position.column)
end

#string(format = Formatter::Base.new) ⇒ String

Parameters:

Returns:



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/habaki/sub_selector.rb', line 166

def string(format = Formatter::Base.new)
  str = ""
  if attribute_selector?
    str += "[#{@attribute.string(format)}"
    case @match
    when :attribute_exact
      str += "="
    when :attribute_set
      str += "]"
    when :attribute_list
      str += "~="
    when :attribute_hyphen
      str += "|="
    when :attribute_begin
      str += "^="
    when :attribute_end
      str += "$="
    when :attribute_contain
      str += "*="
    end
    str += "\"#{@value}\"]" if @match != :attribute_set
  else
    case @match
    when :tag
      str += @tag.string(format)
    when :class
      str += ".#{@value}"
    when :id
      str += "##{@value}"
    when :pseudo_class, :pseudo_page_class
      str += ":#{@value}"
      case @pseudo
      when :any, :not, :host, :host_context
        str += @selectors.string(format)
        str += ")"
      when :lang, :nth_child, :nth_last_child, :nth_of_type, :nth_last_of_type
        str += "#{@argument})"
      end
    when :pseudo_element
      str += "::#{@value}"
    end
  end
  str
end

#tag_match?(name, specificity = nil) ⇒ Boolean

does selector match tag ?

Parameters:

Returns:

  • (Boolean)


69
70
71
# File 'lib/habaki/sub_selector.rb', line 69

def tag_match?(name, specificity = nil)
  match_with_specificity(@tag.local == name, specificity, 1) || @tag.local == "*"
end