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,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