xpath 0.1.4 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +61 -4
- data/lib/xpath.rb +6 -57
- data/lib/xpath/dsl.rb +104 -0
- data/lib/xpath/expression.rb +8 -298
- data/lib/xpath/html.rb +101 -62
- data/lib/xpath/literal.rb +8 -0
- data/lib/xpath/renderer.rb +146 -0
- data/lib/xpath/union.rb +10 -12
- data/lib/xpath/version.rb +1 -1
- data/spec/fixtures/form.html +49 -7
- data/spec/html_spec.rb +45 -47
- data/spec/union_spec.rb +14 -13
- data/spec/xpath_spec.rb +35 -88
- metadata +78 -69
data/lib/xpath/html.rb
CHANGED
@@ -3,112 +3,151 @@ module XPath
|
|
3
3
|
include XPath
|
4
4
|
extend self
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
6
|
+
# Match an `a` link element.
|
7
|
+
#
|
8
|
+
# @param [String] locator
|
9
|
+
# Text, id, title, or image alt attribute of the link
|
10
|
+
#
|
11
|
+
def link(locator)
|
12
|
+
link = descendant(:a)[attr(:href)]
|
13
|
+
link[attr(:id).equals(locator) | string.n.contains(locator) | attr(:title).contains(locator) | descendant(:img)[attr(:alt).contains(locator)]]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Match a `submit`, `image`, or `button` element.
|
17
|
+
#
|
18
|
+
# @param [String] locator
|
19
|
+
# Value, title, id, or image alt attribute of the button
|
20
|
+
#
|
16
21
|
def button(locator)
|
17
|
-
button = descendant(:input)[attr(:type).one_of('submit', 'image', 'button')][attr(:id).equals(locator) | attr(:value).
|
18
|
-
button += descendant(:button)[attr(:id).equals(locator) | attr(:value).
|
19
|
-
button += descendant(:input)[attr(:type).equals('image')][attr(:alt).
|
22
|
+
button = descendant(:input)[attr(:type).one_of('submit', 'reset', 'image', 'button')][attr(:id).equals(locator) | attr(:value).contains(locator) | attr(:title).contains(locator)]
|
23
|
+
button += descendant(:button)[attr(:id).equals(locator) | attr(:value).contains(locator) | string.n.contains(locator) | attr(:title).contains(locator)]
|
24
|
+
button += descendant(:input)[attr(:type).equals('image')][attr(:alt).contains(locator)]
|
20
25
|
end
|
21
26
|
|
27
|
+
|
28
|
+
# Match anything returned by either {#link} or {#button}.
|
29
|
+
#
|
30
|
+
# @param [String] locator
|
31
|
+
# Text, id, title, or image alt attribute of the link or button
|
32
|
+
#
|
22
33
|
def link_or_button(locator)
|
23
34
|
link(locator) + button(locator)
|
24
35
|
end
|
25
36
|
|
37
|
+
|
38
|
+
# Match any `fieldset` element.
|
39
|
+
#
|
40
|
+
# @param [String] locator
|
41
|
+
# Legend or id of the fieldset
|
42
|
+
#
|
26
43
|
def fieldset(locator)
|
27
|
-
descendant(:fieldset)[attr(:id).equals(locator) |
|
44
|
+
descendant(:fieldset)[attr(:id).equals(locator) | child(:legend)[string.n.contains(locator)]]
|
28
45
|
end
|
29
46
|
|
30
|
-
|
47
|
+
|
48
|
+
# Match any `input`, `textarea`, or `select` element that doesn't have a
|
49
|
+
# type of `submit`, `image`, or `hidden`.
|
50
|
+
#
|
51
|
+
# @param [String] locator
|
52
|
+
# Label, id, or name of field to match
|
53
|
+
#
|
54
|
+
def field(locator)
|
31
55
|
xpath = descendant(:input, :textarea, :select)[~attr(:type).one_of('submit', 'image', 'hidden')]
|
32
56
|
xpath = locate_field(xpath, locator)
|
33
|
-
xpath = xpath[attr(:checked)] if options[:checked]
|
34
|
-
xpath = xpath[~attr(:checked)] if options[:unchecked]
|
35
|
-
xpath = xpath[field_value(options[:with])] if options.has_key?(:with)
|
36
57
|
xpath
|
37
58
|
end
|
38
59
|
|
39
|
-
|
60
|
+
|
61
|
+
# Match any `input` or `textarea` element that can be filled with text.
|
62
|
+
# This excludes any inputs with a type of `submit`, `image`, `radio`,
|
63
|
+
# `checkbox`, `hidden`, or `file`.
|
64
|
+
#
|
65
|
+
# @param [String] locator
|
66
|
+
# Label, id, or name of field to match
|
67
|
+
#
|
68
|
+
def fillable_field(locator)
|
40
69
|
xpath = descendant(:input, :textarea)[~attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
|
41
70
|
xpath = locate_field(xpath, locator)
|
42
|
-
xpath = xpath[field_value(options[:with])] if options.has_key?(:with)
|
43
71
|
xpath
|
44
72
|
end
|
45
73
|
|
46
|
-
def select(locator, options={})
|
47
|
-
xpath = locate_field(descendant(:select), locator)
|
48
74
|
|
49
|
-
|
50
|
-
|
51
|
-
|
75
|
+
# Match any `select` element.
|
76
|
+
#
|
77
|
+
# @param [String] locator
|
78
|
+
# Label, id, or name of the field to match
|
79
|
+
#
|
80
|
+
def select(locator)
|
81
|
+
locate_field(descendant(:select), locator)
|
82
|
+
end
|
52
83
|
|
53
|
-
[options[:selected]].flatten.each do |option|
|
54
|
-
xpath = xpath[descendant(:option)[attr(:selected)].equals(option)]
|
55
|
-
end if options[:selected]
|
56
84
|
|
57
|
-
|
85
|
+
# Match any `input` element of type `checkbox`.
|
86
|
+
#
|
87
|
+
# @param [String] locator
|
88
|
+
# Label, id, or name of the checkbox to match
|
89
|
+
#
|
90
|
+
def checkbox(locator)
|
91
|
+
locate_field(descendant(:input)[attr(:type).equals('checkbox')], locator)
|
58
92
|
end
|
59
93
|
|
60
|
-
def checkbox(locator, options={})
|
61
|
-
xpath = locate_field(descendant(:input)[attr(:type).equals('checkbox')], locator)
|
62
|
-
end
|
63
94
|
|
64
|
-
|
95
|
+
# Match any `input` element of type `radio`.
|
96
|
+
#
|
97
|
+
# @param [String] locator
|
98
|
+
# Label, id, or name of the radio button to match
|
99
|
+
#
|
100
|
+
def radio_button(locator)
|
65
101
|
locate_field(descendant(:input)[attr(:type).equals('radio')], locator)
|
66
102
|
end
|
67
103
|
|
68
|
-
|
104
|
+
|
105
|
+
# Match any `input` element of type `file`.
|
106
|
+
#
|
107
|
+
# @param [String] locator
|
108
|
+
# Label, id, or name of the file field to match
|
109
|
+
#
|
110
|
+
def file_field(locator)
|
69
111
|
locate_field(descendant(:input)[attr(:type).equals('file')], locator)
|
70
112
|
end
|
71
113
|
|
114
|
+
|
115
|
+
# Match an `optgroup` element.
|
116
|
+
#
|
117
|
+
# @param [String] name
|
118
|
+
# Label for the option group
|
119
|
+
#
|
72
120
|
def optgroup(name)
|
73
|
-
descendant(:optgroup)[attr(:label).
|
121
|
+
descendant(:optgroup)[attr(:label).contains(name)]
|
74
122
|
end
|
75
123
|
|
76
|
-
def option(name)
|
77
|
-
descendant(:option)[string.n.is(name)]
|
78
|
-
end
|
79
124
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
125
|
+
# Match an `option` element.
|
126
|
+
#
|
127
|
+
# @param [String] name
|
128
|
+
# Visible text of the option
|
129
|
+
#
|
130
|
+
def option(name)
|
131
|
+
descendant(:option)[string.n.equals(name)]
|
84
132
|
end
|
85
133
|
|
86
|
-
def table_rows(rows)
|
87
|
-
row_conditions = descendant(:tr)[table_row(rows.first)]
|
88
|
-
rows.drop(1).each do |row|
|
89
|
-
row_conditions = row_conditions.next_sibling(:tr)[table_row(row)]
|
90
|
-
end
|
91
|
-
row_conditions
|
92
|
-
end
|
93
134
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
135
|
+
# Match any `table` element.
|
136
|
+
#
|
137
|
+
# @param [String] locator
|
138
|
+
# Caption or id of the table to match
|
139
|
+
# @option options [Array] :rows
|
140
|
+
# Content of each cell in each row to match
|
141
|
+
#
|
142
|
+
def table(locator)
|
143
|
+
descendant(:table)[attr(:id).equals(locator) | descendant(:caption).contains(locator)]
|
100
144
|
end
|
101
145
|
|
102
146
|
protected
|
103
147
|
|
104
148
|
def locate_field(xpath, locator)
|
105
|
-
locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.
|
106
|
-
locate_field += descendant(:label)[string.n.
|
149
|
+
locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.contains(locator)].attr(:for))]
|
150
|
+
locate_field += descendant(:label)[string.n.contains(locator)].descendant(xpath)
|
107
151
|
end
|
108
|
-
|
109
|
-
def field_value(value)
|
110
|
-
(string.n.is(value) & tag(:textarea)) | (attr(:value).equals(value) & ~tag(:textarea))
|
111
|
-
end
|
112
|
-
|
113
152
|
end
|
114
153
|
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module XPath
|
2
|
+
class Renderer
|
3
|
+
def self.render(node)
|
4
|
+
new.render(node)
|
5
|
+
end
|
6
|
+
|
7
|
+
def render(node)
|
8
|
+
arguments = node.arguments.map { |argument| convert_argument(argument) }
|
9
|
+
send(node.expression, *arguments)
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert_argument(argument)
|
13
|
+
case argument
|
14
|
+
when Expression, Union then render(argument)
|
15
|
+
when Array then argument.map { |element| convert_argument(element) }
|
16
|
+
when String then string_literal(argument)
|
17
|
+
when Literal then argument.value
|
18
|
+
else argument.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def string_literal(string)
|
23
|
+
if string.include?("'")
|
24
|
+
string = string.split("'", -1).map do |substr|
|
25
|
+
"'#{substr}'"
|
26
|
+
end.join(%q{,"'",})
|
27
|
+
"concat(#{string})"
|
28
|
+
else
|
29
|
+
"'#{string}'"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def this_node
|
34
|
+
'.'
|
35
|
+
end
|
36
|
+
|
37
|
+
def descendant(parent, element_names)
|
38
|
+
if element_names.length == 1
|
39
|
+
"#{parent}//#{element_names.first}"
|
40
|
+
elsif element_names.length > 1
|
41
|
+
"#{parent}//*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
|
42
|
+
else
|
43
|
+
"#{parent}//*"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def child(parent, element_names)
|
48
|
+
if element_names.length == 1
|
49
|
+
"#{parent}/#{element_names.first}"
|
50
|
+
elsif element_names.length > 1
|
51
|
+
"#{parent}/*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
|
52
|
+
else
|
53
|
+
"#{parent}/*"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def axis(parent, name, tag_name)
|
58
|
+
"#{parent}/#{name}::#{tag_name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def node_name(current)
|
62
|
+
"name(#{current})"
|
63
|
+
end
|
64
|
+
|
65
|
+
def where(on, condition)
|
66
|
+
"#{on}[#{condition}]"
|
67
|
+
end
|
68
|
+
|
69
|
+
def attribute(current, name)
|
70
|
+
"#{current}/@#{name}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def equality(one, two)
|
74
|
+
"#{one} = #{two}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def variable(name)
|
78
|
+
"%{#{name}}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def text(current)
|
82
|
+
"#{current}/text()"
|
83
|
+
end
|
84
|
+
|
85
|
+
def normalized_space(current)
|
86
|
+
"normalize-space(#{current})"
|
87
|
+
end
|
88
|
+
|
89
|
+
def literal(node)
|
90
|
+
node
|
91
|
+
end
|
92
|
+
|
93
|
+
def css(current, selector)
|
94
|
+
paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
|
95
|
+
"#{current}#{xpath_selector}"
|
96
|
+
end
|
97
|
+
union(paths)
|
98
|
+
end
|
99
|
+
|
100
|
+
def union(*expressions)
|
101
|
+
expressions.join(' | ')
|
102
|
+
end
|
103
|
+
|
104
|
+
def anywhere(tag_name)
|
105
|
+
"//#{tag_name}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def contains(current, value)
|
109
|
+
"contains(#{current}, #{value})"
|
110
|
+
end
|
111
|
+
|
112
|
+
def starts_with(current, value)
|
113
|
+
"starts-with(#{current}, #{value})"
|
114
|
+
end
|
115
|
+
|
116
|
+
def and(one, two)
|
117
|
+
"(#{one} and #{two})"
|
118
|
+
end
|
119
|
+
|
120
|
+
def or(one, two)
|
121
|
+
"(#{one} or #{two})"
|
122
|
+
end
|
123
|
+
|
124
|
+
def one_of(current, values)
|
125
|
+
values.map { |value| "#{current} = #{value}" }.join(' or ')
|
126
|
+
end
|
127
|
+
|
128
|
+
def next_sibling(current, element_names)
|
129
|
+
if element_names.length == 1
|
130
|
+
"#{current}/following-sibling::*[1]/self::#{element_names.first}"
|
131
|
+
elsif element_names.length > 1
|
132
|
+
"#{current}/following-sibling::*[1]/self::*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
|
133
|
+
else
|
134
|
+
"#{current}/following-sibling::*[1]/self::*"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def inverse(current)
|
139
|
+
"not(#{current})"
|
140
|
+
end
|
141
|
+
|
142
|
+
def string_function(current)
|
143
|
+
"string(#{current})"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/xpath/union.rb
CHANGED
@@ -3,29 +3,27 @@ module XPath
|
|
3
3
|
include Enumerable
|
4
4
|
|
5
5
|
attr_reader :expressions
|
6
|
+
alias_method :arguments, :expressions
|
6
7
|
|
7
8
|
def initialize(*expressions)
|
8
9
|
@expressions = expressions
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_s
|
16
|
-
to_xpaths.join(' | ')
|
12
|
+
def expression
|
13
|
+
:union
|
17
14
|
end
|
18
15
|
|
19
|
-
def
|
20
|
-
|
16
|
+
def each(&block)
|
17
|
+
arguments.each(&block)
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
24
|
-
|
20
|
+
def method_missing(*args)
|
21
|
+
XPath::Union.new(*arguments.map { |e| e.send(*args) })
|
25
22
|
end
|
26
23
|
|
27
|
-
def
|
28
|
-
|
24
|
+
def to_xpath
|
25
|
+
Renderer.render(self)
|
29
26
|
end
|
27
|
+
alias_method :to_s, :to_xpath
|
30
28
|
end
|
31
29
|
end
|
data/lib/xpath/version.rb
CHANGED
data/spec/fixtures/form.html
CHANGED
@@ -28,7 +28,15 @@
|
|
28
28
|
<input type="submit" title="My submit title" value="submit-with-title" data="title-submit">
|
29
29
|
<input type="submit" title="Exact submit title" value="exact title submit" data="exact-title-submit">
|
30
30
|
<input type="submit" title="Not Exact submit title" value="exact title submit" data="not-exact-title-submit">
|
31
|
-
|
31
|
+
|
32
|
+
<input type="reset" id="reset-with-id" data="id-reset" value="Has ID"/>
|
33
|
+
<input type="reset" value="reset-with-value" data="value-reset"/>
|
34
|
+
<input type="reset" value="not exact value reset" data="not-exact-value-reset"/>
|
35
|
+
<input type="reset" value="exact value reset" data="exact-value-reset"/>
|
36
|
+
<input type="reset" title="My reset title" value="reset-with-title" data="title-reset">
|
37
|
+
<input type="reset" title="Exact reset title" value="exact title reset" data="exact-title-reset">
|
38
|
+
<input type="reset" title="Not Exact reset title" value="exact title reset" data="not-exact-title-reset">
|
39
|
+
|
32
40
|
<input type="button" id="button-with-id" data="id-button" value="Has ID"/>
|
33
41
|
<input type="button" value="button-with-value" data="value-button"/>
|
34
42
|
<input type="button" value="not exact value button" data="not-exact-value-button"/>
|
@@ -46,10 +54,10 @@
|
|
46
54
|
<input type="image" title="Not Exact imgbut title" value="not exact title imgbut" data="not-exact-title-imgbut">
|
47
55
|
<input type="image" title="Exact imgbut title" value="exact title imgbut" data="exact-title-imgbut">
|
48
56
|
|
49
|
-
<button id="btag-with-id" data="id-btag" value="Has ID"
|
50
|
-
<button value="btag-with-value" data="value-btag"
|
51
|
-
<button value="not exact value btag" data="not-exact-value-btag"
|
52
|
-
<button value="exact value btag" data="exact-value-btag"
|
57
|
+
<button id="btag-with-id" data="id-btag" value="Has ID"></button>
|
58
|
+
<button value="btag-with-value" data="value-btag"></button>
|
59
|
+
<button value="not exact value btag" data="not-exact-value-btag"></button>
|
60
|
+
<button value="exact value btag" data="exact-value-btag"></button>
|
53
61
|
|
54
62
|
<button data="text-btag">btag-with-text</button>
|
55
63
|
<button data="not-exact-text-btag">not exact text btag</button>
|
@@ -77,16 +85,30 @@
|
|
77
85
|
<fieldset data="fieldset-legend-span"><legend><span>Span Legend</span></legend></fieldset>
|
78
86
|
<fieldset data="fieldset-fuzzy"><legend>Long legend yo</legend></fieldset>
|
79
87
|
<fieldset data="fieldset-exact"><legend>Long legend</legend></fieldset>
|
88
|
+
<fieldset data="fieldset-outer"><legend>Outer legend</legend>
|
89
|
+
<fieldset data="fieldset-inner"><legend>Inner legend</legend></fieldset>
|
90
|
+
</fieldset>
|
80
91
|
</p>
|
81
92
|
|
82
93
|
<p>
|
83
94
|
<select>
|
84
95
|
<optgroup label="Group A" data="optgroup-a"></optgroup>
|
85
96
|
<optgroup label="Group B" data="optgroup-b"></optgroup>
|
97
|
+
<option data="option-with-text-data">Option with text</option>
|
86
98
|
</select>
|
87
99
|
</p>
|
88
100
|
|
89
|
-
<
|
101
|
+
<h2>Tables</h2>
|
102
|
+
|
103
|
+
<table id="table-with-id" data="table-with-id-data">
|
104
|
+
<tr><td>First</td><td>Second</td></tr>
|
105
|
+
</table>
|
106
|
+
|
107
|
+
<table data="table-with-caption-data">
|
108
|
+
<caption>Table with caption</caption>
|
109
|
+
<tr><td>First</td><td>Second</td></tr>
|
110
|
+
</table>
|
111
|
+
|
90
112
|
<table id="whitespaced-table" data="table-with-whitespace">
|
91
113
|
<tr>
|
92
114
|
<td data="cell-whitespaced">I have
|
@@ -95,7 +117,7 @@
|
|
95
117
|
<td>I don't</td>
|
96
118
|
</tr>
|
97
119
|
</table>
|
98
|
-
|
120
|
+
|
99
121
|
|
100
122
|
<p>
|
101
123
|
<h2>Fields</h2>
|
@@ -103,6 +125,7 @@
|
|
103
125
|
<h4>With id</h4>
|
104
126
|
<input id="input-with-id" value="correct-value" data="input-with-id-data"/>
|
105
127
|
<input type="text" id="input-text-with-id" data="input-text-with-id-data"/>
|
128
|
+
<input type="file" id="input-file-with-id" data="input-file-with-id-data"/>
|
106
129
|
<input type="password" id="input-password-with-id" data="input-password-with-id-data"/>
|
107
130
|
<input type="custom" id="input-custom-with-id" data="input-custom-with-id-data"/>
|
108
131
|
<textarea id="textarea-with-id" data="textarea-with-id-data">Correct value</textarea>
|
@@ -110,10 +133,13 @@
|
|
110
133
|
<input type="submit" id="input-submit-with-id" data="input-submit-with-id-data"/>
|
111
134
|
<input type="image" id="input-image-with-id" data="input-image-with-id-data"/>
|
112
135
|
<input type="hidden" id="input-hidden-with-id" data="input-hidden-with-id-data"/>
|
136
|
+
<input type="checkbox" id="input-checkbox-with-id" data="input-checkbox-with-id-data"/>
|
137
|
+
<input type="radio" id="input-radio-with-id" data="input-radio-with-id-data"/>
|
113
138
|
|
114
139
|
<h4>With name</h4>
|
115
140
|
<input name="input-with-name" data="input-with-name-data"/>
|
116
141
|
<input type="text" name="input-text-with-name" data="input-text-with-name-data"/>
|
142
|
+
<input type="file" name="input-file-with-name" data="input-file-with-name-data"/>
|
117
143
|
<input type="password" name="input-password-with-name" data="input-password-with-name-data"/>
|
118
144
|
<input type="custom" name="input-custom-with-name" data="input-custom-with-name-data"/>
|
119
145
|
<textarea name="textarea-with-name" data="textarea-with-name-data"></textarea>
|
@@ -121,10 +147,21 @@
|
|
121
147
|
<input type="submit" name="input-submit-with-name" data="input-submit-with-name-data"/>
|
122
148
|
<input type="image" name="input-image-with-name" data="input-image-with-name-data"/>
|
123
149
|
<input type="hidden" name="input-hidden-with-name" data="input-hidden-with-name-data"/>
|
150
|
+
<input type="checkbox" name="input-checkbox-with-name" data="input-checkbox-with-name-data"/>
|
151
|
+
<input type="radio" name="input-radio-with-name" data="input-radio-with-name-data"/>
|
152
|
+
|
153
|
+
<h4>With placeholder</h4>
|
154
|
+
<input name="input-with-placeholder" data="input-with-placeholder-data"/>
|
155
|
+
<input type="text" placeholder="input-text-with-placeholder" data="input-text-with-placeholder-data"/>
|
156
|
+
<input type="password" placeholder="input-password-with-placeholder" data="input-password-with-placeholder-data"/>
|
157
|
+
<input type="custom" placeholder="input-custom-with-placeholder" data="input-custom-with-placeholder-data"/>
|
158
|
+
<textarea placeholder="textarea-with-placeholder" data="textarea-with-placeholder-data"></textarea>
|
159
|
+
<input type="hidden" placeholder="input-hidden-with-placeholder" data="input-hidden-with-placeholder-data"/>
|
124
160
|
|
125
161
|
<h4>With referenced label</h4>
|
126
162
|
<label for="input-with-label">Input with label</label><input id="input-with-label" data="input-with-label-data"/>
|
127
163
|
<label for="input-text-with-label">Input text with label</label><input type="text" id="input-text-with-label" data="input-text-with-label-data"/>
|
164
|
+
<label for="input-file-with-label">Input file with label</label><input type="file" id="input-file-with-label" data="input-file-with-label-data"/>
|
128
165
|
<label for="input-password-with-label">Input password with label</label><input type="password" id="input-password-with-label" data="input-password-with-label-data"/>
|
129
166
|
<label for="input-custom-with-label">Input custom with label</label><input type="custom" id="input-custom-with-label" data="input-custom-with-label-data"/>
|
130
167
|
<label for="textarea-with-label">Textarea with label</label><textarea id="textarea-with-label" data="textarea-with-label-data"></textarea>
|
@@ -132,10 +169,13 @@
|
|
132
169
|
<label for="input-submit-with-label">Input submit with label</label><input type="submit" id="input-submit-with-label" data="input-submit-with-label-data"/>
|
133
170
|
<label for="input-image-with-label">Input image with label</label><input type="image" id="input-image-with-label" data="input-image-with-label-data"/>
|
134
171
|
<label for="input-hidden-with-label">Input hidden with label</label><input type="hidden" id="input-hidden-with-label" data="input-hidden-with-label-data"/>
|
172
|
+
<label for="input-checkbox-with-label">Input checkbox with label</label><input type="checkbox" id="input-checkbox-with-label" data="input-checkbox-with-label-data"/>
|
173
|
+
<label for="input-radio-with-label">Input radio with label</label><input type="radio" id="input-radio-with-label" data="input-radio-with-label-data"/>
|
135
174
|
|
136
175
|
<h4>With parent label</h4>
|
137
176
|
<label>Input with parent label<input data="input-with-parent-label-data"/></label>
|
138
177
|
<label>Input text with parent label<input type="text" data="input-text-with-parent-label-data"/></label>
|
178
|
+
<label>Input file with parent label<input type="file" data="input-file-with-parent-label-data"/></label>
|
139
179
|
<label>Input password with parent label<input type="password" data="input-password-with-parent-label-data"/></label>
|
140
180
|
<label>Input custom with parent label<input type="custom" data="input-custom-with-parent-label-data"/></label>
|
141
181
|
<label>Textarea with parent label<textarea data="textarea-with-parent-label-data"></textarea></label>
|
@@ -143,4 +183,6 @@
|
|
143
183
|
<label>Input submit with parent label<input type="submit" data="input-submit-with-parent-label-data"/></label>
|
144
184
|
<label>Input image with parent label<input type="image" data="input-image-with-parent-label-data"/></label>
|
145
185
|
<label>Input hidden with parent label<input type="hidden" data="input-hidden-with-parent-label-data"/></label>
|
186
|
+
<label>Input checkbox with parent label<input type="checkbox" data="input-checkbox-with-parent-label-data"/></label>
|
187
|
+
<label>Input radio with parent label<input type="radio" data="input-radio-with-parent-label-data"/></label>
|
146
188
|
</p>
|