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,561 @@
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_navigation')
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 AccessibleNavigationImplementation class is official implementation of
39
+ # AccessibleNavigation interface.
40
+ class AccessibleNavigationImplementation < AccessibleNavigation
41
+ public_class_method :new
42
+
43
+ ##
44
+ # The id of list element that contains the skippers.
45
+ ID_CONTAINER_SKIPPERS = 'container-skippers'.freeze
46
+
47
+ ##
48
+ # The id of list element that contains the links for the headings, before
49
+ # the whole content of page.
50
+ ID_CONTAINER_HEADING_BEFORE = 'container-heading-before'.freeze
51
+
52
+ ##
53
+ # The id of list element that contains the links for the headings, after
54
+ # the whole content of page.
55
+ ID_CONTAINER_HEADING_AFTER = 'container-heading-after'.freeze
56
+
57
+ ##
58
+ # The HTML class of text of description of container of heading links.
59
+ CLASS_TEXT_HEADING = 'text-heading'.freeze
60
+
61
+ ##
62
+ # The HTML class of anchor of skipper.
63
+ CLASS_SKIPPER_ANCHOR = 'skipper-anchor'.freeze
64
+
65
+ ##
66
+ # The HTML class of anchor of heading link.
67
+ CLASS_HEADING_ANCHOR = 'heading-anchor'.freeze
68
+
69
+ ##
70
+ # The HTML class of force link, before it.
71
+ CLASS_FORCE_LINK_BEFORE = 'force-link-before'.freeze
72
+
73
+ ##
74
+ # The HTML class of force link, after it.
75
+ CLASS_FORCE_LINK_AFTER = 'force-link-after'.freeze
76
+
77
+ ##
78
+ # The name of attribute that links the anchor of skipper with the element.
79
+ DATA_ANCHOR_FOR = 'data-anchorfor'.freeze
80
+
81
+ ##
82
+ # The name of attribute that links the anchor of heading link with
83
+ # heading.
84
+ DATA_HEADING_ANCHOR_FOR = 'data-headinganchorfor'.freeze
85
+
86
+ ##
87
+ # The name of attribute that indicates the level of heading of link.
88
+ DATA_HEADING_LEVEL = 'data-headinglevel'.freeze
89
+
90
+ ##
91
+ # The name of attribute that link the anchor of long description with the
92
+ # image.
93
+ DATA_ATTRIBUTE_LONG_DESCRIPTION_OF =
94
+ 'data-attributelongdescriptionof'.freeze
95
+
96
+ protected
97
+
98
+ ##
99
+ # Generate the list of skippers of page.
100
+ #
101
+ # @return [Hatemile::Util::Html::HTMLDOMElement] The list of skippers of
102
+ # page.
103
+ def generate_list_skippers
104
+ container = @parser.find("##{ID_CONTAINER_SKIPPERS}").first_result
105
+ html_list = nil
106
+ if container.nil?
107
+ local = @parser.find('body').first_result
108
+ unless local.nil?
109
+ container = @parser.create_element('div')
110
+ container.set_attribute('id', ID_CONTAINER_SKIPPERS)
111
+ local.prepend_element(container)
112
+ end
113
+ end
114
+ unless container.nil?
115
+ html_list = @parser.find(container).find_children('ul').first_result
116
+ if html_list.nil?
117
+ html_list = @parser.create_element('ul')
118
+ container.append_element(html_list)
119
+ end
120
+ end
121
+ @list_skippers_added = true
122
+
123
+ html_list
124
+ end
125
+
126
+ ##
127
+ # Generate the list of heading links of page.
128
+ def generate_list_heading
129
+ local = @parser.find('body').first_result
130
+
131
+ return if local.nil?
132
+
133
+ container_before = @parser.find(
134
+ "##{ID_CONTAINER_HEADING_BEFORE}"
135
+ ).first_result
136
+ if container_before.nil? && !@elements_heading_before.empty?
137
+ container_before = @parser.create_element('div')
138
+ container_before.set_attribute('id', ID_CONTAINER_HEADING_BEFORE)
139
+
140
+ text_container_before = @parser.create_element('span')
141
+ text_container_before.set_attribute('class', CLASS_TEXT_HEADING)
142
+ text_container_before.append_text(@elements_heading_before)
143
+
144
+ container_before.append_element(text_container_before)
145
+ local.prepend_element(container_before)
146
+ end
147
+ unless container_before.nil?
148
+ @list_heading_before = @parser.find(
149
+ container_before
150
+ ).find_children('ol').first_result
151
+ if @list_heading_before.nil?
152
+ @list_heading_before = @parser.create_element('ol')
153
+ container_before.append_element(@list_heading_before)
154
+ end
155
+ end
156
+
157
+ container_after = @parser.find(
158
+ "##{ID_CONTAINER_HEADING_AFTER}"
159
+ ).first_result
160
+ if container_after.nil? && !@elements_heading_after.empty?
161
+ container_after = @parser.create_element('div')
162
+ container_after.set_attribute('id', ID_CONTAINER_HEADING_AFTER)
163
+
164
+ text_container_after = @parser.create_element('span')
165
+ text_container_after.set_attribute('class', CLASS_TEXT_HEADING)
166
+ text_container_after.append_text(@elements_heading_after)
167
+
168
+ container_after.append_element(text_container_after)
169
+ local.append_element(container_after)
170
+ end
171
+ unless container_after.nil?
172
+ @list_heading_after = @parser.find(
173
+ container_after
174
+ ).find_children('ol').first_result
175
+ if @list_heading_after.nil?
176
+ @list_heading_after = @parser.create_element('ol')
177
+ container_after.append_element(@list_heading_after)
178
+ end
179
+ end
180
+
181
+ @list_heading_added = true
182
+ end
183
+
184
+ ##
185
+ # Returns the level of heading.
186
+ #
187
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The heading.
188
+ # @return [Integer] The level of heading.
189
+ def get_heading_level(element)
190
+ tag = element.get_tag_name
191
+ return 1 if tag == 'H1'
192
+ return 2 if tag == 'H2'
193
+ return 3 if tag == 'H3'
194
+ return 4 if tag == 'H4'
195
+ return 5 if tag == 'H5'
196
+ return 6 if tag == 'H6'
197
+ -1
198
+ end
199
+
200
+ ##
201
+ # Check that the headings of page are sintatic correct.
202
+ #
203
+ # @return [Boolean] True if the headings of page are sintatic correct or
204
+ # false if not.
205
+ def valid_heading?
206
+ elements = @parser.find('h1,h2,h3,h4,h5,h6').list_results
207
+ last_level = 0
208
+ count_main_heading = 0
209
+ @validate_heading = true
210
+ elements.each do |element|
211
+ level = get_heading_level(element)
212
+ if level == 1
213
+ return false if count_main_heading == 1
214
+ count_main_heading = 1
215
+ end
216
+ return false if (level - last_level) > 1
217
+ last_level = level
218
+ end
219
+ true
220
+ end
221
+
222
+ ##
223
+ # Generate an anchor for the element.
224
+ #
225
+ # @param element [Hatemile::Util::Html::HTMLDOMElement] The element.
226
+ # @param data_attribute [String] The name of attribute that links the
227
+ # element with the anchor.
228
+ # @param anchor_class [String] The HTML class of anchor.
229
+ # @return [Hatemile::Util::Html::HTMLDOMElement] The anchor.
230
+ def generate_anchor_for(element, data_attribute, anchor_class)
231
+ @id_generator.generate_id(element)
232
+ anchor = nil
233
+ if @parser.find(
234
+ "[#{data_attribute}=\"#{element.get_attribute('id')}\"]"
235
+ ).first_result.nil?
236
+ if element.get_tag_name == 'A'
237
+ anchor = element
238
+ else
239
+ anchor = @parser.create_element('a')
240
+ @id_generator.generate_id(anchor)
241
+ anchor.set_attribute('class', anchor_class)
242
+ element.insert_before(anchor)
243
+ end
244
+ unless anchor.has_attribute?('name')
245
+ anchor.set_attribute('name', anchor.get_attribute('id'))
246
+ end
247
+ anchor.set_attribute(data_attribute, element.get_attribute('id'))
248
+ end
249
+ anchor
250
+ end
251
+
252
+ ##
253
+ # Replace the shortcut of elements, that has the shortcut passed.
254
+ #
255
+ # @param shortcut [String] The shortcut.
256
+ # @return [void]
257
+ def free_shortcut(shortcut)
258
+ found = false
259
+ alpha_numbers = '1234567890abcdefghijklmnopqrstuvwxyz'
260
+ elements = @parser.find('[accesskey]').list_results
261
+ elements.each do |element|
262
+ shortcuts = element.get_attribute('accesskey').downcase
263
+
264
+ unless Hatemile::Util::CommonFunctions.in_list?(shortcuts, shortcut)
265
+ next
266
+ end
267
+
268
+ (0..alpha_numbers.length - 1).each do |i|
269
+ key = alpha_numbers[i, i + 1]
270
+ found = true
271
+ elements.each do |element_with_shortcuts|
272
+ shortcuts = element_with_shortcuts.get_attribute(
273
+ 'accesskey'
274
+ ).downcase
275
+
276
+ unless Hatemile::Util::CommonFunctions.in_list?(shortcuts, key)
277
+ next
278
+ end
279
+
280
+ element.set_attribute('accesskey', key)
281
+ found = false
282
+ break
283
+ end
284
+ break if found
285
+ end
286
+ break if found
287
+ end
288
+ end
289
+
290
+ ##
291
+ # Returns the skippers of configuration.
292
+ #
293
+ #
294
+ # @param configure [Hatemile::Util::Configure] The configuration of
295
+ # HaTeMiLe.
296
+ # @param file_name [String] The file path of skippers configuration.
297
+ # @return [Array<Hash>] The skippers of configuration.
298
+ def get_skippers(configure, file_name)
299
+ skippers = []
300
+ if file_name.nil?
301
+ file_name = File.join(
302
+ File.dirname(File.dirname(File.dirname(__FILE__))),
303
+ 'skippers.xml'
304
+ )
305
+ end
306
+ document = REXML::Document.new(File.read(file_name))
307
+ document.elements.each('skippers/skipper') do |skipper_xml|
308
+ skipper = {}
309
+ skipper[:selector] = skipper_xml.attribute('selector').value
310
+ skipper[:description] = configure.get_parameter(
311
+ skipper_xml.attribute('description').value
312
+ )
313
+ skipper[:shortcut] = skipper_xml.attribute('shortcut').value
314
+ skippers.push(skipper)
315
+ end
316
+ skippers
317
+ end
318
+
319
+ public
320
+
321
+ ##
322
+ # Initializes a new object that manipulate the accessibility of the
323
+ # navigation of parser.
324
+ #
325
+ # @param parser [Hatemile::Util::Html::HTMLDOMParser] The HTML parser.
326
+ # @param configure [Hatemile::Util::Configure] The configuration of
327
+ # HaTeMiLe.
328
+ # @param skipper_file_name [String] The file path of skippers
329
+ # configuration.
330
+ def initialize(parser, configure, skipper_file_name = nil)
331
+ Hatemile::Helper.require_not_nil(parser, configure)
332
+ Hatemile::Helper.require_valid_type(
333
+ parser,
334
+ Hatemile::Util::Html::HTMLDOMParser
335
+ )
336
+ Hatemile::Helper.require_valid_type(
337
+ configure,
338
+ Hatemile::Util::Configure
339
+ )
340
+ Hatemile::Helper.require_valid_type(skipper_file_name, String)
341
+
342
+ @parser = parser
343
+ @id_generator = Hatemile::Util::IDGenerator.new('navigation')
344
+ @elements_heading_before = configure.get_parameter(
345
+ 'elements-heading-before'
346
+ )
347
+ @elements_heading_after = configure.get_parameter(
348
+ 'elements-heading-after'
349
+ )
350
+ @attribute_long_description_prefix_before = configure.get_parameter(
351
+ 'attribute-longdescription-prefix-before'
352
+ )
353
+ @attribute_long_description_suffix_before = configure.get_parameter(
354
+ 'attribute-longdescription-suffix-before'
355
+ )
356
+ @attribute_long_description_prefix_after = configure.get_parameter(
357
+ 'attribute-longdescription-prefix-after'
358
+ )
359
+ @attribute_long_description_suffix_after = configure.get_parameter(
360
+ 'attribute-longdescription-suffix-after'
361
+ )
362
+ @skippers = get_skippers(configure, skipper_file_name)
363
+ @list_skippers_added = false
364
+ @list_heading_added = false
365
+ @validate_heading = false
366
+ @valid_heading = false
367
+ @list_skippers = nil
368
+ @list_heading_before = nil
369
+ @list_heading_after = nil
370
+ end
371
+
372
+ ##
373
+ # @see Hatemile::AccessibleNavigation#provide_navigation_by_skipper
374
+ def provide_navigation_by_skipper(element)
375
+ skipper = nil
376
+ @skippers.each do |auxiliar_skipper|
377
+ elements = @parser.find(auxiliar_skipper[:selector]).list_results
378
+ if elements.include?(element)
379
+ skipper = auxiliar_skipper
380
+ break
381
+ end
382
+ end
383
+
384
+ return if skipper.nil?
385
+
386
+ @list_skippers = generate_list_skippers unless @list_skippers_added
387
+
388
+ return if @list_skippers.nil?
389
+
390
+ anchor = generate_anchor_for(
391
+ element,
392
+ DATA_ANCHOR_FOR,
393
+ CLASS_SKIPPER_ANCHOR
394
+ )
395
+
396
+ return if anchor.nil?
397
+
398
+ item_link = @parser.create_element('li')
399
+ link = @parser.create_element('a')
400
+ link.set_attribute('href', "##{anchor.get_attribute('name')}")
401
+ link.append_text(skipper[:description])
402
+
403
+ free_shortcut(skipper[:shortcut])
404
+ link.set_attribute('accesskey', skipper[:shortcut])
405
+
406
+ @id_generator.generate_id(link)
407
+
408
+ item_link.append_element(link)
409
+ @list_skippers.append_element(item_link)
410
+ end
411
+
412
+ ##
413
+ # @see Hatemile::AccessibleNavigation#provide_navigation_by_all_skippers
414
+ def provide_navigation_by_all_skippers
415
+ @skippers.each do |skipper|
416
+ elements = @parser.find(skipper[:selector]).list_results
417
+ elements.each do |element|
418
+ next unless Hatemile::Util::CommonFunctions.is_valid_element?(
419
+ element
420
+ )
421
+
422
+ provide_navigation_by_skipper(element)
423
+ end
424
+ end
425
+ end
426
+
427
+ ##
428
+ # @see Hatemile::AccessibleNavigation#provide_navigation_by_heading
429
+ def provide_navigation_by_heading(heading)
430
+ @valid_heading = valid_heading? unless @validate_heading
431
+
432
+ return unless @valid_heading
433
+
434
+ anchor = generate_anchor_for(
435
+ heading,
436
+ DATA_HEADING_ANCHOR_FOR,
437
+ CLASS_HEADING_ANCHOR
438
+ )
439
+
440
+ return if anchor.nil?
441
+
442
+ generate_list_heading unless @list_heading_added
443
+ list_before = nil
444
+ list_after = nil
445
+ level = get_heading_level(heading)
446
+ if level == 1
447
+ list_before = @list_heading_before
448
+ list_after = @list_heading_after
449
+ else
450
+ selector = "[#{DATA_HEADING_LEVEL}=\"#{level - 1}\"]"
451
+ unless @list_heading_before.nil?
452
+ super_item_before = @parser.find(
453
+ @list_heading_before
454
+ ).find_descendants(selector).last_result
455
+ end
456
+ unless super_item_before.nil?
457
+ list_before = @parser.find(
458
+ super_item_before
459
+ ).find_children('ol').first_result
460
+ if list_before.nil?
461
+ list_before = @parser.create_element('ol')
462
+ super_item_before.append_element(list_before)
463
+ end
464
+ end
465
+ unless @list_heading_after.nil?
466
+ super_item_after = @parser.find(
467
+ @list_heading_after
468
+ ).find_descendants(selector).last_result
469
+ end
470
+ unless super_item_after.nil?
471
+ list_after = @parser.find(
472
+ super_item_after
473
+ ).find_children('ol').first_result
474
+ if list_after.nil?
475
+ list_after = @parser.create_element('ol')
476
+ super_item_after.append_element(list_after)
477
+ end
478
+ end
479
+ end
480
+
481
+ item = @parser.create_element('li')
482
+ item.set_attribute(DATA_HEADING_LEVEL, level.to_s)
483
+
484
+ link = @parser.create_element('a')
485
+ link.set_attribute('href', "##{anchor.get_attribute('name')}")
486
+ link.append_text(heading.get_text_content)
487
+ item.append_element(link)
488
+
489
+ list_before.append_element(item.clone_element) unless list_before.nil?
490
+ list_after.append_element(item.clone_element) unless list_after.nil?
491
+ end
492
+
493
+ ##
494
+ # @see Hatemile::AccessibleNavigation#provide_navigation_by_all_headings
495
+ def provide_navigation_by_all_headings
496
+ headings = @parser.find('h1,h2,h3,h4,h5,h6').list_results
497
+ headings.each do |heading|
498
+ if Hatemile::Util::CommonFunctions.is_valid_element?(heading)
499
+ provide_navigation_by_heading(heading)
500
+ end
501
+ end
502
+ end
503
+
504
+ ##
505
+ # @see Hatemile::AccessibleNavigation#provide_navigation_to_long_description
506
+ def provide_navigation_to_long_description(image)
507
+ unless image.has_attribute?('longdesc') && image.has_attribute?('alt')
508
+ return
509
+ end
510
+
511
+ @id_generator.generate_id(image)
512
+ id = image.get_attribute('id')
513
+
514
+ selector = "[#{DATA_ATTRIBUTE_LONG_DESCRIPTION_OF}=\"#{id}\"]"
515
+ return unless @parser.find(selector).first_result.nil?
516
+
517
+ alternative_text = image.get_attribute('alt').gsub(
518
+ /[ \n\t\r]+/,
519
+ ' '
520
+ ).strip
521
+ unless @attribute_long_description_prefix_before.empty? &&
522
+ @attribute_long_description_suffix_before.empty?
523
+ before_text = "#{@attribute_long_description_prefix_before}" \
524
+ "#{alternative_text}" \
525
+ "#{@attribute_long_description_suffix_before}"
526
+ before_anchor = @parser.create_element('a')
527
+ before_anchor.set_attribute('href', image.get_attribute('longdesc'))
528
+ before_anchor.set_attribute('target', '_blank')
529
+ before_anchor.set_attribute(DATA_ATTRIBUTE_LONG_DESCRIPTION_OF, id)
530
+ before_anchor.set_attribute('class', CLASS_FORCE_LINK_BEFORE)
531
+ before_anchor.append_text(before_text)
532
+ image.insert_after(before_anchor)
533
+ end
534
+ unless @attribute_long_description_prefix_after.empty? &&
535
+ @attribute_long_description_suffix_after.empty?
536
+ after_text = "#{@attribute_long_description_prefix_after}" \
537
+ "#{alternative_text}" \
538
+ "#{@attribute_long_description_suffix_after}"
539
+ after_anchor = @parser.create_element('a')
540
+ after_anchor.set_attribute('href', image.get_attribute('longdesc'))
541
+ after_anchor.set_attribute('target', '_blank')
542
+ after_anchor.set_attribute(DATA_ATTRIBUTE_LONG_DESCRIPTION_OF, id)
543
+ after_anchor.set_attribute('class', CLASS_FORCE_LINK_AFTER)
544
+ after_anchor.append_text(after_text)
545
+ image.insert_after(after_anchor)
546
+ end
547
+ end
548
+
549
+ ##
550
+ # @see Hatemile::AccessibleNavigation#provide_navigation_to_all_long_descriptions
551
+ def provide_navigation_to_all_long_descriptions
552
+ images = @parser.find('[alt][longdesc]').list_results
553
+ images.each do |image|
554
+ if Hatemile::Util::CommonFunctions.is_valid_element?(image)
555
+ provide_navigation_to_long_description(image)
556
+ end
557
+ end
558
+ end
559
+ end
560
+ end
561
+ end