hatemile 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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