forked from codelearncreate/c2lc-coding-environment
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCharacterAriaLive.js
More file actions
152 lines (135 loc) · 5.54 KB
/
CharacterAriaLive.js
File metadata and controls
152 lines (135 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// @flow
import React from 'react';
import CharacterDescriptionBuilder from './CharacterDescriptionBuilder';
import CharacterState from './CharacterState';
import CustomBackground from './CustomBackground';
import DesignModeCursorDescriptionBuilder from './DesignModeCursorDescriptionBuilder';
import DesignModeCursorState from './DesignModeCursorState';
import { injectIntl } from 'react-intl';
import type { IntlShape } from 'react-intl';
import type { RunningState } from './types';
import type { WorldName } from './Worlds';
type CharacterAriaLiveProps = {
intl: IntlShape,
ariaLiveRegionId: string,
ariaHidden: boolean,
characterState: CharacterState,
designModeCursorState: DesignModeCursorState,
runningState: RunningState,
world: WorldName,
customBackground: CustomBackground,
customBackgroundDesignMode: boolean,
characterDescriptionBuilder: CharacterDescriptionBuilder,
designModeCursorDescriptionBuilder: DesignModeCursorDescriptionBuilder,
message: ?string
};
class CharacterAriaLive extends React.Component<CharacterAriaLiveProps, {}> {
lastMessage: ?string;
constructor(props: any) {
super(props);
this.lastMessage = null;
}
setCharacterMoving() {
const characterLabel = this.props.intl.formatMessage({
id: `${this.props.world}.character`
});
const text = this.props.intl.formatMessage(
{ id:'CharacterAriaLive.movementAriaLabel' },
{ sceneCharacter: characterLabel }
);
this.setLiveRegion(text);
}
// Combine the most recent message (if there is one) with the character
// description in a single update. With 2 separate updates, it was not
// possible to have both updates be spoken by VoiceOver on macOS. When
// the character description update was made while the message was still
// being spoken, either the character description would interrupt the
// message, or the character description would be ignored. A number of
// different node structures and live region attributes were tried but
// none were successful. With this approach, the message and character
// description texts are combined into a single live region update.
setMessageAndCharacterDescription() {
let text = '';
if (this.props.message != null
&& this.props.message !== this.lastMessage) {
text = this.props.message;
if (text.endsWith('.')) {
text += ' ';
} else {
text += '. ';
}
this.lastMessage = this.props.message;
}
text += this.props.characterDescriptionBuilder.buildDescription(
this.props.characterState,
this.props.world,
this.props.customBackground
);
this.setLiveRegion(text);
}
setDesignModeCursorDescription() {
this.setLiveRegion(
this.props.designModeCursorDescriptionBuilder.buildDescription(
this.props.designModeCursorState,
this.props.world,
this.props.customBackground
)
);
}
setLiveRegion(text: string) {
const ariaLiveRegion = document.getElementById(this.props.ariaLiveRegionId);
if (ariaLiveRegion) {
ariaLiveRegion.textContent = text;
}
}
render() {
return (
<React.Fragment />
);
}
componentDidMount() {
// Set aria-hidden
const ariaLiveRegion = document.getElementById(this.props.ariaLiveRegionId);
if (ariaLiveRegion) {
ariaLiveRegion.setAttribute('aria-hidden', this.props.ariaHidden.toString());
}
}
componentDidUpdate(prevProps: CharacterAriaLiveProps) {
// Set aria-hidden
if (prevProps.ariaHidden !== this.props.ariaHidden) {
const ariaLiveRegion = document.getElementById(this.props.ariaLiveRegionId);
if (ariaLiveRegion) {
ariaLiveRegion.setAttribute('aria-hidden', this.props.ariaHidden.toString());
}
}
if (this.props.message == null) {
this.lastMessage = null;
}
// Update the live region
if (prevProps.characterState !== this.props.characterState) {
if (this.props.runningState !== 'running') {
this.setMessageAndCharacterDescription();
}
} else if (prevProps.designModeCursorState !== this.props.designModeCursorState) {
this.setDesignModeCursorDescription();
} else if (prevProps.runningState !== this.props.runningState) {
if (this.props.runningState === 'stopRequested'
|| this.props.runningState === 'pauseRequested'
|| (prevProps.runningState === 'running' && this.props.runningState === 'stopped')
|| (prevProps.runningState === 'running' && this.props.runningState === 'paused')) {
this.setMessageAndCharacterDescription();
} else if (this.props.runningState === "running") {
this.setCharacterMoving();
}
} else if (prevProps.customBackgroundDesignMode && !(this.props.customBackgroundDesignMode)) {
this.setMessageAndCharacterDescription();
} else if (prevProps.world !== this.props.world) {
if (this.props.customBackgroundDesignMode) {
this.setDesignModeCursorDescription();
} else {
this.setMessageAndCharacterDescription();
}
}
}
}
export default injectIntl(CharacterAriaLive);