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,1362 @@
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 'rexml/document'
14
+ require File.join(File.dirname(File.dirname(__FILE__)), 'accessible_display')
15
+ require File.join(File.dirname(File.dirname(__FILE__)), 'helper')
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', 'configure')
22
+ require File.join(File.dirname(File.dirname(__FILE__)), 'util', 'id_generator')
23
+ require File.join(
24
+ File.dirname(File.dirname(__FILE__)),
25
+ 'util',
26
+ 'html',
27
+ 'html_dom_parser'
28
+ )
29
+
30
+ ##
31
+ # The Hatemile module contains the interfaces with the acessibility solutions.
32
+ module Hatemile
33
+ ##
34
+ # The Hatemile::Implementation module contains the official implementation of
35
+ # interfaces solutions.
36
+ module Implementation
37
+ ##
38
+ # The AccessibleDisplayImplementation class is official implementation of
39
+ # Hatemile::AccessibleDisplay for screen readers.
40
+ class AccessibleDisplayImplementation < AccessibleDisplay
41
+ public_class_method :new
42
+
43
+ ##
44
+ # The id of list element that contains the description of shortcuts,
45
+ # before the whole content of page.
46
+ ID_CONTAINER_SHORTCUTS_BEFORE = 'container-shortcuts-before'.freeze
47
+
48
+ ##
49
+ # The id of list element that contains the description of shortcuts, after
50
+ # the whole content of page.
51
+ ID_CONTAINER_SHORTCUTS_AFTER = 'container-shortcuts-after'.freeze
52
+
53
+ ##
54
+ # The HTML class of text of description of container of shortcuts
55
+ # descriptions.
56
+ CLASS_TEXT_SHORTCUTS = 'text-shortcuts'.freeze
57
+
58
+ ##
59
+ # The HTML class of content to force the screen reader show the current
60
+ # state of element, before it.
61
+ CLASS_FORCE_READ_BEFORE = 'force-read-before'.freeze
62
+
63
+ ##
64
+ # The HTML class of content to force the screen reader show the current
65
+ # state of element, after it.
66
+ CLASS_FORCE_READ_AFTER = 'force-read-after'.freeze
67
+
68
+ ##
69
+ # The name of attribute that links the content of autocomplete state of
70
+ # field.
71
+ DATA_ARIA_AUTOCOMPLETE_OF = 'data-ariaautocompleteof'.freeze
72
+
73
+ ##
74
+ # The name of attribute that links the content of busy state of element.
75
+ DATA_ARIA_BUSY_OF = 'data-ariabusyof'.freeze
76
+
77
+ ##
78
+ # The name of attribute that links the content of checked state field.
79
+ DATA_ARIA_CHECKED_OF = 'data-ariacheckedof'.freeze
80
+
81
+ ##
82
+ # The name of attribute that links the content of drop effect state of
83
+ # element.
84
+ DATA_ARIA_DROPEFFECT_OF = 'data-ariadropeffectof'.freeze
85
+
86
+ ##
87
+ # The name of attribute that links the content of expanded state of
88
+ # element.
89
+ DATA_ARIA_EXPANDED_OF = 'data-ariaexpandedof'.freeze
90
+
91
+ ##
92
+ # The name of attribute that links the content of grabbed state of
93
+ # element.
94
+ DATA_ARIA_GRABBED_OF = 'data-ariagrabbedof'.freeze
95
+
96
+ ##
97
+ # The name of attribute that links the content that show if the field has
98
+ # popup.
99
+ DATA_ARIA_HASPOPUP_OF = 'data-ariahaspopupof'.freeze
100
+
101
+ ##
102
+ # The name of attribute that links the content of level state of element.
103
+ DATA_ARIA_LEVEL_OF = 'data-arialevelof'.freeze
104
+
105
+ ##
106
+ # The name of attribute that links the content of orientation state of
107
+ # element.
108
+ DATA_ARIA_ORIENTATION_OF = 'data-ariaorientationof'.freeze
109
+
110
+ ##
111
+ # The name of attribute that links the content of pressed state of field.
112
+ DATA_ARIA_PRESSED_OF = 'data-ariapressedof'.freeze
113
+
114
+ ##
115
+ # The name of attribute that links the content of minimum range state of
116
+ # field.
117
+ DATA_ARIA_RANGE_MIN_OF = 'data-attributevalueminof'.freeze
118
+
119
+ ##
120
+ # The name of attribute that links the content of maximum range state of
121
+ # field.
122
+ DATA_ARIA_RANGE_MAX_OF = 'data-attributevaluemaxof'.freeze
123
+
124
+ ##
125
+ # The name of attribute that links the content of required state of field.
126
+ DATA_ARIA_REQUIRED_OF = 'data-attributerequiredof'.freeze
127
+
128
+ ##
129
+ # The name of attribute that links the content of selected state of field.
130
+ DATA_ARIA_SELECTED_OF = 'data-ariaselectedof'.freeze
131
+
132
+ ##
133
+ # The name of attribute that links the content of sort state of element.
134
+ DATA_ARIA_SORT_OF = 'data-ariasortof'.freeze
135
+
136
+ ##
137
+ # The name of attribute that links the description of shortcut of element.
138
+ DATA_ATTRIBUTE_ACCESSKEY_OF = 'data-attributeaccesskeyof'.freeze
139
+
140
+ ##
141
+ # The name of attribute that links the content of download link.
142
+ DATA_ATTRIBUTE_DOWNLOAD_OF = 'data-attributedownloadof'.freeze
143
+
144
+ ##
145
+ # The name of attribute that links the content of header cell with the
146
+ # data cell.
147
+ DATA_ATTRIBUTE_HEADERS_OF = 'data-headersof'.freeze
148
+
149
+ ##
150
+ # The name of attribute that links the description of language with the
151
+ # element.
152
+ DATA_ATTRIBUTE_LANGUAGE_OF = 'data-languageof'.freeze
153
+
154
+ ##
155
+ # The name of attribute that links the content of link that open a new
156
+ # instance.
157
+ DATA_ATTRIBUTE_TARGET_OF = 'data-attributetargetof'.freeze
158
+
159
+ ##
160
+ # The name of attribute that links the content of title of element.
161
+ DATA_ATTRIBUTE_TITLE_OF = 'data-attributetitleof'.freeze
162
+
163
+ ##
164
+ # The name of attribute that links the content of role of element with the
165
+ # element.
166
+ DATA_ROLE_OF = 'data-roleof'.freeze
167
+
168
+ protected
169
+
170
+ ##
171
+ # Returns the description of element.
172
+ #
173
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The element.
174
+ # @return [String] The description of element.
175
+ def get_description(element)
176
+ description = nil
177
+ tag_name = element.get_tag_name
178
+ if element.has_attribute?('title')
179
+ description = element.get_attribute('title')
180
+ elsif element.has_attribute?('aria-label')
181
+ description = element.get_attribute('aria-label')
182
+ elsif element.has_attribute?('alt')
183
+ description = element.get_attribute('alt')
184
+ elsif element.has_attribute?('label')
185
+ description = element.get_attribute('label')
186
+ elsif element.has_attribute?('aria-labelledby') ||
187
+ element.has_attribute?('aria-describedby')
188
+ description_ids = if element.has_attribute?('aria-labelledby')
189
+ element.get_attribute(
190
+ 'aria-labelledby'
191
+ ).split(/[ \n\t\r]+/)
192
+ else
193
+ element.get_attribute(
194
+ 'aria-describedby'
195
+ ).split(/[ \n\t\r]+/)
196
+ end
197
+ description_ids.each do |description_id|
198
+ element_description = @parser.find(
199
+ "##{description_id}"
200
+ ).first_result
201
+ unless element_description.nil?
202
+ description = element_description.get_text_content
203
+ break
204
+ end
205
+ end
206
+ elsif %w[INPUT TEXTAREA OPTION].include?(tag_name)
207
+ if element.has_attribute?('type') &&
208
+ %w[button submit reset].include?(
209
+ element.get_attribute('type').downcase
210
+ ) &&
211
+ element.has_attribute?('value')
212
+ description = element.get_attribute('value')
213
+ else
214
+ label = nil
215
+ if element.has_attribute?('id')
216
+ field_id = element.get_attribute('id')
217
+ label = @parser.find("label[for=\"#{field_id}\"]").first_result
218
+ end
219
+ if label.nil?
220
+ label = @parser.find(element).find_ancestors('label').first_result
221
+ end
222
+ description = label.get_text_content unless label.nil?
223
+ end
224
+ end
225
+ description = element.get_text_content if description.nil?
226
+ description.gsub(/[ \n\t\r]+/, ' ').strip
227
+ end
228
+
229
+ ##
230
+ # Generate the list of shortcuts of page.
231
+ #
232
+ # @return [void]
233
+ def generate_list_shortcuts
234
+ local = @parser.find('body').first_result
235
+
236
+ return if local.nil?
237
+
238
+ container_before = @parser.find(
239
+ "##{ID_CONTAINER_SHORTCUTS_BEFORE}"
240
+ ).first_result
241
+ if container_before.nil? && !@attribute_accesskey_before.empty?
242
+ container_before = @parser.create_element('div')
243
+ container_before.set_attribute('id', ID_CONTAINER_SHORTCUTS_BEFORE)
244
+
245
+ text_container_before = @parser.create_element('span')
246
+ text_container_before.set_attribute('class', CLASS_TEXT_SHORTCUTS)
247
+ text_container_before.append_text(@attribute_accesskey_before)
248
+
249
+ container_before.append_element(text_container_before)
250
+ local.prepend_element(container_before)
251
+ end
252
+ unless container_before.nil?
253
+ @list_shortcuts_before = @parser.find(
254
+ container_before
255
+ ).find_children('ul').first_result
256
+ if @list_shortcuts_before.nil?
257
+ @list_shortcuts_before = @parser.create_element('ul')
258
+ container_before.append_element(@list_shortcuts_before)
259
+ end
260
+ end
261
+ container_after = @parser.find(
262
+ "##{ID_CONTAINER_SHORTCUTS_AFTER}"
263
+ ).first_result
264
+ if container_after.nil? && !@attribute_accesskey_after.empty?
265
+ container_after = @parser.create_element('div')
266
+ container_after.set_attribute('id', ID_CONTAINER_SHORTCUTS_AFTER)
267
+
268
+ text_container_after = @parser.create_element('span')
269
+ text_container_after.set_attribute('class', CLASS_TEXT_SHORTCUTS)
270
+ text_container_after.append_text(@attribute_accesskey_after)
271
+
272
+ container_after.append_element(text_container_after)
273
+ local.append_element(container_after)
274
+ end
275
+ unless container_after.nil?
276
+ @list_shortcuts_after = @parser.find(
277
+ container_after
278
+ ).find_children('ul').first_result
279
+ if @list_shortcuts_after.nil?
280
+ @list_shortcuts_after = @parser.create_element('ul')
281
+ container_after.append_element(@list_shortcuts_after)
282
+ end
283
+ end
284
+ @list_shortcuts_added = true
285
+ end
286
+
287
+ ##
288
+ # Returns the shortcut prefix of browser.
289
+ #
290
+ # @param user_agent [String] The user agent of browser.
291
+ # @param standart_prefix [String] The default prefix.
292
+ # @return [String] The shortcut prefix of browser.
293
+ def get_shortcut_prefix(user_agent, standart_prefix)
294
+ return standart_prefix if user_agent.nil?
295
+
296
+ user_agent = user_agent.downcase
297
+ opera = user_agent.include?('opera')
298
+ mac = user_agent.include?('mac')
299
+ konqueror = user_agent.include?('konqueror')
300
+ spoofer = user_agent.include?('spoofer')
301
+ safari = user_agent.include?('applewebkit')
302
+ windows = user_agent.include?('windows')
303
+ chrome = user_agent.include?('chrome')
304
+ firefox = user_agent.include?('firefox') ||
305
+ user_agent.include?('minefield')
306
+ ie = user_agent.include?('msie') || user_agent.include?('trident')
307
+
308
+ return 'SHIFT + ESC' if opera
309
+ return 'CTRL + OPTION' if chrome && mac && !spoofer
310
+ return 'CTRL + ALT' if safari && !windows && !spoofer
311
+ return 'CTRL' if !windows && (safari || mac || konqueror)
312
+ return 'ALT + SHIFT' if firefox
313
+ return 'ALT' if chrome || ie
314
+
315
+ standart_prefix
316
+ end
317
+
318
+ ##
319
+ # Returns the description of role.
320
+ #
321
+ # @param role [String] The role.
322
+ # @return [String] The description of role.
323
+ def get_role_description(role)
324
+ parameter = "role-#{role.downcase}"
325
+ if @configure.has_parameter?(parameter)
326
+ return @configure.get_parameter(parameter)
327
+ end
328
+ nil
329
+ end
330
+
331
+ ##
332
+ # Returns the description of language.
333
+ #
334
+ # @param language_code [String] The BCP 47 code language.
335
+ # @return [String] The description of language.
336
+ def get_language_description(language_code)
337
+ language = language_code.downcase
338
+ p = "language-#{language}"
339
+ return @configure.get_parameter(p) if @configure.has_parameter?(p)
340
+ if language.include?('-')
341
+ codes = language.split(/\-/)
342
+ p = "language-#{codes.first}"
343
+ return @configure.get_parameter(p) if @configure.has_parameter?(p)
344
+ end
345
+ nil
346
+ end
347
+
348
+ ##
349
+ # Insert a element before or after other element.
350
+ #
351
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The reference
352
+ # element.
353
+ # @param new_element [Hatemile::Util::Html::HTMLDOMElement] The element
354
+ # that be inserted.
355
+ # @param before [Boolean] To insert the element before the other element.
356
+ # @return [void]
357
+ def insert(element, new_element, before)
358
+ return unless Hatemile::Util::CommonFunctions.is_valid_element?(element)
359
+
360
+ tag_name = element.get_tag_name
361
+ append_tags = %w[BODY A FIGCAPTION LI DT DD LABEL OPTION TD TH]
362
+ controls = %w[INPUT SELECT TEXTAREA]
363
+ if tag_name == 'HTML'
364
+ body = @parser.find('body').first_result
365
+ insert(body, new_element, before) unless body.nil?
366
+ elsif append_tags.include?(tag_name)
367
+ element.prepend_element(new_element) if before
368
+ element.append_element(new_element) unless before
369
+ elsif controls.include?(tag_name)
370
+ labels = []
371
+ if element.has_attribute?('id')
372
+ labels = @parser.find(
373
+ "label[for=\"#{element.get_attribute('id')}\"]"
374
+ ).list_results
375
+ end
376
+ if labels.empty?
377
+ labels = @parser.find(element).find_ancestors('label').list_results
378
+ end
379
+ labels.each do |label|
380
+ insert(label, new_element, before)
381
+ end
382
+ elsif before
383
+ element.insert_before(new_element)
384
+ else
385
+ element.insert_after(new_element)
386
+ end
387
+ end
388
+
389
+ ##
390
+ # Force the screen reader display an information of element.
391
+ #
392
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The reference
393
+ # element.
394
+ # @param text_before [String] The text content to show before the element.
395
+ # @param text_after [String] The text content to show after the element.
396
+ # @param data_of [String] The name of attribute that links the content
397
+ # with element.
398
+ # @return [void]
399
+ def force_read_simple(element, text_before, text_after, data_of)
400
+ @id_generator.generate_id(element)
401
+ identifier = element.get_attribute('id')
402
+ selector = "[#{data_of}=\"#{identifier}\"]"
403
+
404
+ reference_before = @parser.find(
405
+ ".#{CLASS_FORCE_READ_BEFORE}#{selector}"
406
+ ).first_result
407
+ reference_after = @parser.find(
408
+ ".#{CLASS_FORCE_READ_AFTER}#{selector}"
409
+ ).first_result
410
+ references = @parser.find(selector).list_results
411
+ if references.include?(reference_before)
412
+ references.delete(reference_before)
413
+ end
414
+ if references.include?(reference_after)
415
+ references.delete(reference_after)
416
+ end
417
+
418
+ return unless references.empty?
419
+
420
+ unless text_before.empty?
421
+ reference_before.remove_node unless reference_before.nil?
422
+
423
+ span = @parser.create_element('span')
424
+ span.set_attribute('class', CLASS_FORCE_READ_BEFORE)
425
+ span.set_attribute(data_of, identifier)
426
+ span.append_text(text_before)
427
+ insert(element, span, true)
428
+ end
429
+
430
+ return if text_after.empty?
431
+
432
+ reference_after.remove_node unless reference_after.nil?
433
+
434
+ span = @parser.create_element('span')
435
+ span.set_attribute('class', CLASS_FORCE_READ_AFTER)
436
+ span.set_attribute(data_of, identifier)
437
+ span.append_text(text_after)
438
+ insert(element, span, false)
439
+ end
440
+
441
+ ##
442
+ # Force the screen reader display an information of element with prefixes
443
+ # or suffixes.
444
+ #
445
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The reference
446
+ # element.
447
+ # @param value [String] The value to be show.
448
+ # @param text_prefix_before [String] The prefix of value to show before
449
+ # the element.
450
+ # @param text_suffix_before [String] The suffix of value to show before
451
+ # the element.
452
+ # @param text_prefix_after [String] The prefix of value to show after the
453
+ # element.
454
+ # @param text_suffix_after [String] The suffix of value to show after the
455
+ # element.
456
+ # @param data_of [String] The name of attribute that links the content
457
+ # with element.
458
+ # @return [void]
459
+ def force_read(
460
+ element,
461
+ value,
462
+ text_prefix_before,
463
+ text_suffix_before,
464
+ text_prefix_after,
465
+ text_suffix_after,
466
+ data_of
467
+ )
468
+ text_before = if !text_prefix_before.empty? ||
469
+ !text_suffix_before.empty?
470
+ text_prefix_before + value + text_suffix_before
471
+ else
472
+ ''
473
+ end
474
+ text_after = if !text_prefix_after.empty? || !text_suffix_after.empty?
475
+ text_prefix_after + value + text_suffix_after
476
+ else
477
+ ''
478
+ end
479
+ force_read_simple(element, text_before, text_after, data_of)
480
+ end
481
+
482
+ public
483
+
484
+ ##
485
+ # Initializes a new object that manipulate the display for screen readers
486
+ # of parser.
487
+ #
488
+ # @param parser [Hatemile::Util::Html::HTMLDOMParser] The HTML parser.
489
+ # @param configure [Hatemile::Util::Configure] The configuration of
490
+ # HaTeMiLe.
491
+ # @param user_agent [String] The user agent of the user.
492
+ def initialize(parser, configure, user_agent = nil)
493
+ Hatemile::Helper.require_not_nil(parser, configure)
494
+ Hatemile::Helper.require_valid_type(
495
+ parser,
496
+ Hatemile::Util::Html::HTMLDOMParser
497
+ )
498
+ Hatemile::Helper.require_valid_type(
499
+ configure,
500
+ Hatemile::Util::Configure
501
+ )
502
+ Hatemile::Helper.require_valid_type(user_agent, String)
503
+
504
+ @parser = parser
505
+ @configure = configure
506
+ @id_generator = Hatemile::Util::IDGenerator.new('display')
507
+ @shortcut_prefix = get_shortcut_prefix(
508
+ user_agent,
509
+ configure.get_parameter('attribute-accesskey-default')
510
+ )
511
+ @aria_autocomplete_both_before = configure.get_parameter(
512
+ 'aria-autocomplete-both-before'
513
+ )
514
+ @aria_autocomplete_both_after = configure.get_parameter(
515
+ 'aria-autocomplete-both-after'
516
+ )
517
+ @aria_autocomplete_inline_before = configure.get_parameter(
518
+ 'aria-autocomplete-inline-before'
519
+ )
520
+ @aria_autocomplete_inline_after = configure.get_parameter(
521
+ 'aria-autocomplete-inline-after'
522
+ )
523
+ @aria_autocomplete_list_before = configure.get_parameter(
524
+ 'aria-autocomplete-list-before'
525
+ )
526
+ @aria_autocomplete_list_after = configure.get_parameter(
527
+ 'aria-autocomplete-list-after'
528
+ )
529
+ @aria_busy_true_before = configure.get_parameter(
530
+ 'aria-busy-true-before'
531
+ )
532
+ @aria_busy_true_after = configure.get_parameter('aria-busy-true-after')
533
+ @aria_checked_false_before = configure.get_parameter(
534
+ 'aria-checked-false-before'
535
+ )
536
+ @aria_checked_false_after = configure.get_parameter(
537
+ 'aria-checked-false-after'
538
+ )
539
+ @aria_checked_mixed_before = configure.get_parameter(
540
+ 'aria-checked-mixed-before'
541
+ )
542
+ @aria_checked_mixed_after = configure.get_parameter(
543
+ 'aria-checked-mixed-after'
544
+ )
545
+ @aria_checked_true_before = configure.get_parameter(
546
+ 'aria-checked-true-before'
547
+ )
548
+ @aria_checked_true_after = configure.get_parameter(
549
+ 'aria-checked-true-after'
550
+ )
551
+ @aria_dropeffect_copy_before = configure.get_parameter(
552
+ 'aria-dropeffect-copy-before'
553
+ )
554
+ @aria_dropeffect_copy_after = configure.get_parameter(
555
+ 'aria-dropeffect-copy-after'
556
+ )
557
+ @aria_dropeffect_execute_before = configure.get_parameter(
558
+ 'aria-dropeffect-execute-before'
559
+ )
560
+ @aria_dropeffect_execute_after = configure.get_parameter(
561
+ 'aria-dropeffect-execute-after'
562
+ )
563
+ @aria_dropeffect_link_before = configure.get_parameter(
564
+ 'aria-dropeffect-link-before'
565
+ )
566
+ @aria_dropeffect_link_after = configure.get_parameter(
567
+ 'aria-dropeffect-link-after'
568
+ )
569
+ @aria_dropeffect_move_before = configure.get_parameter(
570
+ 'aria-dropeffect-move-before'
571
+ )
572
+ @aria_dropeffect_move_after = configure.get_parameter(
573
+ 'aria-dropeffect-move-after'
574
+ )
575
+ @aria_dropeffect_popup_before = configure.get_parameter(
576
+ 'aria-dropeffect-popup-before'
577
+ )
578
+ @aria_dropeffect_popup_after = configure.get_parameter(
579
+ 'aria-dropeffect-popup-after'
580
+ )
581
+ @aria_expanded_false_before = configure.get_parameter(
582
+ 'aria-expanded-false-before'
583
+ )
584
+ @aria_expanded_false_after = configure.get_parameter(
585
+ 'aria-expanded-false-after'
586
+ )
587
+ @aria_expanded_true_before = configure.get_parameter(
588
+ 'aria-expanded-true-before'
589
+ )
590
+ @aria_expanded_true_after = configure.get_parameter(
591
+ 'aria-expanded-true-after'
592
+ )
593
+ @aria_grabbed_false_before = configure.get_parameter(
594
+ 'aria-grabbed-false-before'
595
+ )
596
+ @aria_grabbed_false_after = configure.get_parameter(
597
+ 'aria-grabbed-false-after'
598
+ )
599
+ @aria_grabbed_true_before = configure.get_parameter(
600
+ 'aria-grabbed-true-before'
601
+ )
602
+ @aria_grabbed_true_after = configure.get_parameter(
603
+ 'aria-grabbed-true-after'
604
+ )
605
+ @aria_haspopup_true_before = configure.get_parameter(
606
+ 'aria-haspopup-true-before'
607
+ )
608
+ @aria_haspopup_true_after = configure.get_parameter(
609
+ 'aria-haspopup-true-after'
610
+ )
611
+ @aria_level_prefix_before = configure.get_parameter(
612
+ 'aria-level-prefix-before'
613
+ )
614
+ @aria_level_suffix_before = configure.get_parameter(
615
+ 'aria-level-suffix-before'
616
+ )
617
+ @aria_level_prefix_after = configure.get_parameter(
618
+ 'aria-level-prefix-after'
619
+ )
620
+ @aria_level_suffix_after = configure.get_parameter(
621
+ 'aria-level-suffix-after'
622
+ )
623
+ @aria_value_maximum_prefix_before = configure.get_parameter(
624
+ 'aria-value-maximum-prefix-before'
625
+ )
626
+ @aria_value_maximum_suffix_before = configure.get_parameter(
627
+ 'aria-value-maximum-suffix-before'
628
+ )
629
+ @aria_value_maximum_prefix_after = configure.get_parameter(
630
+ 'aria-value-maximum-prefix-after'
631
+ )
632
+ @aria_value_maximum_suffix_after = configure.get_parameter(
633
+ 'aria-value-maximum-suffix-after'
634
+ )
635
+ @aria_value_minimum_prefix_before = configure.get_parameter(
636
+ 'aria-value-minimum-prefix-before'
637
+ )
638
+ @aria_value_minimum_suffix_before = configure.get_parameter(
639
+ 'aria-value-minimum-suffix-before'
640
+ )
641
+ @aria_value_minimum_prefix_after = configure.get_parameter(
642
+ 'aria-value-minimum-prefix-after'
643
+ )
644
+ @aria_value_minimum_suffix_after = configure.get_parameter(
645
+ 'aria-value-minimum-suffix-after'
646
+ )
647
+ @aria_orientation_horizontal_before = configure.get_parameter(
648
+ 'aria-orientation-horizontal-before'
649
+ )
650
+ @aria_orientation_horizontal_after = configure.get_parameter(
651
+ 'aria-orientation-horizontal-after'
652
+ )
653
+ @aria_orientation_vertical_before = configure.get_parameter(
654
+ 'aria-orientation-vertical-before'
655
+ )
656
+ @aria_orientation_vertical_after = configure.get_parameter(
657
+ 'aria-orientation-vertical-after'
658
+ )
659
+ @aria_pressed_false_before = configure.get_parameter(
660
+ 'aria-pressed-false-before'
661
+ )
662
+ @aria_pressed_false_after = configure.get_parameter(
663
+ 'aria-pressed-false-after'
664
+ )
665
+ @aria_pressed_mixed_before = configure.get_parameter(
666
+ 'aria-pressed-mixed-before'
667
+ )
668
+ @aria_pressed_mixed_after = configure.get_parameter(
669
+ 'aria-pressed-mixed-after'
670
+ )
671
+ @aria_pressed_true_before = configure.get_parameter(
672
+ 'aria-pressed-true-before'
673
+ )
674
+ @aria_pressed_true_after = configure.get_parameter(
675
+ 'aria-pressed-true-after'
676
+ )
677
+ @aria_required_true_before = configure.get_parameter(
678
+ 'aria-required-true-before'
679
+ )
680
+ @aria_required_true_after = configure.get_parameter(
681
+ 'aria-required-true-after'
682
+ )
683
+ @aria_selected_false_before = configure.get_parameter(
684
+ 'aria-selected-false-before'
685
+ )
686
+ @aria_selected_false_after = configure.get_parameter(
687
+ 'aria-selected-false-after'
688
+ )
689
+ @aria_selected_true_before = configure.get_parameter(
690
+ 'aria-selected-true-before'
691
+ )
692
+ @aria_selected_true_after = configure.get_parameter(
693
+ 'aria-selected-true-after'
694
+ )
695
+ @aria_sort_ascending_before = configure.get_parameter(
696
+ 'aria-sort-ascending-before'
697
+ )
698
+ @aria_sort_ascending_after = configure.get_parameter(
699
+ 'aria-sort-ascending-after'
700
+ )
701
+ @aria_sort_descending_before = configure.get_parameter(
702
+ 'aria-sort-descending-before'
703
+ )
704
+ @aria_sort_descending_after = configure.get_parameter(
705
+ 'aria-sort-descending-after'
706
+ )
707
+ @aria_sort_other_before = configure.get_parameter(
708
+ 'aria-sort-other-before'
709
+ )
710
+ @aria_sort_other_after = configure.get_parameter(
711
+ 'aria-sort-other-after'
712
+ )
713
+ @attribute_accesskey_before = configure.get_parameter(
714
+ 'attribute-accesskey-before'
715
+ )
716
+ @attribute_accesskey_after = configure.get_parameter(
717
+ 'attribute-accesskey-after'
718
+ )
719
+ @attribute_accesskey_prefix_before = configure.get_parameter(
720
+ 'attribute-accesskey-prefix-before'
721
+ )
722
+ @attribute_accesskey_suffix_before = configure.get_parameter(
723
+ 'attribute-accesskey-suffix-before'
724
+ )
725
+ @attribute_accesskey_prefix_after = configure.get_parameter(
726
+ 'attribute-accesskey-prefix-after'
727
+ )
728
+ @attribute_accesskey_suffix_after = configure.get_parameter(
729
+ 'attribute-accesskey-suffix-after'
730
+ )
731
+ @attribute_download_before = configure.get_parameter(
732
+ 'attribute-download-before'
733
+ )
734
+ @attribute_download_after = configure.get_parameter(
735
+ 'attribute-download-after'
736
+ )
737
+ @attribute_headers_prefix_before = configure.get_parameter(
738
+ 'attribute-headers-prefix-before'
739
+ )
740
+ @attribute_headers_suffix_before = configure.get_parameter(
741
+ 'attribute-headers-suffix-before'
742
+ )
743
+ @attribute_headers_prefix_after = configure.get_parameter(
744
+ 'attribute-headers-prefix-after'
745
+ )
746
+ @attribute_headers_suffix_after = configure.get_parameter(
747
+ 'attribute-headers-suffix-after'
748
+ )
749
+ @attribute_language_prefix_before = configure.get_parameter(
750
+ 'attribute-language-prefix-before'
751
+ )
752
+ @attribute_language_suffix_before = configure.get_parameter(
753
+ 'attribute-language-suffix-before'
754
+ )
755
+ @attribute_language_prefix_after = configure.get_parameter(
756
+ 'attribute-language-prefix-after'
757
+ )
758
+ @attribute_language_suffix_after = configure.get_parameter(
759
+ 'attribute-language-suffix-after'
760
+ )
761
+ @attribute_role_prefix_before = configure.get_parameter(
762
+ 'attribute-role-prefix-before'
763
+ )
764
+ @attribute_role_suffix_before = configure.get_parameter(
765
+ 'attribute-role-suffix-before'
766
+ )
767
+ @attribute_role_prefix_after = configure.get_parameter(
768
+ 'attribute-role-prefix-after'
769
+ )
770
+ @attribute_role_suffix_after = configure.get_parameter(
771
+ 'attribute-role-suffix-after'
772
+ )
773
+ @attribute_target_blank_before = configure.get_parameter(
774
+ 'attribute-target-blank-before'
775
+ )
776
+ @attribute_target_blank_after = configure.get_parameter(
777
+ 'attribute-target-blank-after'
778
+ )
779
+ @attribute_title_prefix_before = configure.get_parameter(
780
+ 'attribute-title-prefix-before'
781
+ )
782
+ @attribute_title_suffix_before = configure.get_parameter(
783
+ 'attribute-title-suffix-before'
784
+ )
785
+ @attribute_title_prefix_after = configure.get_parameter(
786
+ 'attribute-title-prefix-after'
787
+ )
788
+ @attribute_title_suffix_after = configure.get_parameter(
789
+ 'attribute-title-suffix-after'
790
+ )
791
+ @list_shortcuts_added = false
792
+ @list_shortcuts_before = nil
793
+ @list_shortcuts_after = nil
794
+ end
795
+
796
+ ##
797
+ # @see Hatemile::AccessibleDisplay#display_shortcut
798
+ def display_shortcut(element)
799
+ return unless element.has_attribute?('accesskey')
800
+
801
+ description = get_description(element)
802
+ unless element.has_attribute?('title')
803
+ element.set_attribute('title', description)
804
+
805
+ @id_generator.generate_id(element)
806
+ element.set_attribute(
807
+ DATA_ATTRIBUTE_TITLE_OF,
808
+ element.get_attribute('id')
809
+ )
810
+ end
811
+
812
+ generate_list_shortcuts unless @list_shortcuts_added
813
+
814
+ keys = element.get_attribute('accesskey').upcase.split(/[ \n\t\r]+/)
815
+ keys.each do |key|
816
+ shortcut = "#{@shortcut_prefix} + #{key}"
817
+ selector = "[#{DATA_ATTRIBUTE_ACCESSKEY_OF}=\"#{key}\"]"
818
+
819
+ force_read(
820
+ element,
821
+ shortcut,
822
+ @attribute_accesskey_prefix_before,
823
+ @attribute_accesskey_suffix_before,
824
+ @attribute_accesskey_prefix_after,
825
+ @attribute_accesskey_suffix_after,
826
+ DATA_ATTRIBUTE_ACCESSKEY_OF
827
+ )
828
+
829
+ item = @parser.create_element('li')
830
+ item.set_attribute(DATA_ATTRIBUTE_ACCESSKEY_OF, key)
831
+ item.append_text("#{shortcut}: #{description}")
832
+
833
+ if !@list_shortcuts_before.nil? &&
834
+ @parser.find(@list_shortcuts_before).find_children(
835
+ selector
836
+ ).first_result.nil?
837
+ @list_shortcuts_before.append_element(item.clone_element)
838
+ end
839
+ unless !@list_shortcuts_after.nil? &&
840
+ @parser.find(@list_shortcuts_after).find_children(
841
+ selector
842
+ ).first_result.nil?
843
+ next
844
+ end
845
+ @list_shortcuts_after.append_element(item.clone_element)
846
+ end
847
+ end
848
+
849
+ ##
850
+ # @see Hatemile::AccessibleDisplay#display_all_shortcuts
851
+ def display_all_shortcuts
852
+ elements = @parser.find('[accesskey]').list_results
853
+ elements.each do |element|
854
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
855
+ display_shortcut(element)
856
+ end
857
+ end
858
+ end
859
+
860
+ ##
861
+ # @see Hatemile::AccessibleDisplay#display_role
862
+ def display_role(element)
863
+ return unless element.has_attribute?('role')
864
+
865
+ role_description = get_role_description(element.get_attribute('role'))
866
+
867
+ return if role_description.nil?
868
+
869
+ force_read(
870
+ element,
871
+ role_description,
872
+ @attribute_role_prefix_before,
873
+ @attribute_role_suffix_before,
874
+ @attribute_role_prefix_after,
875
+ @attribute_role_suffix_after,
876
+ DATA_ROLE_OF
877
+ )
878
+ end
879
+
880
+ ##
881
+ # @see Hatemile::AccessibleDisplay#display_all_roles
882
+ def display_all_roles
883
+ elements = @parser.find('[role]').list_results
884
+ elements.each do |element|
885
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
886
+ display_role(element)
887
+ end
888
+ end
889
+ end
890
+
891
+ ##
892
+ # @see Hatemile::AccessibleDisplay#display_cell_header
893
+ def display_cell_header(table_cell)
894
+ return unless table_cell.has_attribute?('headers')
895
+
896
+ text_header = ''
897
+ ids_headers = table_cell.get_attribute('headers').split(/[ \n\t\r]+/)
898
+ ids_headers.each do |id_header|
899
+ header = @parser.find("##{id_header}").first_result
900
+
901
+ next if header.nil?
902
+
903
+ text_header = if text_header.empty?
904
+ header.get_text_content.strip
905
+ else
906
+ "#{text_header} #{header.get_text_content.strip}"
907
+ end
908
+ end
909
+
910
+ return if text_header.strip.empty?
911
+
912
+ force_read(
913
+ table_cell,
914
+ text_header.gsub(/[ \n\t\r]+/, ' ').strip,
915
+ @attribute_headers_prefix_before,
916
+ @attribute_headers_suffix_before,
917
+ @attribute_headers_prefix_after,
918
+ @attribute_headers_suffix_after,
919
+ DATA_ATTRIBUTE_HEADERS_OF
920
+ )
921
+ end
922
+
923
+ ##
924
+ # @see Hatemile::AccessibleDisplay#display_all_cell_headers
925
+ def display_all_cell_headers
926
+ elements = @parser.find('td[headers],th[headers]').list_results
927
+ elements.each do |element|
928
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
929
+ display_cell_header(element)
930
+ end
931
+ end
932
+ end
933
+
934
+ ##
935
+ # @see Hatemile::AccessibleDisplay#display_waiaria_states
936
+ def display_waiaria_states(element)
937
+ if element.has_attribute?('aria-busy') &&
938
+ element.get_attribute('aria-busy') == 'true'
939
+ force_read_simple(
940
+ element,
941
+ @aria_busy_true_before,
942
+ @aria_busy_true_after,
943
+ DATA_ARIA_BUSY_OF
944
+ )
945
+ end
946
+ if element.has_attribute?('aria-checked')
947
+ attribute_value = element.get_attribute('aria-checked')
948
+ if attribute_value == 'true'
949
+ force_read_simple(
950
+ element,
951
+ @aria_checked_true_before,
952
+ @aria_checked_true_after,
953
+ DATA_ARIA_CHECKED_OF
954
+ )
955
+ elsif attribute_value == 'false'
956
+ force_read_simple(
957
+ element,
958
+ @aria_checked_false_before,
959
+ @aria_checked_false_after,
960
+ DATA_ARIA_CHECKED_OF
961
+ )
962
+ elsif attribute_value == 'mixed'
963
+ force_read_simple(
964
+ element,
965
+ @aria_checked_mixed_before,
966
+ @aria_checked_mixed_after,
967
+ DATA_ARIA_CHECKED_OF
968
+ )
969
+ end
970
+ end
971
+ if element.has_attribute?('aria-expanded')
972
+ attribute_value = element.get_attribute('aria-expanded')
973
+ if attribute_value == 'true'
974
+ force_read_simple(
975
+ element,
976
+ @aria_expanded_true_before,
977
+ @aria_expanded_true_after,
978
+ DATA_ARIA_EXPANDED_OF
979
+ )
980
+ elsif attribute_value == 'false'
981
+ force_read_simple(
982
+ element,
983
+ @aria_expanded_false_before,
984
+ @aria_expanded_false_after,
985
+ DATA_ARIA_EXPANDED_OF
986
+ )
987
+ end
988
+ end
989
+ if element.has_attribute?('aria-haspopup') &&
990
+ element.get_attribute('aria-haspopup') == 'true'
991
+ force_read_simple(
992
+ element,
993
+ @aria_haspopup_true_before,
994
+ @aria_haspopup_true_after,
995
+ DATA_ARIA_HASPOPUP_OF
996
+ )
997
+ end
998
+ if element.has_attribute?('aria-level')
999
+ force_read(
1000
+ element,
1001
+ element.get_attribute('aria-level'),
1002
+ @aria_level_prefix_before,
1003
+ @aria_level_suffix_before,
1004
+ @aria_level_prefix_after,
1005
+ @aria_level_suffix_after,
1006
+ DATA_ARIA_LEVEL_OF
1007
+ )
1008
+ end
1009
+ if element.has_attribute?('aria-orientation')
1010
+ attribute_value = element.get_attribute('aria-orientation')
1011
+ if attribute_value == 'vertical'
1012
+ force_read_simple(
1013
+ element,
1014
+ @aria_orientation_vertical_before,
1015
+ @aria_orientation_vertical_after,
1016
+ DATA_ARIA_ORIENTATION_OF
1017
+ )
1018
+ elsif attribute_value == 'horizontal'
1019
+ force_read_simple(
1020
+ element,
1021
+ @aria_orientation_horizontal_before,
1022
+ @aria_orientation_horizontal_after,
1023
+ DATA_ARIA_ORIENTATION_OF
1024
+ )
1025
+ end
1026
+ end
1027
+ if element.has_attribute?('aria-pressed')
1028
+ attribute_value = element.get_attribute('aria-pressed')
1029
+ if attribute_value == 'true'
1030
+ force_read_simple(
1031
+ element,
1032
+ @aria_pressed_true_before,
1033
+ @aria_pressed_true_after,
1034
+ DATA_ARIA_PRESSED_OF
1035
+ )
1036
+ elsif attribute_value == 'false'
1037
+ force_read_simple(
1038
+ element,
1039
+ @aria_pressed_false_before,
1040
+ @aria_pressed_false_after,
1041
+ DATA_ARIA_PRESSED_OF
1042
+ )
1043
+ elsif attribute_value == 'mixed'
1044
+ force_read_simple(
1045
+ element,
1046
+ @aria_pressed_mixed_before,
1047
+ @aria_pressed_mixed_after,
1048
+ DATA_ARIA_PRESSED_OF
1049
+ )
1050
+ end
1051
+ end
1052
+ if element.has_attribute?('aria-selected')
1053
+ attribute_value = element.get_attribute('aria-selected')
1054
+ if attribute_value == 'true'
1055
+ force_read_simple(
1056
+ element,
1057
+ @aria_selected_true_before,
1058
+ @aria_selected_true_after,
1059
+ DATA_ARIA_SELECTED_OF
1060
+ )
1061
+ elsif attribute_value == 'false'
1062
+ force_read_simple(
1063
+ element,
1064
+ @aria_selected_false_before,
1065
+ @aria_selected_false_after,
1066
+ DATA_ARIA_SELECTED_OF
1067
+ )
1068
+ end
1069
+ end
1070
+ if element.has_attribute?('aria-sort')
1071
+ attribute_value = element.get_attribute('aria-sort')
1072
+ if attribute_value == 'ascending'
1073
+ force_read_simple(
1074
+ element,
1075
+ @aria_sort_ascending_before,
1076
+ @aria_sort_ascending_after,
1077
+ DATA_ARIA_SORT_OF
1078
+ )
1079
+ elsif attribute_value == 'descending'
1080
+ force_read_simple(
1081
+ element,
1082
+ @aria_sort_descending_before,
1083
+ @aria_sort_descending_after,
1084
+ DATA_ARIA_SORT_OF
1085
+ )
1086
+ elsif attribute_value == 'other'
1087
+ force_read_simple(
1088
+ element,
1089
+ @aria_sort_other_before,
1090
+ @aria_sort_other_after,
1091
+ DATA_ARIA_SORT_OF
1092
+ )
1093
+ end
1094
+ end
1095
+ if element.has_attribute?('aria-required') &&
1096
+ element.get_attribute('aria-required') == 'true'
1097
+ force_read_simple(
1098
+ element,
1099
+ @aria_required_true_before,
1100
+ @aria_required_true_after,
1101
+ DATA_ARIA_REQUIRED_OF
1102
+ )
1103
+ end
1104
+ if element.has_attribute?('aria-valuemin')
1105
+ force_read(
1106
+ element,
1107
+ element.get_attribute('aria-valuemin'),
1108
+ @aria_value_minimum_prefix_before,
1109
+ @aria_value_minimum_suffix_before,
1110
+ @aria_value_minimum_prefix_after,
1111
+ @aria_value_minimum_suffix_after,
1112
+ DATA_ARIA_RANGE_MIN_OF
1113
+ )
1114
+ end
1115
+ if element.has_attribute?('aria-valuemax')
1116
+ force_read(
1117
+ element,
1118
+ element.get_attribute('aria-valuemax'),
1119
+ @aria_value_maximum_prefix_before,
1120
+ @aria_value_maximum_suffix_before,
1121
+ @aria_value_maximum_prefix_after,
1122
+ @aria_value_maximum_suffix_after,
1123
+ DATA_ARIA_RANGE_MAX_OF
1124
+ )
1125
+ end
1126
+ if element.has_attribute?('aria-autocomplete')
1127
+ attribute_value = element.get_attribute('aria-autocomplete')
1128
+ if attribute_value == 'both'
1129
+ force_read_simple(
1130
+ element,
1131
+ @aria_autocomplete_both_before,
1132
+ @aria_autocomplete_both_after,
1133
+ DATA_ARIA_AUTOCOMPLETE_OF
1134
+ )
1135
+ elsif attribute_value == 'inline'
1136
+ force_read_simple(
1137
+ element,
1138
+ @aria_autocomplete_list_before,
1139
+ @aria_autocomplete_list_after,
1140
+ DATA_ARIA_AUTOCOMPLETE_OF
1141
+ )
1142
+ elsif attribute_value == 'list'
1143
+ force_read_simple(
1144
+ element,
1145
+ @aria_autocomplete_inline_before,
1146
+ @aria_autocomplete_inline_after,
1147
+ DATA_ARIA_AUTOCOMPLETE_OF
1148
+ )
1149
+ end
1150
+ end
1151
+ if element.has_attribute?('aria-dropeffect')
1152
+ attribute_value = element.get_attribute('aria-dropeffect')
1153
+ if attribute_value == 'copy'
1154
+ force_read_simple(
1155
+ element,
1156
+ @aria_dropeffect_copy_before,
1157
+ @aria_dropeffect_copy_after,
1158
+ DATA_ARIA_DROPEFFECT_OF
1159
+ )
1160
+ elsif attribute_value == 'move'
1161
+ force_read_simple(
1162
+ element,
1163
+ @aria_dropeffect_move_before,
1164
+ @aria_dropeffect_move_after,
1165
+ DATA_ARIA_DROPEFFECT_OF
1166
+ )
1167
+ elsif attribute_value == 'link'
1168
+ force_read_simple(
1169
+ element,
1170
+ @aria_dropeffect_link_before,
1171
+ @aria_dropeffect_link_after,
1172
+ DATA_ARIA_DROPEFFECT_OF
1173
+ )
1174
+ elsif attribute_value == 'execute'
1175
+ force_read_simple(
1176
+ element,
1177
+ @aria_dropeffect_execute_before,
1178
+ @aria_dropeffect_execute_after,
1179
+ DATA_ARIA_DROPEFFECT_OF
1180
+ )
1181
+ elsif attribute_value == 'popup'
1182
+ force_read_simple(
1183
+ element,
1184
+ @aria_dropeffect_popup_before,
1185
+ @aria_dropeffect_popup_after,
1186
+ DATA_ARIA_DROPEFFECT_OF
1187
+ )
1188
+ end
1189
+ end
1190
+
1191
+ return unless element.has_attribute?('aria-grabbed')
1192
+
1193
+ attribute_value = element.get_attribute('aria-grabbed')
1194
+ if attribute_value == 'true'
1195
+ force_read_simple(
1196
+ element,
1197
+ @aria_grabbed_true_before,
1198
+ @aria_grabbed_true_after,
1199
+ DATA_ARIA_GRABBED_OF
1200
+ )
1201
+ elsif attribute_value == 'false'
1202
+ force_read_simple(
1203
+ element,
1204
+ @aria_grabbed_false_before,
1205
+ @aria_grabbed_false_after,
1206
+ DATA_ARIA_GRABBED_OF
1207
+ )
1208
+ end
1209
+ end
1210
+
1211
+ ##
1212
+ # @see Hatemile::AccessibleDisplay#display_all_waiaria_states
1213
+ def display_all_waiaria_states
1214
+ elements = @parser.find(
1215
+ '[aria-busy=true],[aria-checked],[aria-dropeffect],' \
1216
+ '[aria-expanded],[aria-grabbed],[aria-haspopup],[aria-level],' \
1217
+ '[aria-orientation],[aria-pressed],[aria-selected],[aria-sort],' \
1218
+ '[aria-required=true],[aria-valuemin],[aria-valuemax],' \
1219
+ '[aria-autocomplete]'
1220
+ ).list_results
1221
+ elements.each do |element|
1222
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
1223
+ display_waiaria_states(element)
1224
+ end
1225
+ end
1226
+ end
1227
+
1228
+ ##
1229
+ # @see Hatemile::AccessibleDisplay#display_link_attributes
1230
+ def display_link_attributes(link)
1231
+ if link.has_attribute?('download')
1232
+ force_read_simple(
1233
+ link,
1234
+ @attribute_download_before,
1235
+ @attribute_download_after,
1236
+ DATA_ATTRIBUTE_DOWNLOAD_OF
1237
+ )
1238
+ end
1239
+ if link.has_attribute?('target') &&
1240
+ link.get_attribute('target') == '_blank'
1241
+ force_read_simple(
1242
+ link,
1243
+ @attribute_target_blank_before,
1244
+ @attribute_target_blank_after,
1245
+ DATA_ATTRIBUTE_TARGET_OF
1246
+ )
1247
+ end
1248
+ end
1249
+
1250
+ ##
1251
+ # @see Hatemile::AccessibleDisplay#display_all_links_attributes
1252
+ def display_all_links_attributes
1253
+ links = @parser.find('a[download],a[target="_blank"]').list_results
1254
+ links.each do |link|
1255
+ if Hatemile::Util::CommonFunctions.is_valid_element?(link)
1256
+ display_link_attributes(link)
1257
+ end
1258
+ end
1259
+ end
1260
+
1261
+ ##
1262
+ # @see Hatemile::AccessibleDisplay#display_title
1263
+ def display_title(element)
1264
+ if element.get_tag_name == 'IMG'
1265
+ display_alternative_text_image(element)
1266
+ elsif element.has_attribute?('title') &&
1267
+ !element.get_attribute('title').empty?
1268
+ force_read(
1269
+ element,
1270
+ element.get_attribute('title').gsub(/[ \n\t\r]+/, ' ').strip,
1271
+ @attribute_title_prefix_before,
1272
+ @attribute_title_suffix_before,
1273
+ @attribute_title_prefix_after,
1274
+ @attribute_title_suffix_after,
1275
+ DATA_ATTRIBUTE_TITLE_OF
1276
+ )
1277
+ end
1278
+ end
1279
+
1280
+ ##
1281
+ # @see Hatemile::AccessibleDisplay#display_all_titles
1282
+ def display_all_titles
1283
+ elements = @parser.find('body [title]').list_results
1284
+ elements.each do |element|
1285
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
1286
+ display_title(element)
1287
+ end
1288
+ end
1289
+ end
1290
+
1291
+ ##
1292
+ # @see Hatemile::AccessibleDisplay#display_language
1293
+ def display_language(element)
1294
+ language_code = if element.has_attribute?('lang')
1295
+ element.get_attribute('lang')
1296
+ elsif element.has_attribute?('hreflang')
1297
+ element.get_attribute('hreflang')
1298
+ end
1299
+ language = get_language_description(language_code)
1300
+
1301
+ return if language.nil?
1302
+
1303
+ force_read(
1304
+ element,
1305
+ language,
1306
+ @attribute_language_prefix_before,
1307
+ @attribute_language_suffix_before,
1308
+ @attribute_language_prefix_after,
1309
+ @attribute_language_suffix_after,
1310
+ DATA_ATTRIBUTE_LANGUAGE_OF
1311
+ )
1312
+ end
1313
+
1314
+ ##
1315
+ # @see Hatemile::AccessibleDisplay#display_all_languages
1316
+ def display_all_languages
1317
+ elements = @parser.find(
1318
+ 'html[lang],body[lang],body [lang],body [hreflang]'
1319
+ ).list_results
1320
+ elements.each do |element|
1321
+ if Hatemile::Util::CommonFunctions.is_valid_element?(element)
1322
+ display_language(element)
1323
+ end
1324
+ end
1325
+ end
1326
+
1327
+ ##
1328
+ # @see Hatemile::AccessibleDisplay#display_alternative_text_image
1329
+ def display_alternative_text_image(image)
1330
+ if image.has_attribute?('alt') || image.has_attribute?('title')
1331
+ if image.has_attribute?('alt') &&
1332
+ !image.has_attribute?('title')
1333
+ image.set_attribute('title', image.get_attribute('alt'))
1334
+ elsif image.has_attribute?('title') &&
1335
+ !image.has_attribute?('alt')
1336
+ image.set_attribute('alt', image.get_attribute('title'))
1337
+ end
1338
+ @id_generator.generate_id(image)
1339
+ image.set_attribute(
1340
+ DATA_ATTRIBUTE_TITLE_OF,
1341
+ image.get_attribute('id')
1342
+ )
1343
+ else
1344
+ image.set_attribute('alt', '')
1345
+ image.set_attribute('role', 'presentation')
1346
+ image.set_attribute('aria-hidden', 'true')
1347
+ end
1348
+ end
1349
+
1350
+ ##
1351
+ # @see Hatemile::AccessibleDisplay#display_all_alternative_text_images
1352
+ def display_all_alternative_text_images
1353
+ images = @parser.find('img').list_results
1354
+ images.each do |image|
1355
+ if Hatemile::Util::CommonFunctions.is_valid_element?(image)
1356
+ display_alternative_text_image(image)
1357
+ end
1358
+ end
1359
+ end
1360
+ end
1361
+ end
1362
+ end