mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 818342 - Introduce announcement output. r=davidb
This commit is contained in:
parent
723100f2cc
commit
085bf7b9c8
@ -28,3 +28,35 @@
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#announce-box {
|
||||
position: fixed;
|
||||
width: 7.5em;
|
||||
height: 5em;
|
||||
top: calc(100% - 50% - 2.5em);
|
||||
left: calc(100% - 50% - 3.75em);
|
||||
pointer-events: none;
|
||||
display: table;
|
||||
font-size: 28pt;
|
||||
font-weight: 700;
|
||||
color: orange;
|
||||
background-color: black;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
|
||||
#announce-box:not(.showing) {
|
||||
opacity: 0.0;
|
||||
margin: 0.1em;
|
||||
-moz-transition: opacity 0.4s linear;
|
||||
}
|
||||
|
||||
#announce-box.showing {
|
||||
opacity: 1.0;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
}
|
||||
|
||||
#announce-box * {
|
||||
text-align: center;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ this.AccessFu = {
|
||||
|
||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||
Cu.import('resource://gre/modules/accessibility/TouchAdapter.jsm');
|
||||
Cu.import('resource://gre/modules/accessibility/Presentation.jsm');
|
||||
|
||||
Logger.info('enable');
|
||||
|
||||
@ -145,26 +146,30 @@ this.AccessFu = {
|
||||
|
||||
switch (aMessage.name) {
|
||||
case 'AccessFu:Ready':
|
||||
let mm = Utils.getMessageManager(aMessage.target);
|
||||
mm.sendAsyncMessage('AccessFu:Start',
|
||||
{method: 'start', buildApp: Utils.MozBuildApp});
|
||||
break;
|
||||
let mm = Utils.getMessageManager(aMessage.target);
|
||||
mm.sendAsyncMessage('AccessFu:Start',
|
||||
{method: 'start', buildApp: Utils.MozBuildApp});
|
||||
break;
|
||||
case 'AccessFu:Present':
|
||||
this._output(aMessage.json, aMessage.target);
|
||||
break;
|
||||
case 'AccessFu:Input':
|
||||
Input.setEditState(aMessage.json);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_output: function _output(aPresentationData, aBrowser) {
|
||||
try {
|
||||
for each (let presenter in aMessage.json) {
|
||||
for each (let presenter in aPresentationData) {
|
||||
if (!presenter)
|
||||
continue;
|
||||
|
||||
Output[presenter.type](presenter.details, aMessage.target);
|
||||
Output[presenter.type](presenter.details, aBrowser);
|
||||
}
|
||||
} catch (x) {
|
||||
Logger.logException(x);
|
||||
}
|
||||
break;
|
||||
case 'AccessFu:Input':
|
||||
Input.setEditState(aMessage.json);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_loadFrameScript: function _loadFrameScript(aMessageManager) {
|
||||
@ -243,6 +248,11 @@ this.AccessFu = {
|
||||
}
|
||||
},
|
||||
|
||||
announce: function announce(aAnnouncement) {
|
||||
this._output(Presentation.announce(aAnnouncement),
|
||||
Utils.getCurrentBrowser(this.chromeWin));
|
||||
},
|
||||
|
||||
// So we don't enable/disable twice
|
||||
_enabled: false,
|
||||
|
||||
@ -262,34 +272,71 @@ var Output = {
|
||||
},
|
||||
|
||||
Visual: function Visual(aDetails, aBrowser) {
|
||||
if (!this.highlightBox) {
|
||||
// Add highlight box
|
||||
this.highlightBox = this.chromeWin.document.
|
||||
createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
this.chromeWin.document.documentElement.appendChild(this.highlightBox);
|
||||
this.highlightBox.id = 'virtual-cursor-box';
|
||||
switch (aDetails.method) {
|
||||
case 'showBounds':
|
||||
{
|
||||
if (!this.highlightBox) {
|
||||
// Add highlight box
|
||||
this.highlightBox = this.chromeWin.document.
|
||||
createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
this.chromeWin.document.documentElement.appendChild(this.highlightBox);
|
||||
this.highlightBox.id = 'virtual-cursor-box';
|
||||
|
||||
// Add highlight inset for inner shadow
|
||||
let inset = this.chromeWin.document.
|
||||
createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
inset.id = 'virtual-cursor-inset';
|
||||
// Add highlight inset for inner shadow
|
||||
let inset = this.chromeWin.document.
|
||||
createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
inset.id = 'virtual-cursor-inset';
|
||||
|
||||
this.highlightBox.appendChild(inset);
|
||||
}
|
||||
this.highlightBox.appendChild(inset);
|
||||
}
|
||||
|
||||
if (aDetails.method == 'show') {
|
||||
let padding = aDetails.padding;
|
||||
let r = this._adjustBounds(aDetails.bounds, aBrowser);
|
||||
let padding = aDetails.padding;
|
||||
let r = this._adjustBounds(aDetails.bounds, aBrowser);
|
||||
|
||||
// First hide it to avoid flickering when changing the style.
|
||||
this.highlightBox.style.display = 'none';
|
||||
this.highlightBox.style.top = (r.top - padding) + 'px';
|
||||
this.highlightBox.style.left = (r.left - padding) + 'px';
|
||||
this.highlightBox.style.width = (r.width + padding*2) + 'px';
|
||||
this.highlightBox.style.height = (r.height + padding*2) + 'px';
|
||||
this.highlightBox.style.display = 'block';
|
||||
} else if (aDetails.method == 'hide') {
|
||||
this.highlightBox.style.display = 'none';
|
||||
// First hide it to avoid flickering when changing the style.
|
||||
this.highlightBox.style.display = 'none';
|
||||
this.highlightBox.style.top = (r.top - padding) + 'px';
|
||||
this.highlightBox.style.left = (r.left - padding) + 'px';
|
||||
this.highlightBox.style.width = (r.width + padding*2) + 'px';
|
||||
this.highlightBox.style.height = (r.height + padding*2) + 'px';
|
||||
this.highlightBox.style.display = 'block';
|
||||
|
||||
break;
|
||||
}
|
||||
case 'hideBounds':
|
||||
{
|
||||
if (this.highlightBox)
|
||||
this.highlightBox.style.display = 'none';
|
||||
break;
|
||||
}
|
||||
case 'showAnnouncement':
|
||||
{
|
||||
if (!this.announceBox) {
|
||||
this.announceBox = this.chromeWin.document.
|
||||
createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
this.announceBox.id = 'announce-box';
|
||||
this.chromeWin.document.documentElement.appendChild(this.announceBox);
|
||||
}
|
||||
|
||||
this.announceBox.innerHTML = '<div>' + aDetails.text + '</div>';
|
||||
this.announceBox.classList.add('showing');
|
||||
|
||||
if (this._announceHideTimeout)
|
||||
this.chromeWin.clearTimeout(this._announceHideTimeout);
|
||||
|
||||
if (aDetails.duration > 0)
|
||||
this._announceHideTimeout = this.chromeWin.setTimeout(
|
||||
function () {
|
||||
this.announceBox.classList.remove('showing');
|
||||
this._announceHideTimeout = 0;
|
||||
}.bind(this), aDetails.duration);
|
||||
break;
|
||||
}
|
||||
case 'hideAnnouncement':
|
||||
{
|
||||
this.announceBox.classList.remove('showing');
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -100,7 +100,12 @@ Presenter.prototype = {
|
||||
/**
|
||||
* We have entered or left text editing mode.
|
||||
*/
|
||||
editingModeChanged: function editingModeChanged(aIsEditing) {}
|
||||
editingModeChanged: function editingModeChanged(aIsEditing) {},
|
||||
|
||||
/**
|
||||
* Announce something. Typically an app state change.
|
||||
*/
|
||||
announce: function announce(aAnnouncement) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -125,7 +130,7 @@ VisualPresenter.prototype = {
|
||||
return {
|
||||
type: this.type,
|
||||
details: {
|
||||
method: 'show',
|
||||
method: 'showBounds',
|
||||
bounds: context.bounds,
|
||||
padding: this.BORDER_PADDING
|
||||
}
|
||||
@ -139,7 +144,7 @@ VisualPresenter.prototype = {
|
||||
this._currentAccessible = aContext.accessible;
|
||||
|
||||
if (!aContext.accessible)
|
||||
return {type: this.type, details: {method: 'hide'}};
|
||||
return {type: this.type, details: {method: 'hideBounds'}};
|
||||
|
||||
try {
|
||||
aContext.accessible.scrollTo(
|
||||
@ -147,7 +152,7 @@ VisualPresenter.prototype = {
|
||||
return {
|
||||
type: this.type,
|
||||
details: {
|
||||
method: 'show',
|
||||
method: 'showBounds',
|
||||
bounds: aContext.bounds,
|
||||
padding: this.BORDER_PADDING
|
||||
}
|
||||
@ -165,9 +170,20 @@ VisualPresenter.prototype = {
|
||||
tabStateChanged: function VisualPresenter_tabStateChanged(aDocObj,
|
||||
aPageState) {
|
||||
if (aPageState == 'newdoc')
|
||||
return {type: this.type, details: {method: 'hide'}};
|
||||
return {type: this.type, details: {method: 'hideBounds'}};
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
announce: function VisualPresenter_announce(aAnnouncement) {
|
||||
return {
|
||||
type: this.type,
|
||||
details: {
|
||||
method: 'showAnnouncement',
|
||||
text: aAnnouncement,
|
||||
duration: 1000
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -257,8 +273,8 @@ AndroidPresenter.prototype = {
|
||||
|
||||
tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj,
|
||||
aPageState) {
|
||||
return this._appAnnounce(
|
||||
UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
|
||||
return this.announce(
|
||||
UtteranceGenerator.genForTabStateChange(aDocObj, aPageState).join(' '));
|
||||
},
|
||||
|
||||
textChanged: function AndroidPresenter_textChanged(aIsInserted, aStart,
|
||||
@ -303,20 +319,18 @@ AndroidPresenter.prototype = {
|
||||
},
|
||||
|
||||
editingModeChanged: function AndroidPresenter_editingModeChanged(aIsEditing) {
|
||||
return this._appAnnounce(UtteranceGenerator.genForEditingMode(aIsEditing));
|
||||
return this.announce(
|
||||
UtteranceGenerator.genForEditingMode(aIsEditing).join(' '));
|
||||
},
|
||||
|
||||
_appAnnounce: function _appAnnounce(aUtterance) {
|
||||
if (!aUtterance.length)
|
||||
return null;
|
||||
|
||||
announce: function AndroidPresenter_announce(aAnnouncement) {
|
||||
return {
|
||||
type: this.type,
|
||||
details: [{
|
||||
eventType: (Utils.AndroidSdkVersion >= 16) ?
|
||||
this.ANDROID_ANNOUNCEMENT : this.ANDROID_VIEW_TEXT_CHANGED,
|
||||
text: aUtterance,
|
||||
addedCount: aUtterance.join(' ').length,
|
||||
text: [aAnnouncement],
|
||||
addedCount: aAnnouncement.length,
|
||||
removedCount: 0,
|
||||
fromIndex: 0
|
||||
}]
|
||||
@ -500,7 +514,6 @@ PresenterContext.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.Presentation = {
|
||||
get presenters() {
|
||||
delete this.presenters;
|
||||
@ -550,5 +563,12 @@ this.Presentation = {
|
||||
editingModeChanged: function Presentation_editingModeChanged(aIsEditing) {
|
||||
return [p.editingModeChanged(aIsEditing)
|
||||
for each (p in this.presenters)];
|
||||
},
|
||||
|
||||
announce: function Presentation_announce(aAnnouncement) {
|
||||
// XXX: Typically each presenter uses the UtteranceGenerator,
|
||||
// but there really isn't a point here.
|
||||
return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)[0])
|
||||
for each (p in this.presenters)];
|
||||
}
|
||||
};
|
||||
|
@ -97,6 +97,20 @@ this.UtteranceGenerator = {
|
||||
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates an utterance for an announcement. Basically attempts to localize
|
||||
* the announcement string.
|
||||
* @param {string} aAnnouncement unlocalized announcement.
|
||||
* @return {Array} A one string array with the announcement.
|
||||
*/
|
||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
||||
try {
|
||||
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
||||
} catch (x) {
|
||||
return [aAnnouncement];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates an utterance for a tab state change.
|
||||
* @param {nsIAccessible} aAccessible accessible object of the tab's attached
|
||||
@ -309,7 +323,7 @@ this.UtteranceGenerator = {
|
||||
|
||||
return stateUtterances;
|
||||
},
|
||||
|
||||
|
||||
_getListUtterance: function _getListUtterance(aAccessible, aRoleStr, aFlags, aItemCount) {
|
||||
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
|
||||
let desc = [];
|
||||
|
Loading…
Reference in New Issue
Block a user