motion-accessibility 3.0.3 → 3.1
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.
- 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
|