Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions navigator/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.2] - 2025-10-30

### Added

- Guard `WebPubSettings` assignment on `displayTransformability`

### Fixed

- Corrects `isEffective` check in `WebPubPreferencesEditor`

## [2.2.1] - 2025-10-28

### Added
Expand Down
2 changes: 1 addition & 1 deletion navigator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@readium/navigator",
"version": "2.2.1",
"version": "2.2.2",
"type": "module",
"description": "Next generation SDK for publications in Web Apps",
"author": "readium",
Expand Down
23 changes: 19 additions & 4 deletions navigator/src/webpub/WebPubNavigator.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Link, Locator, Publication, ReadingProgression, LocatorLocations } from "@readium/shared";
import { Feature, Link, Locator, Publication, ReadingProgression, LocatorLocations } from "@readium/shared";
import { VisualNavigator, VisualNavigatorViewport, ProgressionRange } from "../Navigator";
import { Configurable } from "../preferences/Configurable";
import { WebPubFramePoolManager } from "./WebPubFramePoolManager";
import { BasicTextSelection, CommsEventKey, FrameClickEvent, ModuleLibrary, ModuleName, WebPubModules } from "@readium/navigator-html-injectables";
import * as path from "path-browserify";
import { WebPubFrameManager } from "./WebPubFrameManager";

import { ManagerEventKey } from "../epub/EpubNavigator";
import { WebPubCSS } from "./css/WebPubCSS";
import { WebUserProperties } from "./css/Properties";
Expand All @@ -12,7 +14,6 @@ import { IWebPubDefaults, WebPubDefaults } from "./preferences/WebPubDefaults";
import { WebPubSettings } from "./preferences/WebPubSettings";
import { IPreferencesEditor } from "../preferences/PreferencesEditor";
import { WebPubPreferencesEditor } from "./preferences/WebPubPreferencesEditor";

export interface WebPubNavigatorConfiguration {
preferences: IWebPubPreferences;
defaults: IWebPubDefaults;
Expand Down Expand Up @@ -71,7 +72,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
// Initialize preference system
this._preferences = new WebPubPreferences(configuration.preferences);
this._defaults = new WebPubDefaults(configuration.defaults);
this._settings = new WebPubSettings(this._preferences, this._defaults);
this._settings = new WebPubSettings(this._preferences, this._defaults, this.hasDisplayTransformability);
this._css = new WebPubCSS({
userProperties: new WebUserProperties({ zoom: this._settings.zoom })
});
Expand Down Expand Up @@ -115,7 +116,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
}

private async applyPreferences() {
this._settings = new WebPubSettings(this._preferences, this._defaults);
this._settings = new WebPubSettings(this._preferences, this._defaults, this.hasDisplayTransformability);

if (this._preferencesEditor !== null) {
this._preferencesEditor = new WebPubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
Expand Down Expand Up @@ -146,6 +147,20 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
this.framePool.setCSSProperties(properties);
}

/**
* Exposed to the public to compensate for lack of implemented readium conveniences
* TODO remove when settings management is incorporated
*/
public get _cframes(): (WebPubFrameManager | undefined)[] {
return this.framePool.currentFrames;
}

private get hasDisplayTransformability(): boolean {
return this.pub.metadata?.accessibility?.feature?.some(
f => f.value === Feature.DISPLAY_TRANSFORMABILITY.value
) ?? false;
}

public eventListener(key: CommsEventKey | ManagerEventKey, data: unknown) {
switch (key) {
case "_pong":
Expand Down
30 changes: 18 additions & 12 deletions navigator/src/webpub/preferences/WebPubPreferencesEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
this.preferences[key] = value;
}

private get isDisplayTransformable(): boolean {
return this.metadata?.accessibility?.feature?.some(
f => f.value === Feature.DISPLAY_TRANSFORMABILITY.value
) ?? false; // Default to false if no metadata
}

get fontFamily(): Preference<string> {
return new Preference<string>({
initialValue: this.preferences.fontFamily,
effectiveValue: this.settings.fontFamily || null,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: string | null | undefined) => {
this.updatePreference("fontFamily", newValue || null);
}
Expand All @@ -48,7 +54,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.fontWeight,
effectiveValue: this.settings.fontWeight || 400,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("fontWeight", newValue || null);
},
Expand All @@ -61,7 +67,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new BooleanPreference({
initialValue: this.preferences.hyphens,
effectiveValue: this.settings.hyphens || false,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: boolean | null | undefined) => {
this.updatePreference("hyphens", newValue || null);
}
Expand All @@ -72,7 +78,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.letterSpacing,
effectiveValue: this.settings.letterSpacing || 0,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("letterSpacing", newValue || null);
},
Expand All @@ -85,7 +91,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new BooleanPreference({
initialValue: this.preferences.ligatures,
effectiveValue: this.settings.ligatures || true,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: boolean | null | undefined) => {
this.updatePreference("ligatures", newValue || null);
}
Expand All @@ -96,7 +102,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.lineHeight,
effectiveValue: this.settings.lineHeight,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("lineHeight", newValue || null);
},
Expand All @@ -109,7 +115,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new BooleanPreference({
initialValue: this.preferences.noRuby,
effectiveValue: this.settings.noRuby || false,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: boolean | null | undefined) => {
this.updatePreference("noRuby", newValue || null);
}
Expand All @@ -120,7 +126,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.paragraphIndent,
effectiveValue: this.settings.paragraphIndent || 0,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("paragraphIndent", newValue || null);
},
Expand All @@ -133,7 +139,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.paragraphSpacing,
effectiveValue: this.settings.paragraphSpacing || 0,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("paragraphSpacing", newValue || null);
},
Expand All @@ -146,7 +152,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new EnumPreference<TextAlignment>({
initialValue: this.preferences.textAlign,
effectiveValue: this.settings.textAlign || TextAlignment.start,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: TextAlignment | null | undefined) => {
this.updatePreference("textAlign", newValue || null);
},
Expand All @@ -158,7 +164,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new BooleanPreference({
initialValue: this.preferences.textNormalization,
effectiveValue: this.settings.textNormalization || false,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: boolean | null | undefined) => {
this.updatePreference("textNormalization", newValue || null);
}
Expand All @@ -169,7 +175,7 @@ export class WebPubPreferencesEditor implements IPreferencesEditor {
return new RangePreference<number>({
initialValue: this.preferences.wordSpacing,
effectiveValue: this.settings.wordSpacing || 0,
isEffective: this.metadata?.accessibility?.feature?.includes(Feature.DISPLAY_TRANSFORMABILITY) ?? false,
isEffective: this.isDisplayTransformable,
onChange: (newValue: number | null | undefined) => {
this.updatePreference("wordSpacing", newValue || null);
},
Expand Down
116 changes: 59 additions & 57 deletions navigator/src/webpub/preferences/WebPubSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,67 @@ export interface IWebPubSettings {
}

export class WebPubSettings implements ConfigurableSettings {
fontFamily: string | null;
fontWeight: number | null;
hyphens: boolean | null;
letterSpacing: number | null;
ligatures: boolean | null;
lineHeight: number | null;
noRuby: boolean | null;
paragraphIndent: number | null;
paragraphSpacing: number | null;
textAlign: TextAlignment | null;
textNormalization: boolean | null;
wordSpacing: number | null;
fontFamily: string | null = null;
fontWeight: number | null = null;
hyphens: boolean | null = null;
letterSpacing: number | null = null;
ligatures: boolean | null = null;
lineHeight: number | null = null;
noRuby: boolean | null = null;
paragraphIndent: number | null = null;
paragraphSpacing: number | null = null;
textAlign: TextAlignment | null = null;
textNormalization: boolean | null = null;
wordSpacing: number | null = null;
zoom: number | null;

constructor(preferences: WebPubPreferences, defaults: WebPubDefaults) {
this.fontFamily = preferences.fontFamily || defaults.fontFamily || null;
this.fontWeight = preferences.fontWeight !== undefined
? preferences.fontWeight
: defaults.fontWeight !== undefined
? defaults.fontWeight
: null;
this.hyphens = typeof preferences.hyphens === "boolean"
? preferences.hyphens
: defaults.hyphens ?? null;
this.letterSpacing = preferences.letterSpacing !== undefined
? preferences.letterSpacing
: defaults.letterSpacing !== undefined
? defaults.letterSpacing
: null;
this.ligatures = typeof preferences.ligatures === "boolean"
? preferences.ligatures
: defaults.ligatures ?? null;
this.lineHeight = preferences.lineHeight !== undefined
? preferences.lineHeight
: defaults.lineHeight !== undefined
? defaults.lineHeight
: null;
this.noRuby = typeof preferences.noRuby === "boolean"
? preferences.noRuby
: defaults.noRuby ?? null;
this.paragraphIndent = preferences.paragraphIndent !== undefined
? preferences.paragraphIndent
: defaults.paragraphIndent !== undefined
? defaults.paragraphIndent
: null;
this.paragraphSpacing = preferences.paragraphSpacing !== undefined
? preferences.paragraphSpacing
: defaults.paragraphSpacing !== undefined
? defaults.paragraphSpacing
: null;
this.textAlign = preferences.textAlign || defaults.textAlign || null;
this.textNormalization = typeof preferences.textNormalization === "boolean"
? preferences.textNormalization
: defaults.textNormalization ?? null;
this.wordSpacing = preferences.wordSpacing !== undefined
? preferences.wordSpacing
: defaults.wordSpacing !== undefined
? defaults.wordSpacing
: null;
constructor(preferences: WebPubPreferences, defaults: WebPubDefaults, hasDisplayTransformability: boolean) {
if (hasDisplayTransformability) {
this.fontFamily = preferences.fontFamily || defaults.fontFamily || null;
this.fontWeight = preferences.fontWeight !== undefined
? preferences.fontWeight
: defaults.fontWeight !== undefined
? defaults.fontWeight
: null;
this.hyphens = typeof preferences.hyphens === "boolean"
? preferences.hyphens
: defaults.hyphens ?? null;
this.letterSpacing = preferences.letterSpacing !== undefined
? preferences.letterSpacing
: defaults.letterSpacing !== undefined
? defaults.letterSpacing
: null;
this.ligatures = typeof preferences.ligatures === "boolean"
? preferences.ligatures
: defaults.ligatures ?? null;
this.lineHeight = preferences.lineHeight !== undefined
? preferences.lineHeight
: defaults.lineHeight !== undefined
? defaults.lineHeight
: null;
this.noRuby = typeof preferences.noRuby === "boolean"
? preferences.noRuby
: defaults.noRuby ?? null;
this.paragraphIndent = preferences.paragraphIndent !== undefined
? preferences.paragraphIndent
: defaults.paragraphIndent !== undefined
? defaults.paragraphIndent
: null;
this.paragraphSpacing = preferences.paragraphSpacing !== undefined
? preferences.paragraphSpacing
: defaults.paragraphSpacing !== undefined
? defaults.paragraphSpacing
: null;
this.textAlign = preferences.textAlign || defaults.textAlign || null;
this.textNormalization = typeof preferences.textNormalization === "boolean"
? preferences.textNormalization
: defaults.textNormalization ?? null;
this.wordSpacing = preferences.wordSpacing !== undefined
? preferences.wordSpacing
: defaults.wordSpacing !== undefined
? defaults.wordSpacing
: null;
}
this.zoom = preferences.zoom !== undefined
? preferences.zoom
: defaults.zoom !== undefined
Expand Down