motion-accessibility 3.0.3 → 3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +314 -81
- data/lib/motion-accessibility-console.rb +1 -0
- data/lib/project/constants.rb +30 -4
- data/lib/project/element.rb +13 -9
- data/lib/project/inspector.rb +3 -1
- data/lib/project/motion-accessibility-console/browser.rb +16 -2
- data/lib/project/motion-accessibility-console/touch.rb +24 -6
- data/lib/project/motion-accessibility-console/tree.rb +31 -1
- data/lib/project/object.rb +16 -0
- data/lib/project/status.rb +27 -0
- data/lib/project/test.rb +50 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac5d11d4ddac910e4320eda4b40d2378f2c34fbd
|
4
|
+
data.tar.gz: 0cb56cc757c04b0f671217d890989294793b90b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fafbc0d2fceb2412f1539036230afe52d1bd4d679b403df5ef14a56bbc6c26e6856143d0784497e55a82be68a4d565e947b83b6712f0591331b4559c638be9d
|
7
|
+
data.tar.gz: 32716ec1402e0f7625baac2d41afd4740ecd217820bac7e90cf38fd8aaf12508a7473134e2d55e57f3300d64a4c1894aa11f37c4c8abfe55a5f641f61043fcdc
|
data/README.md
CHANGED
@@ -4,7 +4,14 @@
|
|
4
4
|
|
5
5
|
https://github.com/austinseraphin/motion-accessibility
|
6
6
|
|
7
|
-
Motion-accessibility provides the tools needed for sighted and blind iOS
|
7
|
+
Motion-accessibility provides the tools needed for sighted and blind iOS
|
8
|
+
RubyMotion developers to make their apps more accessible. It wraps Apple’s
|
9
|
+
UIAccessibility protocols in Ruby, and provides an accessibility inspector. It
|
10
|
+
has a console for blind developers, since the iOS simulator doesn’t work well
|
11
|
+
with VoiceOver. It also has automated accessibility testing for your views, and
|
12
|
+
the accessibility doctor will help diagnose your problems and tell you how to
|
13
|
+
fix them. You can build accessibility testing into your specs, so you will
|
14
|
+
never break VoiceOver compatibility!
|
8
15
|
|
9
16
|
## Installation
|
10
17
|
|
@@ -23,7 +30,9 @@ Or install it yourself as:
|
|
23
30
|
## Usage
|
24
31
|
### The Motion-Accessibility Console
|
25
32
|
|
26
|
-
The motion-accessibility console gives you a way to interact with a running
|
33
|
+
The motion-accessibility console gives you a way to interact with a running
|
34
|
+
application through a purely textual interface. This works well for blind
|
35
|
+
developers and command line users.
|
27
36
|
|
28
37
|
#### Enabling the Console
|
29
38
|
|
@@ -31,18 +40,15 @@ To enable the console, you can do one of two things. If you would just like to t
|
|
31
40
|
|
32
41
|
#### `browse` or `b`
|
33
42
|
|
34
|
-
The `browse` or `b` command lets you examine the view hierarchy in a
|
43
|
+
The `browse` or `b` command lets you examine the view hierarchy in a
|
44
|
+
speech-friendly way. This lets you see all the relevant views displayed in your
|
45
|
+
running application. It will detect if the screen has changed and refresh
|
46
|
+
itself automatically.
|
35
47
|
|
36
48
|
The following examples come from the sample app included with motion-accessibility.
|
37
49
|
|
38
|
-
```
|
39
|
-
|
40
|
-
Browsing UIWindow
|
41
|
-
1 UIView with 3 subviews
|
42
|
-
2 UINavigationBar with 2 subviews
|
43
|
-
3 UITabBar with 3 subviews
|
44
|
-
=> nil
|
45
|
-
```
|
50
|
+
``` (main)> browse Browsing UIWindow 1 UIView with 3 subviews 2
|
51
|
+
UINavigationBar with 2 subviews 3 UITabBar with 3 subviews => nil ```
|
46
52
|
|
47
53
|
If a view has subviews, you can browse that view.
|
48
54
|
|
@@ -56,15 +62,20 @@ Browsing UIView
|
|
56
62
|
=> nil
|
57
63
|
```
|
58
64
|
|
59
|
-
You can return to the top of the view hierarchy by using `:top`. This also
|
65
|
+
You can return to the top of the view hierarchy by using `:top`. This also
|
66
|
+
refreshes the browser.
|
60
67
|
|
61
68
|
You can refresh a table with `:refresh`.
|
62
69
|
|
63
|
-
You may pass the `:scroll` keyword to scroll a UIScrollView or descendants,
|
70
|
+
You may pass the `:scroll` keyword to scroll a UIScrollView or descendants,
|
71
|
+
such as a UITableView. This still has some minor issues .
|
64
72
|
|
65
73
|
#### `view` or `v`
|
66
74
|
|
67
|
-
The `view` or `v` command simply returns the current view. If you have just
|
75
|
+
The `view` or `v` command simply returns the current view. If you have just
|
76
|
+
browsed a view, it will return that. Otherwise, you may specify the view you
|
77
|
+
wish to browse. Note that for all the commands, you may either use its number
|
78
|
+
or accessibility label.
|
68
79
|
|
69
80
|
```
|
70
81
|
(main)> v 1
|
@@ -72,7 +83,9 @@ The `view` or `v` command simply returns the current view. If you have just brow
|
|
72
83
|
```
|
73
84
|
|
74
85
|
#### `touch`
|
75
|
-
The `touch` command lets you interact with the various controls. It works on
|
86
|
+
The `touch` command lets you interact with the various controls. It works on
|
87
|
+
all standard UIControls. `touch` can accept an argument depending on the type
|
88
|
+
of control. For example, you can pass a UITextField a string to set its value.
|
76
89
|
|
77
90
|
```
|
78
91
|
(main)> touch 2,"Motion-accessibility rocks!"
|
@@ -84,7 +97,9 @@ Browsing UIView
|
|
84
97
|
=> nil
|
85
98
|
```
|
86
99
|
|
87
|
-
UIButtons can take a UIControlEvent, but default to
|
100
|
+
UIButtons can take a UIControlEvent, but default to
|
101
|
+
`UIControlEventTouchUpInside`. Note here the use of an accessibility label to
|
102
|
+
reference the view.
|
88
103
|
|
89
104
|
```
|
90
105
|
(main)> touch "update"
|
@@ -98,15 +113,13 @@ Browsing UIView
|
|
98
113
|
|
99
114
|
### The Accessibility Inspector
|
100
115
|
|
101
|
-
You can easily see the state of any of the following attributes and methods by
|
116
|
+
You can easily see the state of any of the following attributes and methods by
|
117
|
+
using the accessibility inspector. Just call `Accessibility.inspect` and pass
|
118
|
+
any object as an argument.
|
102
119
|
|
103
120
|
```
|
104
|
-
(main)>
|
105
|
-
|
106
|
-
(main)> label.text="Hello!"
|
107
|
-
=> "Hello!"
|
108
|
-
(main)> Accessibility.inspect label
|
109
|
-
#<UILabel:0x103b8c40>
|
121
|
+
(main)> A11y.inspect label
|
122
|
+
#<UILabel:0xb438140>
|
110
123
|
Accessibility label: Hello!
|
111
124
|
Accessibility hint: nil
|
112
125
|
Accessibility traits: Static text
|
@@ -117,18 +130,24 @@ Accessibility activation point: x=50.0 y=50.0
|
|
117
130
|
Accessibility path: nil
|
118
131
|
Accessibility view is modal: false
|
119
132
|
Should group accessibility children: false
|
133
|
+
Accessibility elements: nil
|
120
134
|
Accessibility elements hidden: false
|
121
135
|
Is accessibility element: true
|
136
|
+
Accessibility custom actions: nil
|
122
137
|
Accessibility identifier: nil
|
123
138
|
Accessible: true
|
124
139
|
=> nil
|
125
140
|
```
|
126
141
|
|
127
|
-
By the way, `a11y` stands for `accessibility`, because it has a, then 11
|
142
|
+
By the way, `a11y` stands for `accessibility`, because it has a, then 11
|
143
|
+
letters, then y. Hence, you can use `A11y.inspect` as a shortcut.
|
128
144
|
|
129
145
|
### Automated Accessibility Testing
|
130
146
|
|
131
|
-
Below you will find detailed documentation about all of the accessibility
|
147
|
+
Below you will find detailed documentation about all of the accessibility
|
148
|
+
protocols. Don’t feel overwhelmed. The accessibility inspector will tell you
|
149
|
+
exactly what you have to do. Let’s start by creating an unlabeled button, the
|
150
|
+
bane of all VOiceOver users.
|
132
151
|
|
133
152
|
```
|
134
153
|
(main)> button=UIButton.new
|
@@ -157,11 +176,13 @@ Accessible: false
|
|
157
176
|
This incorporates two features discussed below.
|
158
177
|
|
159
178
|
#### `accessible?`
|
160
|
-
Call the `accessible?` predicate on any object to determine its accessibility.
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
179
|
+
Call the `accessible?` predicate on any object to determine its accessibility.
|
180
|
+
Like all predicates it returns true or false. You can include this in your
|
181
|
+
specs. If you build in accessibility testing you will never break
|
182
|
+
accessibility, something even worse than no accessibility at all. For example,
|
183
|
+
if you have a variable `@label` which contains a label, you could write: ```
|
184
|
+
@label.should.be.accessible ``` So simple! This works recursively. Say you run
|
185
|
+
some functional tests on a view controller.
|
165
186
|
|
166
187
|
```
|
167
188
|
tests Test_Controller
|
@@ -181,20 +202,30 @@ it “accessible?” do
|
|
181
202
|
@app.should.be.accessible
|
182
203
|
end
|
183
204
|
```
|
184
|
-
You may not want to do this however, because it can get confusing navigating
|
205
|
+
You may not want to do this however, because it can get confusing navigating
|
206
|
+
down subview hierarchies, though it will report the path taken. Still, better
|
207
|
+
to do that then nothing at all.
|
185
208
|
|
186
209
|
#### `Accessibility.doctor`
|
187
|
-
The accessibility doctor will report on what you have to do. It writes this to
|
210
|
+
The accessibility doctor will report on what you have to do. It writes this to
|
211
|
+
the NSLog. If given no arguments it will report on the last object called with
|
212
|
+
the `accessible?` predicate. It returns the object with the problem, or nil if
|
213
|
+
it finds nothing wrong. The accessibility inspector returns this as well. If a
|
214
|
+
spec fails, `accessible?` will call this automatically..
|
188
215
|
|
189
216
|
#### `accessibility_test`
|
190
|
-
Finally, you can specify which accessibility test applies to an object by
|
217
|
+
Finally, you can specify which accessibility test applies to an object by
|
218
|
+
setting this value. You may do this in the same way you set other attributes.
|
219
|
+
You can use a setter:
|
191
220
|
|
192
221
|
```
|
193
222
|
view=UIView.new
|
194
223
|
view.accessibility_test=:UILabel
|
195
224
|
```
|
196
225
|
|
226
|
+
|
197
227
|
Or you may define it in a class. If you do this make sure that it returns a symbol of the class you want to test against, since it has no error checking unlike the setter.
|
228
|
+
|
198
229
|
```
|
199
230
|
class Custom_View < UIView
|
200
231
|
|
@@ -207,15 +238,28 @@ end
|
|
207
238
|
|
208
239
|
### Accessibility vs. Usability
|
209
240
|
|
210
|
-
A difference exists between accessibility and usability, though often the two
|
241
|
+
A difference exists between accessibility and usability, though often the two
|
242
|
+
get lumped together under the umbrella of the former. Accessibility refers to
|
243
|
+
whether or not a user can view and interact with something in a meaningful way.
|
244
|
+
In this case, this means making VoiceOver aware of the different elements of
|
245
|
+
your app. Usability gets into more intangible realms, and has to do with
|
246
|
+
whether or not it actually makes sense to a user. In this case this means a
|
247
|
+
blind human using VoiceOver, and only a blind human using VoiceOver can tell
|
248
|
+
you this. A computer can test for accessibility, but only a human can test for
|
249
|
+
usability.
|
211
250
|
|
212
251
|
### UIAccessibility Informal Protocol
|
213
252
|
|
214
|
-
This informal protocol describes how to convey proper information to VoiceOver,
|
253
|
+
This informal protocol describes how to convey proper information to VoiceOver,
|
254
|
+
the piece of software which allows the blind to read the screen. All of the
|
255
|
+
UIAccessibility attributes now have Ruby-like names. Just like the protocol,
|
256
|
+
these methods belong to the NSObject class, so you can use them anywhere.
|
257
|
+
Usually, you will define them for a UIView.
|
215
258
|
|
216
259
|
#### Defining Attributes in a Custom Subclass
|
217
260
|
|
218
|
-
You can define these attributes in one of two ways. Firstly you can define a
|
261
|
+
You can define these attributes in one of two ways. Firstly you can define a
|
262
|
+
method in a subclass of UIView.
|
219
263
|
|
220
264
|
```
|
221
265
|
class CustomView < UIView
|
@@ -227,7 +271,9 @@ end
|
|
227
271
|
end
|
228
272
|
```
|
229
273
|
|
230
|
-
Note that motion-accessibility uses some metaprogramming to accomplish this. It
|
274
|
+
Note that motion-accessibility uses some metaprogramming to accomplish this. It
|
275
|
+
tries to play nicely with other gems. If another gem has already defined the
|
276
|
+
`NSObject.method_added` method, it will alias it and run it before its own.
|
231
277
|
|
232
278
|
#### Defining Attributes in the Instanciation Code
|
233
279
|
|
@@ -240,20 +286,38 @@ view.accessibility_label="Hello."
|
|
240
286
|
|
241
287
|
#### `accessibility_label`
|
242
288
|
|
243
|
-
What VoiceOver reads. The most important thing to define. Many standard views
|
289
|
+
What VoiceOver reads. The most important thing to define. Many standard views
|
290
|
+
set the accessibility label automatically. For example, if you set the text of
|
291
|
+
a UILabel, it will also set the accessibility label. However, if you make a
|
292
|
+
custom view you will have to define it. If you set an image for a button, its
|
293
|
+
title will default to the image name. This can have ugly results. Even more
|
294
|
+
annoyingly, if you don't set a label a button will just read as "Button". Make
|
295
|
+
sure to set this.
|
244
296
|
|
245
|
-
Labels briefly describe the element. They do not include the control type. They
|
297
|
+
Labels briefly describe the element. They do not include the control type. They
|
298
|
+
begin with a capitalized word and do not end with a period. Localize them when
|
299
|
+
possible.
|
246
300
|
|
247
301
|
#### `accessibility_hint`
|
248
302
|
|
249
|
-
Hints describe the results of performing an action. Only provide one when not
|
303
|
+
Hints describe the results of performing an action. Only provide one when not
|
304
|
+
obvious. They briefly describe results. They begin with a verb and omit the
|
305
|
+
subject. They use the third person singular declarative form - Plays music
|
306
|
+
instead of play music. Imagine describing it to a friend. "Tapping the button
|
307
|
+
plays music." They begin with a capitalized word and end with a period. They do
|
308
|
+
not include the action or gesture. They do not include the name or type of the
|
309
|
+
controller or view. Localized.
|
250
310
|
|
251
311
|
#### `accessibility_traits`
|
252
312
|
|
253
|
-
Traits describe an element's state, behavior, or usage. They tell
|
254
|
-
|
313
|
+
Traits describe an element's state, behavior, or usage. They tell VoiceOver how
|
314
|
+
to respond to a view. To combine them, use the single vertical bar `|` binary
|
315
|
+
or operator. Remember to call `super.accessibility_traits` if defining them in
|
316
|
+
a method.
|
255
317
|
|
256
|
-
The `accessibility_traits=` method also accepts a symbol or array of symbols,
|
318
|
+
The `accessibility_traits=` method also accepts a symbol or array of symbols,
|
319
|
+
and applies the accessibility_traits method to them. For example, if a view
|
320
|
+
displays an image that opens a link, you can do this.
|
257
321
|
|
258
322
|
```
|
259
323
|
class ImageLinkView < UIView
|
@@ -262,9 +326,7 @@ def accessibility_traits
|
|
262
326
|
super.accessibility_traits|:image.accessibility_trait|:link.accessibility_trait
|
263
327
|
end
|
264
328
|
end
|
265
|
-
|
266
|
-
|
267
|
-
Or, to set it in an instance of a view you can do this.
|
329
|
+
``uur, to set it in an instance of a view you can do this.
|
268
330
|
|
269
331
|
```
|
270
332
|
view=UIView.alloc.init
|
@@ -282,11 +344,14 @@ The view acts like a search field.
|
|
282
344
|
##### :image
|
283
345
|
The view displays an image.
|
284
346
|
##### :selected
|
285
|
-
VoiceOver will report the element as selected. For example, a selected row in a
|
347
|
+
VoiceOver will report the element as selected. For example, a selected row in a
|
348
|
+
table, or segment in a segmented control.
|
286
349
|
##### :keyboard_key
|
287
350
|
The view behaves like a keyboard key.
|
288
351
|
##### :header
|
289
|
-
The view contains a header. VoiceOver will announce this as a heading.
|
352
|
+
The view contains a header. VoiceOver will announce this as a heading.
|
353
|
+
VoiceOver allows for navigation between headings. This gives quick access to
|
354
|
+
different sections.
|
290
355
|
##### :static_text
|
291
356
|
The view displays static text.
|
292
357
|
##### :summary_element
|
@@ -294,13 +359,18 @@ The view provides summary information when the application starts.
|
|
294
359
|
##### :plays_sound
|
295
360
|
The view plays its own sound when activated.
|
296
361
|
#### :starts_media_session
|
297
|
-
Silences VoiceOver during a media session that should not be interrupted. For
|
362
|
+
Silences VoiceOver during a media session that should not be interrupted. For
|
363
|
+
example, silence VoiceOver speech while the user is recording audio.
|
298
364
|
#### :updates_frequently
|
299
|
-
Tells VoiceOver to avoid handling continual notifications. Instead it should
|
365
|
+
Tells VoiceOver to avoid handling continual notifications. Instead it should
|
366
|
+
poll for changes when it needs updated information. You do this with the
|
367
|
+
notifications discussed below.
|
300
368
|
#### :adjustable
|
301
|
-
The view has an adjustable value. Also see the `accessibility_increment` and
|
369
|
+
The view has an adjustable value. Also see the `accessibility_increment` and
|
370
|
+
`accessibility_decrement` methods.
|
302
371
|
#### :allows_direct_interaction
|
303
|
-
This tells VoiceOver to allow the user to interact directly with the view. For
|
372
|
+
This tells VoiceOver to allow the user to interact directly with the view. For
|
373
|
+
example, a piano keyboard.
|
304
374
|
#### :causes_page_turn
|
305
375
|
Causes an automatic page turn when VoiceOver finishes reading the text within it.
|
306
376
|
#### :not_enabled
|
@@ -320,19 +390,44 @@ The frame of the accessibility element. This defaults to the frame of the view.
|
|
320
390
|
|
321
391
|
#### `accessibility_activation_point`
|
322
392
|
|
323
|
-
The point activated when a VoiceOver user activates the view by double tapping
|
393
|
+
The point activated when a VoiceOver user activates the view by double tapping
|
394
|
+
it. This defaults to the center of the view. In other words, a VoiceOver can
|
395
|
+
double-tap anywhere on the screen, but it will simulate a sighted user touching
|
396
|
+
the center of the view.
|
324
397
|
|
325
398
|
#### `accessibility_path`
|
326
399
|
|
327
|
-
If nil, the default, VoiceOver uses the `accessibility_frame` to highlight the
|
400
|
+
If nil, the default, VoiceOver uses the `accessibility_frame` to highlight the
|
401
|
+
element. If set, it will use the path. This method accepts a `UIBezierPath`.
|
328
402
|
|
329
403
|
#### `accessibility_modal_view?` or `accessibility_view_is_modal`
|
330
404
|
|
331
|
-
Ignores elements within views which are siblings of the receiver. If you
|
405
|
+
Ignores elements within views which are siblings of the receiver. If you
|
406
|
+
present a modal view and want VoiceOver to ignore other views on the screen,
|
407
|
+
set this to true.
|
332
408
|
|
333
409
|
#### `group_accessibility_children?` or `should_group_accessibility_children`
|
334
410
|
|
335
|
-
VoiceOver gives two ways to browse the screen. The user can drag their finger
|
411
|
+
VoiceOver gives two ways to browse the screen. The user can drag their finger
|
412
|
+
around the screen and hear the contents. They can also swipe right or left with
|
413
|
+
one finger to hear the next or previous element. When swiping to the next
|
414
|
+
element, VoiceOver reads the elements from left to right, and from top to
|
415
|
+
bottom. Sometimes this can get confusing, depending on the layout of the
|
416
|
+
screen. Setting this to true tells VoiceOver to read the views in the order
|
417
|
+
defined in the subviews array.
|
418
|
+
|
419
|
+
#### `accessibility_elements`
|
420
|
+
|
421
|
+
An array which contains the elements which VoiceOver should access. New in iOS
|
422
|
+
8, this offers a much easier way to create accessibility containers and their
|
423
|
+
elements. Simply pass an array with the views.
|
424
|
+
|
425
|
+
```
|
426
|
+
sample=UIView.new
|
427
|
+
label=UILabel.new
|
428
|
+
button=UIButton.new
|
429
|
+
sample.accessibilitly_elements = [label, button]
|
430
|
+
```
|
336
431
|
|
337
432
|
#### `accessibility_elements_hidden?` or `accessibility_elements_hidden`
|
338
433
|
|
@@ -340,7 +435,66 @@ A boolean value which tells VoiceOver to hide the subviews of this view.
|
|
340
435
|
|
341
436
|
#### `accessibility_element?`, or `is_accessibility_element`
|
342
437
|
|
343
|
-
Tells VoiceOver whether to regard this as something it can read or not.
|
438
|
+
Tells VoiceOver whether to regard this as something it can read or not.
|
439
|
+
Standard views have this set to true. Custom views have this set to false.
|
440
|
+
|
441
|
+
#### `accessibility_custom_actions`
|
442
|
+
|
443
|
+
iOS 8 offers the ability to allow a VoiceOver user to perform custom actions on
|
444
|
+
a view. For example, if you have a view which responds to a non-standard wiping
|
445
|
+
gesture which a VoiceOver user cannot execute, you can implement these actions
|
446
|
+
to allow them to swipe through a list and select one.
|
447
|
+
|
448
|
+
##### Creating a Custom Action
|
449
|
+
|
450
|
+
Custom actions belong to the `A11y::Custom_Action` class. Just call the
|
451
|
+
`initWithName:target:selector` method. It takes the following parameters:
|
452
|
+
- Name: The name of the action read by VoiceOver
|
453
|
+
- Target: The object which receives the message to perform the action, usually
|
454
|
+
`self`.
|
455
|
+
- Selector: A string containing the name of the method to call when selected
|
456
|
+
|
457
|
+
```
|
458
|
+
(main)> action=A11y::Custom_Action.alloc.initWithName("Sample Action", target: self, selector: 'sample_action')
|
459
|
+
=> #<Accessibility::Custom_Action:0xb42e270>
|
460
|
+
```
|
461
|
+
|
462
|
+
##### Using a Hash
|
463
|
+
|
464
|
+
Instead of passing an array of custom actions to
|
465
|
+
`accessibility_custom_actions`, you may provide an array of hashes to create
|
466
|
+
them.
|
467
|
+
|
468
|
+
```
|
469
|
+
(main)> test_view=UIView.new
|
470
|
+
=> #<UIView:0xb435030>
|
471
|
+
(main)> test_view.accessibility_custom_actions = [{name: 'Test', target: self, selector: 'test_action'}, {name: 'Another test', target: self, selector: 'another_test_action'}]
|
472
|
+
=> [#<Accessibility::Custom_Action:0x10c78d90>, #<Accessibility::Custom_Action:0x10c68f10>]
|
473
|
+
```
|
474
|
+
|
475
|
+
You can then see them in the inspector.
|
476
|
+
|
477
|
+
```
|
478
|
+
(main)> A11y.inspect test_view
|
479
|
+
#<UIView:0xb435030>
|
480
|
+
Accessibility label: nil
|
481
|
+
Accessibility hint: nil
|
482
|
+
Accessibility traits: None
|
483
|
+
Accessibility value: nil
|
484
|
+
Accessibility language: nil
|
485
|
+
Accessibility frame: x=0.0 y=0.0 width=0.0 height=0.0
|
486
|
+
Accessibility activation point: x=0.0 y=0.0
|
487
|
+
Accessibility path: nil
|
488
|
+
Accessibility view is modal: false
|
489
|
+
Should group accessibility children: false
|
490
|
+
Accessibility elements: nil
|
491
|
+
Accessibility elements hidden: false
|
492
|
+
Is accessibility element: false
|
493
|
+
Accessibility custom actions: ["Test", "Another test"]
|
494
|
+
Accessibility identifier: nil
|
495
|
+
Accessible: true
|
496
|
+
=> nil
|
497
|
+
```
|
344
498
|
|
345
499
|
#### `accessibility_identifier`
|
346
500
|
|
@@ -348,7 +502,8 @@ A unique identifier if you don't want to define the accessibility label.
|
|
348
502
|
|
349
503
|
### UIPickerView
|
350
504
|
|
351
|
-
If desired, you can use these methods to make your picker views more
|
505
|
+
If desired, you can use these methods to make your picker views more
|
506
|
+
accessible. You only need to do this if the picker contains non-standard views.
|
352
507
|
#### `accessibility_label_for_component`
|
353
508
|
Accepts an integer and returns the accessibility label for the component.
|
354
509
|
#### `accessibility_hint_for_component `
|
@@ -356,23 +511,33 @@ Accepts an integer and returns the accessibility hint for the component.
|
|
356
511
|
|
357
512
|
### UIAccessibility Actions
|
358
513
|
|
359
|
-
These methods trigger when the VoiceOver user performs specific actions. You
|
514
|
+
These methods trigger when the VoiceOver user performs specific actions. You
|
515
|
+
can implement then in a UIView or an accessibility element.
|
360
516
|
|
361
517
|
#### `accessibility_activate`
|
362
518
|
|
363
|
-
New in iOS 7, this method performs a custom action when a VoiceOver double-taps
|
519
|
+
New in iOS 7, this method performs a custom action when a VoiceOver double-taps
|
520
|
+
the view. You can use this if the view uses a custom gesture, for example. It
|
521
|
+
returns true or false depending on the success of the action.
|
364
522
|
|
365
523
|
#### `accessibility_perform_escape`
|
366
524
|
|
367
|
-
VoiceOver has a special two-finger scrub gesture designed to act as a back
|
525
|
+
VoiceOver has a special two-finger scrub gesture designed to act as a back
|
526
|
+
button. The standard back button of a UINavigationController implements this
|
527
|
+
method. It dismisses a modal view, and returns the success or failure of the
|
528
|
+
action. For example, you could use this to dismiss a popover.
|
368
529
|
|
369
530
|
#### `Accessibility_perform_magic_tap`
|
370
531
|
|
371
|
-
VoiceOver has a special two-finger double-tap. This method should toggle the
|
532
|
+
VoiceOver has a special two-finger double-tap. This method should toggle the
|
533
|
+
most important state of the program. For example, if a song plays it will pause
|
534
|
+
and resume the song. If on a telephone call, doing a magic tap will end it.
|
372
535
|
|
373
536
|
#### `accessibility_scroll`
|
374
537
|
|
375
|
-
VoiceOver uses three-finger swipes to scroll the screen. These gestures will
|
538
|
+
VoiceOver uses three-finger swipes to scroll the screen. These gestures will
|
539
|
+
trigger this method. It accepts a scroll direction as a parameter. If the
|
540
|
+
scrolling succeeds, it should return true and post a :scroll notification.
|
376
541
|
|
377
542
|
#### Scroll Directions
|
378
543
|
|
@@ -387,7 +552,8 @@ VoiceOver uses three-finger swipes to scroll the screen. These gestures will tri
|
|
387
552
|
|
388
553
|
#### `accessibility_increment`
|
389
554
|
|
390
|
-
Increments the value of the accessibility element. Make sure to have the
|
555
|
+
Increments the value of the accessibility element. Make sure to have the
|
556
|
+
:adjustable accessibility trait set for this to work.
|
391
557
|
|
392
558
|
#### `accessibility_decrement`
|
393
559
|
|
@@ -395,7 +561,13 @@ Decrements the value of the accessibility element. Make sure to have the :adjust
|
|
395
561
|
|
396
562
|
### Accessibility::Element
|
397
563
|
|
398
|
-
If you have something in your view that does not inherit from UIView or
|
564
|
+
If you have something in your view that does not inherit from UIView or
|
565
|
+
UIControl and you want to make it accessible, you need to define it as an
|
566
|
+
accessibility element. Accessibility elements belong to an accessibility
|
567
|
+
container, in other words the view which contains them. To create one, just
|
568
|
+
call `Accessibility::Element.init_with_accessibility_container` with the
|
569
|
+
container, usually self. Like a UIView, an accessibility element has
|
570
|
+
attributes, and you get and set them in exactly the same way.
|
399
571
|
|
400
572
|
```
|
401
573
|
class CustomView < UIView
|
@@ -439,22 +611,31 @@ The value of the element, if applicable.
|
|
439
611
|
|
440
612
|
#### `is_accessibility_element` or `accessibility_element?`
|
441
613
|
|
442
|
-
Returns true if VoiceOver should consider this an accessibility element. Note
|
614
|
+
Returns true if VoiceOver should consider this an accessibility element. Note
|
615
|
+
that you can only use `is_accessibility_element?=` as a setter.
|
443
616
|
|
444
617
|
### UIAccessibilityContainer Informal Protocol
|
445
618
|
|
446
|
-
The UIAccessibility Container informal protocol allows VoiceOver to handle a
|
619
|
+
The UIAccessibility Container informal protocol allows VoiceOver to handle a
|
620
|
+
custom view which acts like a container. It tells VoiceOver how to read the
|
621
|
+
subviews in the proper order. It contains accessibility elements. Just
|
622
|
+
implement these methods in a subclass of UIView.
|
447
623
|
|
448
624
|
#### `accessibility_element_at_index`
|
449
625
|
Accepts an integer and returns the accessibility element. You can use the standard `Array#[]` method for this.
|
450
626
|
#### `accessibility_element_count`
|
451
627
|
Returns the number of accessible elements. You can use `Array#length` for this.
|
452
628
|
#### `index_of_accessibility_element`
|
453
|
-
Accepts an accessibility element and returns its index as an integer. You can
|
629
|
+
Accepts an accessibility element and returns its index as an integer. You can
|
630
|
+
use the `Array#index` method for this.
|
631
|
+
#### `accessibility_element_container?`
|
632
|
+
Returns true if the object behaves like a container.
|
454
633
|
|
455
634
|
### UIAccessibilityFocus Informal Protocol
|
456
635
|
|
457
|
-
This protocol lets you take actions if a view gains or loses VoiceOver's focus.
|
636
|
+
This protocol lets you take actions if a view gains or loses VoiceOver's focus.
|
637
|
+
Note that if you use these in an Accessibility::Element that you can leave off
|
638
|
+
the `accessibility_element_` prefix.
|
458
639
|
#### `accessibility_element_did_become_focused`
|
459
640
|
Triggered when the accessibility element becomes focused by VoiceOver.
|
460
641
|
#### `accessibility_element_did_lose_focus`
|
@@ -475,7 +656,12 @@ Accepts a CGPoint and returns the line number of the text to read.
|
|
475
656
|
|
476
657
|
### Notifications
|
477
658
|
|
478
|
-
The UIAccessibility notifications can either come from UIKit or from
|
659
|
+
The UIAccessibility notifications can either come from UIKit or from
|
660
|
+
applications. You can observe them with the standard notification center. You
|
661
|
+
can post them with `Accessibility.post_notification`. It takes one of the
|
662
|
+
following symbols as a parameter. Many notifications have additional parameters
|
663
|
+
as well. Motion-Accessibility adds an accessibility_notification method to the
|
664
|
+
Symbol class.
|
479
665
|
|
480
666
|
For example, if a view controller removes a subview and adds another, you will want to post the screen changed notification. You can do this with
|
481
667
|
|
@@ -486,15 +672,23 @@ Accessibility.post_notification(:screen_changed)
|
|
486
672
|
Much easier, don't you think?
|
487
673
|
|
488
674
|
#### :layout_changed
|
489
|
-
Your application should post this notification when a part of the screen's
|
675
|
+
Your application should post this notification when a part of the screen's
|
676
|
+
layout changes. It has one parameter. You can provide a string which VoiceOver
|
677
|
+
should speak. You can also provide an accessibility element, such as a UIView,
|
678
|
+
and VoiceOver will move there.
|
490
679
|
#### :screen_changed
|
491
|
-
Your application should post this notification when a major part of the screen
|
680
|
+
Your application should post this notification when a major part of the screen
|
681
|
+
changes. It has the same parameter as `:layout_changed`.
|
492
682
|
#### :page_scrolled
|
493
|
-
Post this notification after calling `Accessibility.scroll`. Include a string
|
683
|
+
Post this notification after calling `Accessibility.scroll`. Include a string
|
684
|
+
which describes the scrolling action, for example "Page 3 of 10".
|
494
685
|
#### :announcement
|
495
|
-
Post this notification to make VoiceOver output something. Just include the
|
686
|
+
Post this notification to make VoiceOver output something. Just include the
|
687
|
+
string.
|
496
688
|
#### :announcement_did_finish
|
497
|
-
UIKit posts this announcement when VoiceOver finishes announcing something. It
|
689
|
+
UIKit posts this announcement when VoiceOver finishes announcing something. It
|
690
|
+
accepts a dictionary with the following keys as a parameter. Use the zoom_type
|
691
|
+
method on these symbols.
|
498
692
|
- :announcement_key_string_value
|
499
693
|
- :announcement_key_was_successful
|
500
694
|
#### :closed_captioning
|
@@ -507,26 +701,65 @@ UIKit posts this when the user toggles inverted colors.
|
|
507
701
|
UIKit posts this when the user toggles mono audio.
|
508
702
|
#### :voiceover
|
509
703
|
UIKit posts this when the user toggles VoiceOver.
|
704
|
+
#### :bold_text
|
705
|
+
UIKit posts this when the user toggles the Bold Text accessibility setting.
|
706
|
+
#### :darker_colors
|
707
|
+
UIKit posts this when the user toggles the Darker Colors accessibility setting.
|
708
|
+
#### :grayscale
|
709
|
+
Posted when the user toggles the Grayscale accessibility setting
|
710
|
+
#### :reduce_motion
|
711
|
+
Posted when the user toggles the Reduce Motion accessibility seting. This can
|
712
|
+
help users who feel dizzy by all the fancy animations.
|
713
|
+
#### :reduce_transparency
|
714
|
+
Posted when the user toggles the Reduce Transparency accessibility setting.
|
715
|
+
#### :speak_selection
|
716
|
+
Posted when the user toggles the Speak Selection setting located in Accessibility -> Speech
|
717
|
+
#### :speak_screen
|
718
|
+
Posted when the user toggles the Speak Screen setting located under Accessibility -> Speech
|
719
|
+
#### :switch_control
|
720
|
+
Posted when the user toggles use of a switch control
|
721
|
+
#### :switch_control_identifier
|
722
|
+
Contains the unique identifier of the switch control
|
723
|
+
#### :resume_assistive_technology
|
724
|
+
Post this notification to resume VoiceOver or other assistive technology
|
725
|
+
|
726
|
+
#### :pause_assistive_technology
|
727
|
+
Post this notification to pause VoiceOver or other assistive technology
|
510
728
|
|
511
729
|
### Determining the Status of Accessibility Components
|
512
|
-
You can use these handy methods to determine the status of different
|
730
|
+
You can use these handy methods to determine the status of different
|
731
|
+
accessibility components. They take no parameters and return true or false.
|
513
732
|
|
514
733
|
- `Accessibility.voiceover_running?`
|
515
734
|
- `Accessibility.closed_captioning_enabled?`
|
516
735
|
- `Accessibility.guided_access_enabled?`
|
517
736
|
- `Accessibility.invert_colors_enabled?`
|
518
737
|
- `Accessibility.mono_audio_enabled?`
|
738
|
+
- `Accessibility.darker_system_colors_enabled?`
|
739
|
+
- `Accessibility.bold_text_enabled?`
|
740
|
+
- `Accessibility.grayscale_enabled?`
|
741
|
+
- `Accessibility.reduce_motion_enabled?`
|
742
|
+
- `Accessibility.reduce_transparency_enabled?`
|
743
|
+
|
744
|
+
- `Accessibility.speak_selection_enabled?`
|
745
|
+
- `Accessibility.speak_screen_enabled?`
|
746
|
+
- `Accessibility.switch_control_running?`
|
747
|
+
|
519
748
|
|
520
|
-
Additionally, these two methods relate to the Zoom screen magnification
|
749
|
+
Additionally, these two methods relate to the Zoom screen magnification
|
750
|
+
software.
|
521
751
|
|
522
752
|
#### `Accessibility.zoom_focused_changed`
|
523
|
-
This notifies Zoom that an app's focus has changed. It takes a zoom type
|
753
|
+
This notifies Zoom that an app's focus has changed. It takes a zoom type
|
754
|
+
described above, a frame, and the view containing the frame.
|
524
755
|
#### `Accessibility.register_gesture_conflicts_with_zoom`
|
525
|
-
This issues a dialog to the user when a three-fingered gesture conflicts with
|
756
|
+
This issues a dialog to the user when a three-fingered gesture conflicts with
|
757
|
+
Zoom. It lets them choose to disable Zoom or continue.
|
526
758
|
|
527
759
|
### Speech Attributes
|
528
760
|
|
529
|
-
iOS 7 adds some speech attributes to use in attributed strings. To get them,
|
761
|
+
iOS 7 adds some speech attributes to use in attributed strings. To get them,
|
762
|
+
just call the `speech_attribute` method on the following symbols.
|
530
763
|
- `:punctuation`
|
531
764
|
- `:language`
|
532
765
|
- `:pitch`
|
@@ -542,4 +775,4 @@ iOS 7 adds some speech attributes to use in attributed strings. To get them, jus
|
|
542
775
|
|
543
776
|
## A Special Offer for You
|
544
777
|
|
545
|
-
I do [freelance accessibility consulting.](austinseraphin.com) If you use my gem I will give you a discount. Contact me for more information.
|
778
|
+
I do [freelance accessibility consulting.](austinseraphin.com) If you use my gem I will give you a discount. Contact me for more information.
|
data/lib/project/constants.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Accessibility
|
2
2
|
|
3
3
|
Data={}
|
4
4
|
|
@@ -25,6 +25,8 @@ Attributes = {
|
|
25
25
|
:should_group_accessibility_children => :shouldGroupAccessibilityChildren,
|
26
26
|
:group_accessibility_children? => :shouldGroupAccessibilityChildren,
|
27
27
|
:should_group_accessibility_children= => :setShouldGroupAccessibilityChildren,
|
28
|
+
:accessibility_elements => :accessibilityElements,
|
29
|
+
:accessibility_elements= => :setAccessibilityElements,
|
28
30
|
:accessibility_elements_hidden => :accessibilityElementsHidden,
|
29
31
|
:accessibility_elements_hidden? => :accessibilityElementsHidden,
|
30
32
|
:accessibility_elements_hidden= => :setAccessibilityElementsHidden,
|
@@ -35,6 +37,8 @@ Attributes = {
|
|
35
37
|
:accessibility_element? => :isAccessibilityElement,
|
36
38
|
:is_accessibility_element => :isAccessibilityElement,
|
37
39
|
:is_accessibility_element= => :setIsAccessibilityElement,
|
40
|
+
:accessibility_custom_actions => :accessibilityCustomActions,
|
41
|
+
:accessibility_custom_actions= => :setAccessibilityCustomActions,
|
38
42
|
:accessibility_identifier => :accessibilityIdentifier,
|
39
43
|
:accessibility_identifier= => :setAccessibilityIdentifier
|
40
44
|
}
|
@@ -131,6 +135,23 @@ Notifications = {
|
|
131
135
|
:voiceover => UIAccessibilityVoiceOverStatusChanged
|
132
136
|
}
|
133
137
|
|
138
|
+
if UIDevice.currentDevice.systemVersion.to_f>=8.0
|
139
|
+
IOS8_Notifications = {
|
140
|
+
:bold_text => UIAccessibilityBoldTextStatusDidChangeNotification,
|
141
|
+
:darker_colors => UIAccessibilityDarkerSystemColorsStatusDidChangeNotification,
|
142
|
+
:grayscale => UIAccessibilityGrayscaleStatusDidChangeNotification,
|
143
|
+
:reduce_motion => UIAccessibilityReduceMotionStatusDidChangeNotification,
|
144
|
+
:reduce_transparency => UIAccessibilityReduceTransparencyStatusDidChangeNotification,
|
145
|
+
:speak_screen => UIAccessibilitySpeakScreenStatusDidChangeNotification,
|
146
|
+
:speak_selection => UIAccessibilitySpeakSelectionStatusDidChangeNotification,
|
147
|
+
:switch_control => UIAccessibilitySwitchControlStatusDidChangeNotification,
|
148
|
+
:switch_control_identifier => UIAccessibilityNotificationSwitchControlIdentifier,
|
149
|
+
:pause_assistive_technology => UIAccessibilityPauseAssistiveTechnologyNotification,
|
150
|
+
:resume_assistive_technology => UIAccessibilityResumeAssistiveTechnologyNotification
|
151
|
+
}
|
152
|
+
IOS8_Notifications.each {|ruby,ios| Notifications[ruby]=ios}
|
153
|
+
end
|
154
|
+
|
134
155
|
def Accessibility.post_notification(notification, *args)
|
135
156
|
if(notification.kind_of?(Fixnum))
|
136
157
|
UIAccessibilityPostNotification(notification, *args)
|
@@ -169,7 +190,9 @@ Attribute_Types = {
|
|
169
190
|
:accessibilityViewIsModal=>:boolean,
|
170
191
|
:shouldGroupAccessibilityChildren=>:boolean,
|
171
192
|
:accessibilityElementsHidden=>:boolean,
|
172
|
-
:isAccessibilityElement=>:boolean
|
193
|
+
:isAccessibilityElement=>:boolean,
|
194
|
+
:accessibilityElements => :accessibility_elements,
|
195
|
+
:accessibilityCustomActions => :accessibility_custom_actions
|
173
196
|
}
|
174
197
|
|
175
198
|
Default_Type_Values = {
|
@@ -177,7 +200,9 @@ Default_Type_Values = {
|
|
177
200
|
:boolean => true,
|
178
201
|
:fixnum => 23,
|
179
202
|
:cgrect=>CGRectMake(0,0,100,100),
|
180
|
-
:cgpoint=>CGPointMake(100,100)
|
203
|
+
:cgpoint=>CGPointMake(100,100),
|
204
|
+
:accessibility_elements => [UIView.new],
|
205
|
+
:accessibility_custom_actions => [UIAccessibilityCustomAction.alloc.initWithName("Test", target: self, selector: 'test')]
|
181
206
|
}
|
182
207
|
|
183
208
|
def self.attribute_type(attribute)
|
@@ -253,4 +278,5 @@ end
|
|
253
278
|
|
254
279
|
end
|
255
280
|
|
256
|
-
A11y=Accessibility unless defined?
|
281
|
+
A11y=Accessibility unless defined? A11y
|
282
|
+
A11y::Custom_Action = UIAccessibilityCustomAction unless defined? A11y::Custom_Action
|
data/lib/project/element.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
class UIAccessibilityElement
|
2
2
|
|
3
|
-
def
|
3
|
+
def init_with_accessibility_container(container)
|
4
4
|
UIAccessibilityElement.alloc.initWithAccessibilityContainer(container)
|
5
5
|
end
|
6
6
|
|
7
|
+
def inspect
|
8
|
+
self.accessibility_label
|
9
|
+
end
|
10
|
+
|
7
11
|
Accessibility::Element_Attributes.each do |ruby,ios|
|
8
12
|
if ruby=~/=$/
|
9
13
|
define_method(ruby) {|value| self.send(ios,value)}
|
@@ -24,12 +28,12 @@ def traits=(traits)
|
|
24
28
|
end
|
25
29
|
|
26
30
|
if self.respond_to?(:method_added)
|
27
|
-
alias :
|
31
|
+
alias :method_added_accessibility_element :method_added
|
28
32
|
end
|
29
33
|
|
30
34
|
def self.method_added(name)
|
31
35
|
if self.respond_to?(:method_added_accessibility)
|
32
|
-
|
36
|
+
method_added_accessibility_element(name)
|
33
37
|
end
|
34
38
|
return if name=~/=$/
|
35
39
|
attributes=Accessibility::Element_Attributes
|
@@ -48,18 +52,18 @@ define_method(ruby) { self.send(ios)}
|
|
48
52
|
end
|
49
53
|
end
|
50
54
|
|
51
|
-
def self.container?(obj)
|
52
|
-
!obj.accessibility_element_at_index(0).nil?
|
53
|
-
end
|
54
|
-
|
55
55
|
end
|
56
56
|
|
57
|
-
Accessibility::Element=UIAccessibilityElement
|
57
|
+
Accessibility::Element=UIAccessibilityElement unless defined? Accessibility::Element
|
58
58
|
|
59
59
|
class NSObject
|
60
60
|
|
61
|
+
def accessibility_element_container?
|
62
|
+
self.accessibility_element_at_index(0)?true:false
|
63
|
+
end
|
64
|
+
|
61
65
|
def each_accessibility_element
|
62
|
-
return unless
|
66
|
+
return unless self.accessibility_element_container?
|
63
67
|
self.accessibility_element_count.times {|n| yield(self.accessibility_element_at_index(n))}
|
64
68
|
end
|
65
69
|
|
data/lib/project/inspector.rb
CHANGED
@@ -18,7 +18,7 @@ self.inspect_accessibility_attribute(obj,ios)
|
|
18
18
|
displayed<<ios
|
19
19
|
end
|
20
20
|
puts "Accessibility test: #{obj.accessibility_test}" if obj.accessibility_test
|
21
|
-
puts "Accessibility container: #{obj.accessibility_element_count} elements" if
|
21
|
+
puts "Accessibility container: #{obj.accessibility_element_count} elements" if obj.accessibility_element_container?
|
22
22
|
puts "Accessible: #{obj.accessible?}"
|
23
23
|
A11y.doctor
|
24
24
|
end
|
@@ -40,6 +40,8 @@ value=false if value==0||value.nil?
|
|
40
40
|
when :cgrect then value="x=#{value.origin.x.round(1)} y=#{value.origin.y.round(1)} width=#{value.size.width.round(1)} height=#{value.size.height.round(1)}"
|
41
41
|
when :cgpoint then value="x=#{value.x.round(1)} y=#{value.y.round(1)}"
|
42
42
|
when :uibezierpath then value="x=#{value.bounds.origin.x.round(1)} y=#{value.bounds.origin.y.round(1)} width=#{value.bounds.size.width.round(1)} height=#{value.bounds.size.height.round(1)}"
|
43
|
+
when :accessibility_elements then value=value.map {|v| v.accessibility_label}
|
44
|
+
when :accessibility_custom_actions then value=value.map {|a| a.name}
|
43
45
|
end
|
44
46
|
else
|
45
47
|
value="nil" if value.nil?
|
@@ -2,6 +2,7 @@ module Accessibility
|
|
2
2
|
module Console
|
3
3
|
|
4
4
|
$browser_path=[]
|
5
|
+
$browser_last=nil
|
5
6
|
Update_Delay=1.0
|
6
7
|
|
7
8
|
def self.touchable_type(view)
|
@@ -9,6 +10,9 @@ control=view.class
|
|
9
10
|
until A11y::Touchable_Types.member?(control.to_s)||control.nil?
|
10
11
|
control=control.superclass
|
11
12
|
end
|
13
|
+
if control.class==UITableViewCell
|
14
|
+
control=nil unless controll.respond_to?("tableView:didSelectRowAtIndexPath")
|
15
|
+
end
|
12
16
|
control
|
13
17
|
end
|
14
18
|
|
@@ -78,6 +82,7 @@ end
|
|
78
82
|
A11y::Console.init unless A11y::Data[:refresh]
|
79
83
|
$browser_current=found
|
80
84
|
$browser_path<<found
|
85
|
+
$browser_last=request
|
81
86
|
end
|
82
87
|
elsif request.respond_to?(:view)&&request.respond_to?(:subviews)
|
83
88
|
A11y::Console.init(request)
|
@@ -105,11 +110,20 @@ def view(request=nil)
|
|
105
110
|
A11y::Console.init unless A11y::Data[:refresh]
|
106
111
|
$browser_current=$browser_tree unless $browser_current
|
107
112
|
$browser_cursor=$browser_tree unless $browser_cursor
|
108
|
-
|
113
|
+
result=nil
|
114
|
+
if request
|
109
115
|
result=$browser_current.find(request)
|
110
116
|
raise "Unknown view" unless result
|
111
117
|
$browser_cursor=result
|
112
|
-
result.view
|
118
|
+
result=result.view
|
119
|
+
else
|
120
|
+
result=$browser_cursor.view
|
121
|
+
result
|
122
|
+
end
|
123
|
+
if result.class==UITableViewCellAccessibilityElement
|
124
|
+
result=result.tableViewCell
|
125
|
+
end
|
126
|
+
result
|
113
127
|
end
|
114
128
|
|
115
129
|
module_function :browse, :view
|
@@ -1,13 +1,16 @@
|
|
1
1
|
module Accessibility
|
2
2
|
module Console
|
3
3
|
|
4
|
-
def self.touch(
|
4
|
+
def self.touch(request, arg=nil, options={})
|
5
5
|
self.start_refreshing
|
6
6
|
$browser_current=$browser_tree unless $browser_current
|
7
|
+
view=nil
|
7
8
|
unless RUBYMOTION_ENV=='test'
|
8
|
-
found=$browser_current.find(
|
9
|
+
found=$browser_current.find(request)
|
9
10
|
raise "Could not find the view" unless found
|
10
11
|
view=found.view
|
12
|
+
else
|
13
|
+
view=request
|
11
14
|
end
|
12
15
|
control=A11y::Console.touchable_type(view)
|
13
16
|
raise "I don't know how to touch a #{view.class}" if control.nil?
|
@@ -39,14 +42,29 @@ when "UISwitch"
|
|
39
42
|
arg||=!view.arg
|
40
43
|
view.on=arg
|
41
44
|
when "UITableViewCell"
|
45
|
+
raise "You cannot touch cells in this table." unless sv.delegate.respond_to?("tableView:didSelectRowAtIndexPath")
|
42
46
|
raise "Could not get the UITableView" unless sv.kind_of?(UITableView)
|
43
|
-
|
47
|
+
if sv.respond_to?(:numberOfSections)
|
48
|
+
sections=sv.numberOfSections
|
49
|
+
else
|
50
|
+
sections=1
|
51
|
+
end
|
52
|
+
if sections>1
|
53
|
+
index=options[:index]||NSIndexPath.indexPathForRow(request-1, inSection: $browser_last-1)
|
54
|
+
else
|
55
|
+
index=options[:index]||NSIndexPath.indexPathForRow(request-1, inSection: 0)
|
56
|
+
end
|
44
57
|
raise "Could not get the index" unless index
|
45
|
-
sv.delegate.tableView(
|
58
|
+
sv.delegate.tableView(sv.delegate, didSelectRowAtIndexPath: index)
|
46
59
|
when "UITableViewCellAccessibilityElement"
|
47
|
-
raise "
|
48
|
-
|
60
|
+
raise "You cannot touch cells in this table." unless view.container.delegate.respond_to?("tableView:didSelectRowAtIndexPath")
|
61
|
+
if options[:index]
|
62
|
+
index=options[:index]
|
63
|
+
else
|
64
|
+
raise "Invalid number" if request>view.container.delegate.accessibility_element_count
|
65
|
+
index=view.container.indexPathForCell(view.tableViewCell)
|
49
66
|
raise "Could not get the index" unless index
|
67
|
+
end
|
50
68
|
view.container.delegate.tableView(view.container, didSelectRowAtIndexPath: index)
|
51
69
|
when "UINavigationItemButtonView"
|
52
70
|
view.superview.delegate.popViewControllerAnimated(true)
|
@@ -18,14 +18,29 @@ self.subviews.each {|subview| other.subviews<<subview.clone}
|
|
18
18
|
other
|
19
19
|
end
|
20
20
|
|
21
|
+
def self.container_equals(v1, v2, depth=0)
|
22
|
+
return false unless v1==v2
|
23
|
+
return false unless v1.accessibility_element_count==v2.accessibility_element_count
|
24
|
+
if v1.accessibility_element_container?
|
25
|
+
v1.accessibility_element_count.times do |element_index|
|
26
|
+
return false unless self.container_equals(v1.accessibility_element_at_index(element_index), v2.accessibility_element_at_index(element_index), depth+1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
21
32
|
def ==(other)
|
22
33
|
return false if other.nil?
|
23
34
|
return false if self.superview&&other.superview&&self.superview.view!=other.superview.view
|
35
|
+
if self.view.accessibility_element_container?
|
36
|
+
A11y::Console::Tree.container_equals(self.view, other.view)
|
37
|
+
else
|
24
38
|
return false unless self.view==other.view
|
25
39
|
return false unless self.subviews.size==other.subviews.size
|
26
40
|
self.subviews.each_index {|index| return false unless self.subviews[index]==other.subviews[index]}
|
27
41
|
return true
|
28
42
|
end
|
43
|
+
end
|
29
44
|
|
30
45
|
def [](n)
|
31
46
|
a=[@view]
|
@@ -64,6 +79,8 @@ if @view.class==UITableViewCell
|
|
64
79
|
name=view.text
|
65
80
|
elsif @view.class==UITableViewCellAccessibilityElement
|
66
81
|
name=view.tableViewCell.text
|
82
|
+
elsif view.respond_to?(:text)
|
83
|
+
name=view.text
|
67
84
|
elsif @view.class==UITextField
|
68
85
|
name=@view.text
|
69
86
|
else
|
@@ -108,7 +125,20 @@ A11y::Test::Data[:quiet]=true
|
|
108
125
|
tree=self.new
|
109
126
|
view=UIApplication.sharedApplication.keyWindow if view.nil?
|
110
127
|
subviews=[]
|
111
|
-
if
|
128
|
+
if view.respond_to?(:numberOfSections)
|
129
|
+
view.numberOfSections.times do |section_number|
|
130
|
+
section=self.new(view: view, superview: tree)
|
131
|
+
view.numberOfRowsInSection(section_number).times do |row_number|
|
132
|
+
index_path=NSIndexPath.indexPathForRow(row_number, inSection: section_number)
|
133
|
+
cell=view.delegate.tableView(view, cellForRowAtIndexPath: index_path)
|
134
|
+
raise "Could not get the cell" unless cell
|
135
|
+
cell_node=self.build(cell, section)
|
136
|
+
section.subviews<<cell_node
|
137
|
+
end
|
138
|
+
subviews<<section
|
139
|
+
end
|
140
|
+
subviews=subviews.first.subviews if subviews.size==1
|
141
|
+
elsif view.accessibility_element_container?
|
112
142
|
view.each_accessibility_element do |element|
|
113
143
|
subview_tree=self.build(element, tree)
|
114
144
|
subviews<<subview_tree
|
data/lib/project/object.rb
CHANGED
@@ -50,6 +50,22 @@ self.accessibilityTraits=bits
|
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
53
|
+
def accessibility_custom_actions=(actions)
|
54
|
+
raise "You must pass an array to custom_accessibility_actions=" unless actions.kind_of?(Array)
|
55
|
+
actions.map! do |action|
|
56
|
+
if action.kind_of?(A11y::Custom_Action)
|
57
|
+
action
|
58
|
+
elsif action.kind_of?(Hash)
|
59
|
+
%w[name target selector].each {|key| raise "You must provide the #{key}" unless action[key.to_sym]}
|
60
|
+
UIAccessibilityCustomAction.alloc.initWithName(action[:name], target: action[:target], selector: action[:selector])
|
61
|
+
else
|
62
|
+
raise "Unknown custom accessibility action #{action.inspect}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
self.accessibilityCustomActions=actions
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
53
69
|
if self.respond_to?(:method_added)
|
54
70
|
class << self
|
55
71
|
alias :method_added_motion_accessibility :method_added
|
data/lib/project/status.rb
CHANGED
@@ -26,5 +26,32 @@ def registered_gesture_conflict_with_zoom
|
|
26
26
|
UIAccessibilityRegisterGestureConflictWithZoom()
|
27
27
|
end
|
28
28
|
|
29
|
+
if UIDevice.currentDevice.systemVersion.to_f>=8.0
|
30
|
+
def darker_system_colors_enabled?
|
31
|
+
UIAccessibilityDarkerSystemColorsEnabled()
|
32
|
+
end
|
33
|
+
def bold_text_enabled?
|
34
|
+
UIAccessibilityIsBoldTextEnabled()
|
35
|
+
end
|
36
|
+
def grayscale_enabled?
|
37
|
+
UIAccessibilityIsGrayscaleEnabled()
|
38
|
+
end
|
39
|
+
def reduce_motion_enabled?
|
40
|
+
UIAccessibilityIsReduceMotionEnabled()
|
41
|
+
end
|
42
|
+
def reduce_transparency_enabled?
|
43
|
+
UIAccessibilityIsReduceTransparencyEnabled()
|
44
|
+
end
|
45
|
+
def speak_screen_enabled?
|
46
|
+
UIAccessibilityIsSpeakScreenEnabled()
|
47
|
+
end
|
48
|
+
def speak_selection_enabled?
|
49
|
+
UIAccessibilityIsSpeakSelectionEnabled()
|
50
|
+
end
|
51
|
+
def switch_control_running?
|
52
|
+
UIAccessibilityIsSwitchControlRunning()
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
29
56
|
end
|
30
57
|
end
|
data/lib/project/test.rb
CHANGED
@@ -8,6 +8,13 @@ quiet: false,
|
|
8
8
|
debug: false
|
9
9
|
}
|
10
10
|
|
11
|
+
def self.quiet
|
12
|
+
Data[:quiet]
|
13
|
+
end
|
14
|
+
def self.quiet=(q)
|
15
|
+
Data[:quiet]=q
|
16
|
+
end
|
17
|
+
|
11
18
|
Options = {
|
12
19
|
recurse: true
|
13
20
|
}
|
@@ -256,6 +263,48 @@ quiet: false,
|
|
256
263
|
}
|
257
264
|
}
|
258
265
|
|
266
|
+
if UIDevice.currentDevice.systemVersion.to_f>=8.0
|
267
|
+
Tests[:UIActionSheet] = {
|
268
|
+
accessibility_label: nil,
|
269
|
+
is_accessibility_element: false,
|
270
|
+
accessibility_view_is_modal: false
|
271
|
+
}
|
272
|
+
Tests[:UINavigationTransitionView] = {
|
273
|
+
accessibility_label: nil,
|
274
|
+
should_group_accessibility_children: :ignore,
|
275
|
+
is_accessibility_element: false
|
276
|
+
}
|
277
|
+
Tests[:UIPageControl] = {
|
278
|
+
accessibility_label: nil,
|
279
|
+
is_accessibility_element: false,
|
280
|
+
accessibility_value: [String, "You must set the accessibility_value to something meaningful, for example 'Page 1 of 1'"],
|
281
|
+
accessibility_traits: UIAccessibilityTraitUpdatesFrequently|UIAccessibilityTraitAdjustable
|
282
|
+
}
|
283
|
+
Tests[:UISlider] = {
|
284
|
+
accessibility_label: nil,
|
285
|
+
accessibility_value: String,
|
286
|
+
accessibility_traits: UIAccessibilityTraitAdjustable,
|
287
|
+
is_accessibility_element: false,
|
288
|
+
options: {recurse: false}
|
289
|
+
}
|
290
|
+
Tests[:UITableView] = {
|
291
|
+
accessibility_label: nil,
|
292
|
+
accessibility_traits: ->(t){A11y::Test.nonstandard(t)},
|
293
|
+
should_group_accessibility_children: true,
|
294
|
+
is_accessibility_element: false
|
295
|
+
}
|
296
|
+
Tests[:UITableViewCell] = {
|
297
|
+
accessibility_label: :ignore,
|
298
|
+
accessibility_value: :ignore,
|
299
|
+
should_group_accessibility_children: true,
|
300
|
+
is_accessibility_element: false,
|
301
|
+
options: {
|
302
|
+
recurse: false,
|
303
|
+
test: :tableViewCell
|
304
|
+
}
|
305
|
+
}
|
306
|
+
end
|
307
|
+
|
259
308
|
def self.debug
|
260
309
|
Data[:debug]
|
261
310
|
end
|
@@ -411,7 +460,7 @@ after=tests[:options][:test]
|
|
411
460
|
result=result&&this_result
|
412
461
|
Data[:depth]=Data[:depth]-1
|
413
462
|
end
|
414
|
-
if result&&
|
463
|
+
if result&&obj.accessibility_element_container?
|
415
464
|
result=result&&self.container(obj)
|
416
465
|
end
|
417
466
|
if result&&tests[:options][:recurse]&&obj.respond_to?(:subviews)&&obj.subviews
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-accessibility
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: '3.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Austin Seraphin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|