hatemile 2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +9 -0
- data/LICENSE +202 -0
- data/Rakefile +64 -0
- data/hatemile.gemspec +37 -0
- data/lib/hatemile/accessible_association.rb +62 -0
- data/lib/hatemile/accessible_css.rb +43 -0
- data/lib/hatemile/accessible_display.rb +178 -0
- data/lib/hatemile/accessible_event.rb +95 -0
- data/lib/hatemile/accessible_form.rb +101 -0
- data/lib/hatemile/accessible_navigation.rb +82 -0
- data/lib/hatemile/helper.rb +58 -0
- data/lib/hatemile/implementation/accessible_association_implementation.rb +346 -0
- data/lib/hatemile/implementation/accessible_css_implementation.rb +772 -0
- data/lib/hatemile/implementation/accessible_display_implementation.rb +1362 -0
- data/lib/hatemile/implementation/accessible_event_implementation.rb +278 -0
- data/lib/hatemile/implementation/accessible_form_implementation.rb +386 -0
- data/lib/hatemile/implementation/accessible_navigation_implementation.rb +561 -0
- data/lib/hatemile/util/common_functions.rb +106 -0
- data/lib/hatemile/util/configure.rb +92 -0
- data/lib/hatemile/util/css/rcp/rcp_declaration.rb +77 -0
- data/lib/hatemile/util/css/rcp/rcp_parser.rb +115 -0
- data/lib/hatemile/util/css/rcp/rcp_rule.rb +86 -0
- data/lib/hatemile/util/css/style_sheet_declaration.rb +59 -0
- data/lib/hatemile/util/css/style_sheet_parser.rb +43 -0
- data/lib/hatemile/util/css/style_sheet_rule.rb +73 -0
- data/lib/hatemile/util/html/html_dom_element.rb +234 -0
- data/lib/hatemile/util/html/html_dom_node.rb +131 -0
- data/lib/hatemile/util/html/html_dom_parser.rb +150 -0
- data/lib/hatemile/util/html/html_dom_text_node.rb +43 -0
- data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_element.rb +302 -0
- data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_node.rb +112 -0
- data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_parser.rb +208 -0
- data/lib/hatemile/util/html/nokogiri/nokogiri_html_dom_text_node.rb +83 -0
- data/lib/hatemile/util/id_generator.rb +53 -0
- data/lib/js/common.js +98 -0
- data/lib/js/eventlistener.js +36 -0
- data/lib/js/include.js +292 -0
- data/lib/js/scriptlist_validation_fields.js +13 -0
- data/lib/js/validation.js +205 -0
- data/lib/locale/en-US.yml +388 -0
- data/lib/locale/pt-BR.yml +389 -0
- data/lib/skippers.xml +6 -0
- data/lib/symbols.xml +40 -0
- data/test/locale/en-US.yml +5 -0
- data/test/locale/pt-BR.yml +4 -0
- data/test/test_accessible_association_implementation.rb +258 -0
- data/test/test_accessible_css_implementation.rb +518 -0
- data/test/test_accessible_display_implementation.rb +873 -0
- data/test/test_accessible_form_implementation.rb +283 -0
- data/test/test_accessible_navigation_implementation.rb +228 -0
- data/test/test_common_functions.rb +128 -0
- data/test/test_configure.rb +73 -0
- data/test/test_nokogiri_html_dom_element.rb +586 -0
- data/test/test_nokogiri_html_dom_parser.rb +363 -0
- data/test/test_nokogiri_html_dom_text_node.rb +225 -0
- data/test/test_rcp_declaration.rb +103 -0
- data/test/test_rcp_parser.rb +86 -0
- data/test/test_rcp_rule.rb +89 -0
- 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
|