Skip to content

Commit 0f28f67

Browse files
authored
Merge pull request #1480 from cdrini/a11y-fixes
More accessibility improvements
2 parents 7ae6252 + 80e3c45 commit 0f28f67

21 files changed

+288
-238
lines changed

package-lock.json

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"dependencies": {
3434
"@internetarchive/bergamot-translator": "^0.4.9-ia.1",
3535
"@internetarchive/ia-activity-indicator": "^0.0.4",
36-
"@internetarchive/ia-item-navigator": "2.2.1",
36+
"@internetarchive/ia-item-navigator": "2.2.2",
3737
"@internetarchive/icon-bookmark": "^1.3.4",
3838
"@internetarchive/icon-dl": "^1.3.4",
3939
"@internetarchive/icon-edit-pencil": "^1.3.4",

src/BookReader.js

Lines changed: 48 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -876,18 +876,14 @@ BookReader.prototype.setupKeyListeners = function () {
876876
e.preventDefault();
877877
this.last();
878878
break;
879-
case "ArrowDown":
880879
case "PageDown":
881-
case "Down": // hack for IE and old Gecko
882880
// In 1up and thumb mode page scrolling handled by browser
883881
if (this.constMode2up === this.mode) {
884882
e.preventDefault();
885883
this.next();
886884
}
887885
break;
888-
case "ArrowUp":
889886
case "PageUp":
890-
case "Up": // hack for IE and old Gecko
891887
// In 1up and thumb mode page scrolling handled by browser
892888
if (this.constMode2up === this.mode) {
893889
e.preventDefault();
@@ -1119,14 +1115,16 @@ BookReader.prototype._reduceSort = (a, b) => a.reduce - b.reduce;
11191115

11201116
/**
11211117
* Attempts to jump to page
1122-
* @param {string}
1118+
* @param {string} pageNum
1119+
* @param {object} options
1120+
* @param {boolean} [options.ariaLive = false]
11231121
* @return {boolean} Returns true if page could be found, false otherwise.
11241122
*/
1125-
BookReader.prototype.jumpToPage = function(pageNum) {
1123+
BookReader.prototype.jumpToPage = function(pageNum, {ariaLive = false} = {}) {
11261124
const pageIndex = this.book.parsePageString(pageNum);
11271125

11281126
if ('undefined' != typeof(pageIndex)) {
1129-
this.jumpToIndex(pageIndex);
1127+
this.jumpToIndex(pageIndex, { ariaLive });
11301128
return true;
11311129
}
11321130

@@ -1145,27 +1143,35 @@ BookReader.prototype._isIndexDisplayed = function(index) {
11451143

11461144
/**
11471145
* Changes the current page
1148-
* @param {PageIndex} index
1149-
* @param {number} [pageX]
1150-
* @param {number} [pageY]
1151-
* @param {boolean} [noAnimate]
1146+
* @param {PageIndex | 'left' | 'right' | 'next' | 'prev'} indexOrDirection
1147+
* @param {object} options
1148+
* @param {number} [options.pageX] Position on page ; not implemented
1149+
* @param {number} [options.pageY] Position on page ; not implemented
1150+
* @param {boolean} [options.noAnimate]
1151+
* @param {number | 'fast' | 'slow'} [options.flipSpeed]
1152+
* @param {boolean} [options.ariaLive]
1153+
* @param {boolean} [options.triggerStop] - whether to trigger the stop event; default true; maybe deprecated?
11521154
*/
1153-
BookReader.prototype.jumpToIndex = function(index, pageX, pageY, noAnimate) {
1154-
// Don't jump into specific unviewable page
1155-
const page = this.book.getPage(index);
1155+
BookReader.prototype.jumpToIndex = function(indexOrDirection, {pageX = 0, pageY = 0, noAnimate = false, flipSpeed = null, ariaLive = false, triggerStop = true} = {}) {
1156+
const page = this.activeMode.parsePageSpecifier(indexOrDirection);
1157+
flipSpeed = utils.parseAnimationSpeed(flipSpeed) || this.flipSpeed;
1158+
if (!page || page.index == this.currentIndex()) {
1159+
return;
1160+
}
11561161

1162+
// Don't jump into specific unviewable page
11571163
if (!page.isViewable && page.unviewablesStart != page.index) {
11581164
// If already in unviewable range, jump to end of that range
11591165
const alreadyInPreview = this._isIndexDisplayed(page.unviewablesStart);
11601166
const newIndex = alreadyInPreview ? page.findNext({ combineConsecutiveUnviewables: true })?.index : page.unviewablesStart;
11611167
// Rare, but a book can end on an unviewable page, so this could be undefined
11621168
if (typeof newIndex !== 'undefined') {
1163-
this.jumpToIndex(newIndex, pageX, pageY, noAnimate);
1169+
this.jumpToIndex(newIndex, { pageX, pageY, noAnimate, flipSpeed, ariaLive });
11641170
}
11651171
} else {
1166-
this.trigger(BookReader.eventNames.stop);
1167-
1168-
this.activeMode.jumpToIndex(index, pageX, pageY, noAnimate);
1172+
if (triggerStop) this.trigger(BookReader.eventNames.stop);
1173+
this.trigger(BookReader.eventNames.beforePageChanged, { index: page.index, ariaLive });
1174+
this.activeMode.jumpToIndex(page.index, { pageX, pageY, noAnimate, flipSpeed, ariaLive });
11691175
}
11701176
};
11711177

@@ -1316,6 +1322,11 @@ BookReader.prototype.enterFullscreen = async function(bindKeyboardControls = tru
13161322
}
13171323

13181324
this.isFullscreenActive = true;
1325+
1326+
// Change tooltip of fullscreen button
1327+
this.$('.BRnav .BRicon.full').attr('title', 'Exit fullscreen');
1328+
this.$('.BRnav .BRicon.full .BRtooltip').text('Exit fullscreen');
1329+
13191330
// prioritize class updates so CSS can propagate
13201331
this.updateBrClasses();
13211332
if (this.activeMode instanceof Mode1Up) {
@@ -1359,6 +1370,10 @@ BookReader.prototype.exitFullScreen = async function () {
13591370
}
13601371

13611372
this.isFullscreenActive = false;
1373+
1374+
this.$('.BRnav .BRicon.full').attr('title', 'Go fullscreen');
1375+
this.$('.BRnav .BRicon.full .BRtooltip').text('Go fullscreen');
1376+
13621377
// Trigger fullscreen event immediately
13631378
// so that book-nav can relay to web components
13641379
this.trigger(BookReader.eventNames.fullscreenToggled);
@@ -1437,18 +1452,13 @@ BookReader.prototype.updateFirstIndex = function(
14371452

14381453
// event to know if user is actively reading
14391454
this.trigger(BookReader.eventNames.userAction);
1440-
this._components.navbar.updateNavIndexThrottled(index);
14411455
};
14421456

14431457
/**
14441458
* Flip the right page over onto the left
14451459
*/
1446-
BookReader.prototype.right = function() {
1447-
if ('rl' != this.pageProgression) {
1448-
this.next();
1449-
} else {
1450-
this.prev();
1451-
}
1460+
BookReader.prototype.right = function({ ariaLive = true, triggerStop = true } = {}) {
1461+
this.jumpToIndex('right', { ariaLive, triggerStop });
14521462
};
14531463

14541464
/**
@@ -1465,12 +1475,8 @@ BookReader.prototype.rightmost = function() {
14651475
/**
14661476
* Flip the left page over onto the right
14671477
*/
1468-
BookReader.prototype.left = function() {
1469-
if ('rl' != this.pageProgression) {
1470-
this.prev();
1471-
} else {
1472-
this.next();
1473-
}
1478+
BookReader.prototype.left = function({ ariaLive = true, triggerStop = true } = {}) {
1479+
this.jumpToIndex('left', { ariaLive, triggerStop });
14741480
};
14751481

14761482
/**
@@ -1488,51 +1494,36 @@ BookReader.prototype.leftmost = function() {
14881494
* @param {object} options
14891495
* @param {boolean} [options.triggerStop = true]
14901496
* @param {number | 'fast' | 'slow'} [options.flipSpeed]
1497+
* @param {boolean} [options.ariaLive = true]
14911498
*/
14921499
BookReader.prototype.next = function({
14931500
triggerStop = true,
14941501
flipSpeed = null,
1502+
ariaLive = true,
14951503
} = {}) {
1496-
if (this.constMode2up == this.mode) {
1497-
if (triggerStop) this.trigger(BookReader.eventNames.stop);
1498-
flipSpeed = utils.parseAnimationSpeed(flipSpeed) || this.flipSpeed;
1499-
this._modes.mode2Up.mode2UpLit.flipAnimation('next', {flipSpeed});
1500-
} else {
1501-
if (this.firstIndex < this.book.getNumLeafs() - 1) {
1502-
this.jumpToIndex(this.firstIndex + 1);
1503-
}
1504-
}
1504+
this.jumpToIndex('next', { ariaLive, flipSpeed, triggerStop });
15051505
};
15061506

15071507
/**
15081508
* @param {object} options
15091509
* @param {boolean} [options.triggerStop = true]
15101510
* @param {number | 'fast' | 'slow'} [options.flipSpeed]
1511+
* @param {boolean} [options.ariaLive = true]
15111512
*/
15121513
BookReader.prototype.prev = function({
15131514
triggerStop = true,
15141515
flipSpeed = null,
1516+
ariaLive = true,
15151517
} = {}) {
1516-
const isOnFrontPage = this.firstIndex < 1;
1517-
if (isOnFrontPage) return;
1518-
1519-
if (this.constMode2up == this.mode) {
1520-
if (triggerStop) this.trigger(BookReader.eventNames.stop);
1521-
flipSpeed = utils.parseAnimationSpeed(flipSpeed) || this.flipSpeed;
1522-
this._modes.mode2Up.mode2UpLit.flipAnimation('prev', {flipSpeed});
1523-
} else {
1524-
if (this.firstIndex >= 1) {
1525-
this.jumpToIndex(this.firstIndex - 1);
1526-
}
1527-
}
1518+
this.jumpToIndex('prev', { ariaLive, flipSpeed, triggerStop });
15281519
};
15291520

1530-
BookReader.prototype.first = function() {
1531-
this.jumpToIndex(0);
1521+
BookReader.prototype.first = function({ ariaLive = true, triggerStop = false } = {}) {
1522+
this.jumpToIndex(0, { ariaLive, triggerStop });
15321523
};
15331524

1534-
BookReader.prototype.last = function() {
1535-
this.jumpToIndex(this.book.getNumLeafs() - 1);
1525+
BookReader.prototype.last = function({ ariaLive = true, triggerStop = false } = {}) {
1526+
this.jumpToIndex(this.book.getNumLeafs() - 1, { ariaLive, triggerStop });
15361527
};
15371528

15381529

@@ -1744,7 +1735,7 @@ BookReader.prototype.initUIStrings = function() {
17441735
'.bookmark': 'Bookmark this page',
17451736
'.share': 'Share this book',
17461737
'.info': 'About this book',
1747-
'.full': 'Toggle fullscreen',
1738+
'.full': 'Go fullscreen',
17481739
'.toggle_slider': 'Toggle page controls',
17491740
'.book_left': 'Flip left',
17501741
'.book_right': 'Flip right',

src/BookReader/Mode1Up.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
// @ts-check
22
import { Mode1UpLit } from './Mode1UpLit.js';
33
import { DragScrollable } from './DragScrollable.js';
4+
import { ModeAbstract } from './ModeAbstract.js';
45
/** @typedef {import('../BookReader.js').default} BookReader */
56
/** @typedef {import('./BookModel.js').BookModel} BookModel */
67
/** @typedef {import('./BookModel.js').PageIndex} PageIndex */
78

8-
export class Mode1Up {
9+
export class Mode1Up extends ModeAbstract {
910
name = '1up'
1011

1112
/**
1213
* @param {BookReader} br
1314
* @param {BookModel} bookModel
1415
*/
1516
constructor(br, bookModel) {
17+
super();
1618
this.br = br;
1719
this.book = bookModel;
1820
this.mode1UpLit = new Mode1UpLit(bookModel, br);
@@ -72,11 +74,12 @@ export class Mode1Up {
7274
/**
7375
* BREAKING CHANGE: No longer supports pageX/pageY
7476
* @param {PageIndex} index
75-
* @param {number} [pageX] x position on the page (in pixels) to center on
76-
* @param {number} [pageY] y position on the page (in pixels) to center on
77-
* @param {boolean} [noAnimate]
77+
* @param {object} options
78+
* @param {number} [options.pageX] x position on the page (in pixels) to center on
79+
* @param {number} [options.pageY] y position on the page (in pixels) to center on
80+
* @param {boolean} [options.noAnimate]
7881
*/
79-
jumpToIndex(index, pageX, pageY, noAnimate) {
82+
jumpToIndex(index, {pageX = 0, pageY = 0, noAnimate = false} = {}) {
8083
// Only smooth for small distances
8184
const distance = Math.abs(this.br.currentIndex() - index);
8285
const smooth = !noAnimate && distance > 0 && distance <= 4;

src/BookReader/Mode1UpLit.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ export class Mode1UpLit extends LitElement {
196196
// unclear why this is ever really happening
197197
this.br.displayedIndices = this.visiblePages.map(p => p.index);
198198
this.br.updateFirstIndex(this.br.displayedIndices[0]);
199-
this.br._components.navbar.updateNavIndexThrottled();
200199
}
201200
}
202201
if (changedProps.has('scale')) {

src/BookReader/Mode2Up.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
// @ts-check
22
import { Mode2UpLit } from './Mode2UpLit.js';
33
import { DragScrollable } from './DragScrollable.js';
4+
import { ModeAbstract } from './ModeAbstract.js';
45
/** @typedef {import('../BookReader.js').default} BookReader */
56
/** @typedef {import('./BookModel.js').BookModel} BookModel */
67
/** @typedef {import('./BookModel.js').PageIndex} PageIndex */
78

8-
export class Mode2Up {
9+
export class Mode2Up extends ModeAbstract {
910
name = '2up';
1011

1112
/**
1213
* @param {BookReader} br
1314
* @param {BookModel} bookModel
1415
*/
1516
constructor(br, bookModel) {
17+
super();
1618
this.br = br;
1719
this.book = bookModel;
1820
this.mode2UpLit = new Mode2UpLit(bookModel, br);
@@ -70,14 +72,27 @@ export class Mode2Up {
7072
/**
7173
* BREAKING CHANGE: No longer supports pageX/pageY
7274
* @param {PageIndex} index
73-
* @param {number} [pageX] x position on the page (in pixels) to center on
74-
* @param {number} [pageY] y position on the page (in pixels) to center on
75-
* @param {boolean} [noAnimate]
75+
* @param {object} options
76+
* @param {number} [options.pageX] x position on the page (in pixels) to center on
77+
* @param {number} [options.pageY] y position on the page (in pixels) to center on
78+
* @param {boolean} [options.noAnimate]
7679
*/
77-
jumpToIndex(index, pageX, pageY, noAnimate) {
80+
jumpToIndex(index, {pageX = 0, pageY = 0, noAnimate = false} = {}) {
7881
this.mode2UpLit.jumpToIndex(index);
7982
}
8083

84+
/**
85+
* @override
86+
* @param {PageIndex | 'left' | 'right' | 'next' | 'prev'} indexOrDirection
87+
* @return {import('./BookModel.js').PageModel}
88+
*/
89+
parsePageSpecifier(indexOrDirection) {
90+
const isRTL = this.book.pageProgression == 'rl';
91+
const nextSpread = this.mode2UpLit.parseNextSpread(indexOrDirection);
92+
const nextLeftIndex = nextSpread?.left?.index ?? (isRTL ? -1 : this.book.getNumLeafs());
93+
return this.book.getPage(nextLeftIndex);
94+
}
95+
8196
/**
8297
* @param {'in' | 'out'} direction
8398
*/

0 commit comments

Comments
 (0)