Skip to content

Commit

Permalink
Content iterator (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
chocolatkey authored Mar 7, 2024
1 parent 3588329 commit 5053594
Show file tree
Hide file tree
Showing 84 changed files with 7,989 additions and 2,021 deletions.
4 changes: 3 additions & 1 deletion navigator-html-injectables/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"module": "dist/index.js",
"devDependencies": {
"@juggle/resize-observer": "^3.4.0",
"tslib": "^2.3.1"
"@readium/shared": "workspace:1.2.0",
"css-selector-generator": "^3.6.4",
"tslib": "^2.6.1"
}
}
7 changes: 5 additions & 2 deletions navigator-html-injectables/src/comms/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export type CommsEventKey =
"no_more" |
"no_less" |
"swipe" |
"progress";
"progress" |
"first_visible_locator";
;

export type CommsCommandKey =
Expand All @@ -26,7 +27,9 @@ export type CommsCommandKey =
"go_progression" |
"set_property" |
"remove_property" |
"exact_progress" |
// "exact_progress" |
"first_visible_locator" |
"decorate" |
"protect" |
"unprotect" |
"unfocus" |
Expand Down
5 changes: 4 additions & 1 deletion navigator-html-injectables/src/helpers/css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

// Easy way to get a CSS property
export function getProperty(wnd: Window, key: string) {
return wnd.document.documentElement.style.getPropertyValue(key);
}

// Easy way to set a CSS property
export function setProperty(wnd: Window, key: string, value: string) {
Expand Down
122 changes: 122 additions & 0 deletions navigator-html-injectables/src/helpers/dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// (From swift-toolkit @ https://github.com/hypothesis/client/blob/main/src/annotator/highlighter.ts)

import { Locator, LocatorLocations, LocatorText } from "@readium/shared/src/publication";
import type { getCssSelector } from "css-selector-generator";

type BlockedEventData = [0, Function, any[], any[]] | [1, Event];

// This is what is injected into the HTML documents
export interface ReadiumWindow extends Window {
_readium_blockEvents: boolean;
_readium_blockedEvents: BlockedEventData[];
_readium_eventBlocker: EventListenerOrEventListenerObject;
_readium_cssSelectorGenerator: {
getCssSelector: typeof getCssSelector;
};
}


const interactiveTags = [
"a",
"audio",
"button",
"canvas",
"details",
"input",
"label",
"option",
"select",
"submit",
"textarea",
"video",
];

// See https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling
export function nearestInteractiveElement(element: Element): Element | null {
if (interactiveTags.indexOf(element.nodeName.toLowerCase()) !== -1) {
return element;
}

// Checks whether the element is editable by the user.
if (
element.hasAttribute("contenteditable") &&
element.getAttribute("contenteditable")?.toLowerCase() !== "false"
) {
return element;
}

// Checks parents recursively because the touch might be for example on an <em> inside a <a>.
if (element.parentElement) {
return nearestInteractiveElement(element.parentElement);
}

return null;
}

/// Returns the `Locator` object to the first block element that is visible on
/// the screen.
export function findFirstVisibleLocator(wnd: ReadiumWindow, scrolling: boolean) {
const element = findElement(wnd, wnd.document.body, scrolling);
return new Locator({
href: "#",
type: "application/xhtml+xml",
locations: new LocatorLocations({
otherLocations: new Map([
["cssSelector", wnd._readium_cssSelectorGenerator.getCssSelector(element)]
])
}),
text: new LocatorText({
highlight: element.textContent || undefined
}),
});
}

function findElement(wnd: ReadiumWindow, rootElement: Element, scrolling: boolean): Element {
for (var i = 0; i < rootElement.children.length; i++) {
const child = rootElement.children[i];
if (!shouldIgnoreElement(child) && isElementVisible(wnd, child, scrolling)) {
return findElement(wnd, child, scrolling);
}
}
return rootElement;
}

function isElementVisible(wnd: ReadiumWindow, element: Element, scrolling: boolean) {
// if (readium.isFixedLayout) return true;

if (element === document.body || element === document.documentElement) {
return true;
}
if (!document || !document.documentElement || !document.body) {
return false;
}

const rect = element.getBoundingClientRect();
if (scrolling) {
return rect.bottom > 0 && rect.top < wnd.innerHeight;
} else {
return rect.right > 0 && rect.left < wnd.innerWidth;
}
}

function shouldIgnoreElement(element: Element) {
const elStyle = getComputedStyle(element);
if (elStyle) {
const display = elStyle.getPropertyValue("display");
if (display != "block") {
return true;
}
// Cannot be relied upon, because web browser engine reports invisible when out of view in
// scrolled columns!
// const visibility = elStyle.getPropertyValue("visibility");
// if (visibility === "hidden") {
// return false;
// }
const opacity = elStyle.getPropertyValue("opacity");
if (opacity === "0") {
return true;
}
}

return false;
}
Loading

0 comments on commit 5053594

Please sign in to comment.