hatemile 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +46 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE +202 -0
  5. data/Rakefile +64 -0
  6. data/hatemile.gemspec +37 -0
  7. data/lib/hatemile/accessible_association.rb +62 -0
  8. data/lib/hatemile/accessible_css.rb +43 -0
  9. data/lib/hatemile/accessible_display.rb +178 -0
  10. data/lib/hatemile/accessible_event.rb +95 -0
  11. data/lib/hatemile/accessible_form.rb +101 -0
  12. data/lib/hatemile/accessible_navigation.rb +82 -0
  13. data/lib/hatemile/helper.rb +58 -0
  14. data/lib/hatemile/implementation/accessible_association_implementation.rb +346 -0
  15. data/lib/hatemile/implementation/accessible_css_implementation.rb +772 -0
  16. data/lib/hatemile/implementation/accessible_display_implementation.rb +1362 -0
  17. data/lib/hatemile/implementation/accessible_event_implementation.rb +278 -0
  18. data/lib/hatemile/implementation/accessible_form_implementation.rb +386 -0
  19. data/lib/hatemile/implementation/accessible_navigation_implementation.rb +561 -0
  20. data/lib/hatemile/util/common_functions.rb +106 -0
  21. data/lib/hatemile/util/configure.rb +92 -0
  22. data/lib/hatemile/util/css/rcp/rcp_declaration.rb +77 -0
  23. data/lib/hatemile/util/css/rcp/rcp_parser.rb +115 -0
  24. data/lib/hatemile/util/css/rcp/rcp_rule.rb +86 -0
  25. data/lib/hatemile/util/css/style_sheet_declaration.rb +59 -0
  26. data/lib/hatemile/util/css/style_sheet_parser.rb +43 -0
  27. data/lib/hatemile/util/css/style_sheet_rule.rb +73 -0
  28. data/lib/hatemile/util/html/html_dom_element.rb +234 -0
  29. data/lib/hatemile/util/html/html_dom_node.rb +131 -0
  30. data/lib/hatemile/util/html/html_dom_parser.rb +150 -0
  31. data/lib/hatemile/util/html/html_dom_text_node.rb +43 -0
  32. data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_element.rb +302 -0
  33. data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_node.rb +112 -0
  34. data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_parser.rb +208 -0
  35. data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_text_node.rb +83 -0
  36. data/lib/hatemile/util/id_generator.rb +53 -0
  37. data/lib/js/common.js +98 -0
  38. data/lib/js/eventlistener.js +36 -0
  39. data/lib/js/include.js +292 -0
  40. data/lib/js/scriptlist_validation_fields.js +13 -0
  41. data/lib/js/validation.js +205 -0
  42. data/lib/locale/en-US.yml +388 -0
  43. data/lib/locale/pt-BR.yml +389 -0
  44. data/lib/skippers.xml +6 -0
  45. data/lib/symbols.xml +40 -0
  46. data/test/locale/en-US.yml +5 -0
  47. data/test/locale/pt-BR.yml +4 -0
  48. data/test/test_accessible_association_implementation.rb +258 -0
  49. data/test/test_accessible_css_implementation.rb +518 -0
  50. data/test/test_accessible_display_implementation.rb +873 -0
  51. data/test/test_accessible_form_implementation.rb +283 -0
  52. data/test/test_accessible_navigation_implementation.rb +228 -0
  53. data/test/test_common_functions.rb +128 -0
  54. data/test/test_configure.rb +73 -0
  55. data/test/test_nokogiri_html_dom_element.rb +586 -0
  56. data/test/test_nokogiri_html_dom_parser.rb +363 -0
  57. data/test/test_nokogiri_html_dom_text_node.rb +225 -0
  58. data/test/test_rcp_declaration.rb +103 -0
  59. data/test/test_rcp_parser.rb +86 -0
  60. data/test/test_rcp_rule.rb +89 -0
  61. metadata +199 -0
@@ -0,0 +1,278 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require File.join(File.dirname(File.dirname(__FILE__)), 'accessible_event')
14
+ require File.join(File.dirname(File.dirname(__FILE__)), 'helper')
15
+ require File.join(
16
+ File.dirname(File.dirname(__FILE__)),
17
+ 'util',
18
+ 'common_functions'
19
+ )
20
+ require File.join(
21
+ File.dirname(File.dirname(__FILE__)),
22
+ 'util',
23
+ 'html',
24
+ 'html_dom_parser'
25
+ )
26
+ require File.join(File.dirname(File.dirname(__FILE__)), 'util', 'id_generator')
27
+
28
+ ##
29
+ # The Hatemile module contains the interfaces with the acessibility solutions.
30
+ module Hatemile
31
+ ##
32
+ # The Hatemile::Implementation module contains the official implementation of
33
+ # interfaces solutions.
34
+ module Implementation
35
+ ##
36
+ # The AccessibleEventImplementation class is official implementation of
37
+ # AccessibleEvent interface.
38
+ class AccessibleEventImplementation < AccessibleEvent
39
+ public_class_method :new
40
+
41
+ ##
42
+ # The id of script element that replace the event listener methods.
43
+ ID_SCRIPT_EVENT_LISTENER = 'script-eventlistener'.freeze
44
+
45
+ ##
46
+ # The id of script element that contains the list of elements that has
47
+ # inaccessible events.
48
+ ID_LIST_IDS_SCRIPT = 'list-ids-script'.freeze
49
+
50
+ ##
51
+ # The id of script element that modify the events of elements.
52
+ ID_FUNCTION_SCRIPT_FIX = 'id-function-script-fix'.freeze
53
+
54
+ ##
55
+ # The ID of script element that contains the common functions of scripts.
56
+ ID_SCRIPT_COMMON_FUNCTIONS = 'hatemile-common-functions'.freeze
57
+
58
+ protected
59
+
60
+ ##
61
+ # Provide keyboard access for element, if it not has.
62
+ #
63
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The element.
64
+ # @return [void]
65
+ def keyboard_access(element)
66
+ return if element.has_attribute?('tabindex')
67
+
68
+ tag = element.get_tag_name
69
+ if (tag == 'A') && !element.has_attribute?('href')
70
+ element.set_attribute('tabindex', '0')
71
+ elsif (tag != 'A') &&
72
+ (tag != 'INPUT') &&
73
+ (tag != 'BUTTON') &&
74
+ (tag != 'SELECT') &&
75
+ (tag != 'TEXTAREA')
76
+ element.set_attribute('tabindex', '0')
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Include the scripts used by solutions.
82
+ #
83
+ # @return [void]
84
+ def generate_main_scripts
85
+ head = @parser.find('head').first_result
86
+ unless head.nil?
87
+ common_functions_script = @parser.find(
88
+ "##{ID_SCRIPT_COMMON_FUNCTIONS}"
89
+ ).first_result
90
+ if common_functions_script.nil?
91
+ common_functions_script = @parser.create_element('script')
92
+ common_functions_script.set_attribute(
93
+ 'id',
94
+ ID_SCRIPT_COMMON_FUNCTIONS
95
+ )
96
+ common_functions_script.set_attribute('type', 'text/javascript')
97
+ common_functions_script.append_text(
98
+ File.read(
99
+ File.join(
100
+ File.dirname(File.dirname(File.dirname(__FILE__))),
101
+ 'js',
102
+ 'common.js'
103
+ )
104
+ )
105
+ )
106
+ head.prepend_element(common_functions_script)
107
+ end
108
+
109
+ if @parser.find("##{ID_SCRIPT_EVENT_LISTENER}").first_result.nil?
110
+ script = @parser.create_element('script')
111
+ script.set_attribute('id', ID_SCRIPT_EVENT_LISTENER)
112
+ script.set_attribute('type', 'text/javascript')
113
+ script.append_text(
114
+ File.read(
115
+ File.join(
116
+ File.dirname(File.dirname(File.dirname(__FILE__))),
117
+ 'js',
118
+ 'eventlistener.js'
119
+ )
120
+ )
121
+ )
122
+ common_functions_script.insert_after(script)
123
+ end
124
+ end
125
+ local = @parser.find('body').first_result
126
+ unless local.nil?
127
+ @script_list = @parser.find("##{ID_LIST_IDS_SCRIPT}").first_result
128
+ if @script_list.nil?
129
+ @script_list = @parser.create_element('script')
130
+ @script_list.set_attribute('id', ID_LIST_IDS_SCRIPT)
131
+ @script_list.set_attribute('type', 'text/javascript')
132
+ @script_list.append_text('var activeElements = [];')
133
+ @script_list.append_text('var hoverElements = [];')
134
+ @script_list.append_text('var dragElements = [];')
135
+ @script_list.append_text('var dropElements = [];')
136
+ local.append_element(@script_list)
137
+ end
138
+ if @parser.find("##{ID_FUNCTION_SCRIPT_FIX}").first_result.nil?
139
+ script_function = @parser.create_element('script')
140
+ script_function.set_attribute('id', ID_FUNCTION_SCRIPT_FIX)
141
+ script_function.set_attribute('type', 'text/javascript')
142
+ script_function.append_text(
143
+ File.read(
144
+ File.join(
145
+ File.dirname(File.dirname(File.dirname(__FILE__))),
146
+ 'js',
147
+ 'include.js'
148
+ )
149
+ )
150
+ )
151
+ local.append_element(script_function)
152
+ end
153
+ end
154
+ @main_script_added = true
155
+ end
156
+
157
+ ##
158
+ # Add a type of event in element.
159
+ #
160
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The element.
161
+ # @param event [String] The type of event.
162
+ # @return [void]
163
+ def add_event_in_element(element, event)
164
+ generate_main_scripts unless @main_script_added
165
+
166
+ return if @script_list.nil?
167
+
168
+ @id_generator.generate_id(element)
169
+ @script_list.append_text(
170
+ "#{event}Elements.push('#{element.get_attribute('id')}');"
171
+ )
172
+ end
173
+
174
+ public
175
+
176
+ ##
177
+ # Initializes a new object that manipulate the accessibility of the
178
+ # Javascript events of elements of parser.
179
+ #
180
+ # @param parser [Hatemile::Util::Html::HTMLDOMParser] The HTML parser.
181
+ def initialize(parser)
182
+ Hatemile::Helper.require_not_nil(parser)
183
+ Hatemile::Helper.require_valid_type(
184
+ parser,
185
+ Hatemile::Util::Html::HTMLDOMParser
186
+ )
187
+
188
+ @parser = parser
189
+ @id_generator = Hatemile::Util::IDGenerator.new('event')
190
+ @main_script_added = false
191
+ @script_list = nil
192
+ end
193
+
194
+ ##
195
+ # @see Hatemile::AccessibleEvent#make_accessible_drop_events
196
+ def make_accessible_drop_events(element)
197
+ element.set_attribute('aria-dropeffect', 'none')
198
+
199
+ add_event_in_element(element, 'drop')
200
+ end
201
+
202
+ ##
203
+ # @see Hatemile::AccessibleEvent#make_accessible_drag_events
204
+ def make_accessible_drag_events(element)
205
+ keyboard_access(element)
206
+
207
+ element.set_attribute('aria-grabbed', 'false')
208
+
209
+ add_event_in_element(element, 'drag')
210
+ end
211
+
212
+ ##
213
+ # @see Hatemile::AccessibleEvent#make_accessible_all_drag_and_drop_events
214
+ def make_accessible_all_drag_and_drop_events
215
+ draggable_elements = @parser.find(
216
+ '[ondrag],[ondragstart],[ondragend]'
217
+ ).list_results
218
+ draggable_elements.each do |draggable_element|
219
+ next unless Hatemile::Util::CommonFunctions.is_valid_element?(
220
+ draggable_element
221
+ )
222
+
223
+ make_accessible_drag_events(draggable_element)
224
+ end
225
+ droppable_elements = @parser.find(
226
+ '[ondrop],[ondragenter],[ondragleave],[ondragover]'
227
+ ).list_results
228
+ droppable_elements.each do |droppable_element|
229
+ next unless Hatemile::Util::CommonFunctions.is_valid_element?(
230
+ droppable_element
231
+ )
232
+
233
+ make_accessible_drop_events(droppable_element)
234
+ end
235
+ end
236
+
237
+ ##
238
+ # @see Hatemile::AccessibleEvent#make_accessible_hover_events
239
+ def make_accessible_hover_events(element)
240
+ keyboard_access(element)
241
+
242
+ add_event_in_element(element, 'hover')
243
+ end
244
+
245
+ ##
246
+ # @see Hatemile::AccessibleEvent#make_accessible_all_hover_events
247
+ def make_accessible_all_hover_events
248
+ elements = @parser.find('[onmouseover],[onmouseout]').list_results
249
+ elements.each do |element|
250
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
251
+ make_accessible_hover_events(element)
252
+ end
253
+ end
254
+ end
255
+
256
+ ##
257
+ # @see Hatemile::AccessibleEvent#make_accessible_click_events
258
+ def make_accessible_click_events(element)
259
+ keyboard_access(element)
260
+
261
+ add_event_in_element(element, 'active')
262
+ end
263
+
264
+ ##
265
+ # @see Hatemile::AccessibleEvent#make_accessible_all_click_events
266
+ def make_accessible_all_click_events
267
+ elements = @parser.find(
268
+ '[onclick],[onmousedown],[onmouseup],[ondblclick]'
269
+ ).list_results
270
+ elements.each do |element|
271
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
272
+ make_accessible_click_events(element)
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,386 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require File.join(File.dirname(File.dirname(__FILE__)), 'accessible_form')
14
+ require File.join(File.dirname(File.dirname(__FILE__)), 'helper')
15
+ require File.join(File.dirname(__FILE__), 'accessible_event_implementation')
16
+ require File.join(
17
+ File.dirname(File.dirname(__FILE__)),
18
+ 'util',
19
+ 'common_functions'
20
+ )
21
+ require File.join(File.dirname(File.dirname(__FILE__)), 'util', 'id_generator')
22
+ require File.join(
23
+ File.dirname(File.dirname(__FILE__)),
24
+ 'util',
25
+ 'html',
26
+ 'html_dom_parser'
27
+ )
28
+
29
+ ##
30
+ # The Hatemile module contains the interfaces with the acessibility solutions.
31
+ module Hatemile
32
+ ##
33
+ # The Hatemile::Implementation module contains the official implementation of
34
+ # interfaces solutions.
35
+ module Implementation
36
+ ##
37
+ # The AccessibleFormImplementation class is official implementation of
38
+ # AccessibleForm interface.
39
+ class AccessibleFormImplementation < AccessibleForm
40
+ public_class_method :new
41
+
42
+ ##
43
+ # The ID of script element that contains the list of IDs of fields with
44
+ # validation.
45
+ ID_SCRIPT_LIST_VALIDATION_FIELDS =
46
+ 'hatemile-scriptlist-validation-fields'.freeze
47
+
48
+ ##
49
+ # The ID of script element that execute validations on fields.
50
+ ID_SCRIPT_EXECUTE_VALIDATION = 'hatemile-validation-script'.freeze
51
+
52
+ ##
53
+ # The client-site required fields list.
54
+ REQUIRED_FIELDS_LIST = 'required_fields'.freeze
55
+
56
+ ##
57
+ # The client-site pattern fields list.
58
+ PATTERN_FIELDS_LIST = 'pattern_fields'.freeze
59
+
60
+ ##
61
+ # The client-site fields with length list.
62
+ LIMITED_FIELDS_LIST = 'fields_with_length'.freeze
63
+
64
+ ##
65
+ # The client-site range fields list.
66
+ RANGE_FIELDS_LIST = 'range_fields'.freeze
67
+
68
+ ##
69
+ # The client-site week fields list.
70
+ WEEK_FIELDS_LIST = 'week_fields'.freeze
71
+
72
+ ##
73
+ # The client-site month fields list.
74
+ MONTH_FIELDS_LIST = 'month_fields'.freeze
75
+
76
+ ##
77
+ # The client-site datetime fields list.
78
+ DATETIME_FIELDS_LIST = 'datetime_fields'.freeze
79
+
80
+ ##
81
+ # The client-site time fields list.
82
+ TIME_FIELDS_LIST = 'time_fields'.freeze
83
+
84
+ ##
85
+ # The client-site date fields list.
86
+ DATE_FIELDS_LIST = 'date_fields'.freeze
87
+
88
+ ##
89
+ # The client-site email fields list.
90
+ EMAIL_FIELDS_LIST = 'email_fields'.freeze
91
+
92
+ ##
93
+ # The client-site URL fields list.
94
+ URL_FIELDS_LIST = 'url_fields'.freeze
95
+
96
+ protected
97
+
98
+ ##
99
+ # Returns the appropriate value for attribute aria-autocomplete of field.
100
+ #
101
+ # @param field [Hatemile::Util::Html::HTMLDOMElement] The field.
102
+ # @return [String] The ARIA value of field.
103
+ def get_aria_autocomplete(field)
104
+ tag_name = field.get_tag_name
105
+ type = nil
106
+ if field.has_attribute?('type')
107
+ type = field.get_attribute('type').downcase
108
+ end
109
+ if (tag_name == 'TEXTAREA') ||
110
+ (
111
+ (tag_name == 'INPUT') &&
112
+ !(
113
+ (type == 'button') ||
114
+ (type == 'submit') ||
115
+ (type == 'reset') ||
116
+ (type == 'image') ||
117
+ (type == 'file') ||
118
+ (type == 'checkbox') ||
119
+ (type == 'radio') ||
120
+ (type == 'hidden')
121
+ )
122
+ )
123
+ value = nil
124
+ if field.has_attribute?('list')
125
+ list_id = field.get_attribute('list')
126
+ unless @parser.find("datalist[id=\"#{list_id}\"]").first_result.nil?
127
+ return 'list'
128
+ end
129
+ end
130
+ if field.has_attribute?('autocomplete')
131
+ value = field.get_attribute('autocomplete').downcase
132
+ else
133
+ form = @parser.find(field).find_ancestors('form').first_result
134
+ if form.nil? && field.has_attribute?('form')
135
+ form = @parser.find(
136
+ "##{field.get_attribute('form')}"
137
+ ).first_result
138
+ end
139
+ if !form.nil? && form.has_attribute?('autocomplete')
140
+ value = form.get_attribute('autocomplete').downcase
141
+ end
142
+ end
143
+ return 'both' if value == 'on'
144
+ return 'none' if value == 'off'
145
+ end
146
+ nil
147
+ end
148
+
149
+ ##
150
+ # Include the scripts used by solutions.
151
+ def generate_validation_scripts
152
+ local = @parser.find('head,body').first_result
153
+ unless local.nil?
154
+ if @parser.find(
155
+ "##{AccessibleEventImplementation::ID_SCRIPT_COMMON_FUNCTIONS}"
156
+ ).first_result.nil?
157
+ common_functions_script = @parser.create_element('script')
158
+ common_functions_script.set_attribute(
159
+ 'id',
160
+ AccessibleEventImplementation::ID_SCRIPT_COMMON_FUNCTIONS
161
+ )
162
+ common_functions_script.set_attribute('type', 'text/javascript')
163
+ common_functions_script.append_text(
164
+ File.read(
165
+ File.join(
166
+ File.dirname(File.dirname(File.dirname(__FILE__))),
167
+ 'js',
168
+ 'common.js'
169
+ )
170
+ )
171
+ )
172
+ local.prepend_element(common_functions_script)
173
+ end
174
+ end
175
+ @script_list_fields_with_validation = @parser.find(
176
+ "##{ID_SCRIPT_LIST_VALIDATION_FIELDS}"
177
+ ).first_result
178
+ if @script_list_fields_with_validation.nil?
179
+ @script_list_fields_with_validation = @parser.create_element('script')
180
+ @script_list_fields_with_validation.set_attribute(
181
+ 'id',
182
+ ID_SCRIPT_LIST_VALIDATION_FIELDS
183
+ )
184
+ @script_list_fields_with_validation.set_attribute(
185
+ 'type',
186
+ 'text/javascript'
187
+ )
188
+ @script_list_fields_with_validation.append_text(
189
+ File.read(
190
+ File.join(
191
+ File.dirname(File.dirname(File.dirname(__FILE__))),
192
+ 'js',
193
+ 'scriptlist_validation_fields.js'
194
+ )
195
+ )
196
+ )
197
+ local.append_element(@script_list_fields_with_validation)
198
+ end
199
+ if @parser.find("##{ID_SCRIPT_EXECUTE_VALIDATION}").first_result.nil?
200
+ script_function = @parser.create_element('script')
201
+ script_function.set_attribute('id', ID_SCRIPT_EXECUTE_VALIDATION)
202
+ script_function.set_attribute('type', 'text/javascript')
203
+ script_function.append_text(
204
+ File.read(
205
+ File.join(
206
+ File.dirname(File.dirname(File.dirname(__FILE__))),
207
+ 'js',
208
+ 'validation.js'
209
+ )
210
+ )
211
+ )
212
+ @parser.find('body').first_result.append_element(script_function)
213
+ end
214
+ @scripts_added = true
215
+ end
216
+
217
+ ##
218
+ # Validate the field when its value change.
219
+ #
220
+ # @param field [Hatemile::Util::Html::HTMLDOMElement] The field.
221
+ # @param list_attribute [String] The list attribute of field with
222
+ # validation.
223
+ def validate(field, list_attribute)
224
+ generate_validation_scripts unless @scripts_added
225
+ @id_generator.generate_id(field)
226
+ @script_list_fields_with_validation.append_text(
227
+ "hatemileValidationList.#{list_attribute}.push(" \
228
+ "'#{field.get_attribute('id')}');"
229
+ )
230
+ end
231
+
232
+ public
233
+
234
+ ##
235
+ # Initializes a new object that manipulate the accessibility of the forms
236
+ # of parser.
237
+ #
238
+ # @param parser [Hatemile::Util::Html::HTMLDOMParser] The HTML parser.
239
+ def initialize(parser)
240
+ Hatemile::Helper.require_not_nil(parser)
241
+ Hatemile::Helper.require_valid_type(
242
+ parser,
243
+ Hatemile::Util::Html::HTMLDOMParser
244
+ )
245
+
246
+ @parser = parser
247
+ @id_generator = Hatemile::Util::IDGenerator.new('form')
248
+ @scripts_added = false
249
+ @script_list_fields_with_validation = nil
250
+ end
251
+
252
+ ##
253
+ # @see Hatemile::AccessibleForm#mark_required_field
254
+ def mark_required_field(required_field)
255
+ return unless required_field.has_attribute?('required')
256
+
257
+ required_field.set_attribute('aria-required', 'true')
258
+ end
259
+
260
+ ##
261
+ # @see Hatemile::AccessibleForm#mark_all_required_fields
262
+ def mark_all_required_fields
263
+ required_fields = @parser.find('[required]').list_results
264
+ required_fields.each do |required_field|
265
+ if Hatemile::Util::CommonFunctions.is_valid_element?(required_field)
266
+ mark_required_field(required_field)
267
+ end
268
+ end
269
+ end
270
+
271
+ ##
272
+ # @see Hatemile::AccessibleForm#mark_range_field
273
+ def mark_range_field(range_field)
274
+ if range_field.has_attribute?('min')
275
+ range_field.set_attribute(
276
+ 'aria-valuemin',
277
+ range_field.get_attribute('min')
278
+ )
279
+ end
280
+
281
+ return unless range_field.has_attribute?('max')
282
+
283
+ range_field.set_attribute(
284
+ 'aria-valuemax',
285
+ range_field.get_attribute('max')
286
+ )
287
+ end
288
+
289
+ ##
290
+ # @see Hatemile::AccessibleForm#mark_all_range_fields
291
+ def mark_all_range_fields
292
+ range_fields = @parser.find('[min],[max]').list_results
293
+ range_fields.each do |range_field|
294
+ if Hatemile::Util::CommonFunctions.is_valid_element?(range_field)
295
+ mark_range_field(range_field)
296
+ end
297
+ end
298
+ end
299
+
300
+ ##
301
+ # @see Hatemile::AccessibleForm#mark_autocomplete_field
302
+ def mark_autocomplete_field(autocomplete_field)
303
+ aria_autocomplete = get_aria_autocomplete(autocomplete_field)
304
+
305
+ return if aria_autocomplete.nil?
306
+
307
+ autocomplete_field.set_attribute('aria-autocomplete', aria_autocomplete)
308
+ end
309
+
310
+ ##
311
+ # @see Hatemile::AccessibleForm#mark_all_autocomplete_fields
312
+ def mark_all_autocomplete_fields
313
+ elements = @parser.find(
314
+ 'input[autocomplete],textarea[autocomplete],form[autocomplete] ' \
315
+ 'input,form[autocomplete] textarea,[list],[form]'
316
+ ).list_results
317
+ elements.each do |element|
318
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
319
+ mark_autocomplete_field(element)
320
+ end
321
+ end
322
+ end
323
+
324
+ ##
325
+ # @see Hatemile::AccessibleForm#mark_invalid_field
326
+ def mark_invalid_field(field)
327
+ if field.has_attribute?('required') ||
328
+ (
329
+ field.has_attribute?('aria-required') &&
330
+ field.get_attribute('aria-required').casecmp('true').zero?
331
+ )
332
+ validate(field, REQUIRED_FIELDS_LIST)
333
+ end
334
+ validate(field, PATTERN_FIELDS_LIST) if field.has_attribute?('pattern')
335
+ if field.has_attribute?('minlength') ||
336
+ field.has_attribute?('maxlength')
337
+ validate(field, LIMITED_FIELDS_LIST)
338
+ end
339
+ if field.has_attribute?('aria-valuemin') ||
340
+ field.has_attribute?('aria-valuemax')
341
+ validate(field, RANGE_FIELDS_LIST)
342
+ end
343
+
344
+ return unless field.has_attribute?('type')
345
+
346
+ type_field = field.get_attribute('type').downcase
347
+ if type_field == 'week'
348
+ validate(field, WEEK_FIELDS_LIST)
349
+ elsif type_field == 'month'
350
+ validate(field, MONTH_FIELDS_LIST)
351
+ elsif %w[datetime-local datetime].include?(type_field)
352
+ validate(field, DATETIME_FIELDS_LIST)
353
+ elsif type_field == 'time'
354
+ validate(field, TIME_FIELDS_LIST)
355
+ elsif type_field == 'date'
356
+ validate(field, DATE_FIELDS_LIST)
357
+ elsif %w[number range].include?(type_field)
358
+ validate(field, RANGE_FIELDS_LIST)
359
+ elsif type_field == 'email'
360
+ validate(field, EMAIL_FIELDS_LIST)
361
+ elsif type_field == 'url'
362
+ validate(field, AccessibleFormImplementation.URL_FIELDS_LIST)
363
+ end
364
+ end
365
+
366
+ ##
367
+ # @see Hatemile::AccessibleForm#mark_all_invalid_fields
368
+ def mark_all_invalid_fields
369
+ fields = @parser.find(
370
+ '[required],input[pattern],input[minlength],input[maxlength],' \
371
+ 'textarea[minlength],textarea[maxlength],input[type=week],' \
372
+ 'input[type=month],input[type=datetime-local],' \
373
+ 'input[type=datetime],input[type=time],input[type=date],' \
374
+ 'input[type=number],input[type=range],input[type=email],' \
375
+ 'input[type=url],[aria-required=true],input[aria-valuemin],' \
376
+ 'input[aria-valuemax]'
377
+ ).list_results
378
+ fields.each do |field|
379
+ if Hatemile::Util::CommonFunctions.is_valid_element?(field)
380
+ mark_invalid_field(field)
381
+ end
382
+ end
383
+ end
384
+ end
385
+ end
386
+ end