Commit e45a0a1b authored by Robert Knight's avatar Robert Knight

Define `Integration` interface

Explicitly define the common `Integration` interface which is
implemented by both `HTMLIntegration` and `PDFIntegration`.

This makes it more obvious what is part of the common interface that
`Guest` can depend on and what are additional properties or methods that
are specific to a particular implementation.
parent 90139746
......@@ -22,8 +22,9 @@ import { normalizeURI } from './util/url';
* @typedef {import('./util/emitter').EventBus} EventBus
* @typedef {import('../types/annotator').AnnotationData} AnnotationData
* @typedef {import('../types/annotator').Anchor} Anchor
* @typedef {import('../types/annotator').Integration} Integration
* @typedef {import('../types/annotator').SidebarLayout} SidebarLayout
* @typedef {import('../types/api').Target} Target
* @typedef {import('./sidebar').LayoutState} LayoutState
*/
/**
......@@ -142,13 +143,11 @@ export default class Guest {
/** @type {Anchor[]} */
this.anchors = [];
// Setup the document type-specific integration consisting of metadata extraction,
// anchoring module and logic to respond to activity (eg. scrolling) in the page.
if (config.documentType === 'pdf') {
this.integration = new PDFIntegration(this);
} else {
this.integration = new HTMLIntegration(this.element);
}
/** @type {Integration} */
this.integration =
config.documentType === 'pdf'
? new PDFIntegration(this)
: new HTMLIntegration(this.element);
// Set the frame identifier if it's available.
// The "top" guest instance will have this as null since it's in a top frame not a sub frame
......@@ -664,7 +663,7 @@ export default class Guest {
/**
* Attempt to fit the document content alongside the sidebar.
*
* @param {LayoutState} sidebarLayout
* @param {SidebarLayout} sidebarLayout
*/
fitSideBySide(sidebarLayout) {
const active = this.integration.fitSideBySide(sidebarLayout);
......
......@@ -2,6 +2,18 @@ import { anchor, describe } from '../anchoring/html';
import { HTMLMetadata } from './html-metadata';
/**
* @typedef {import('../../types/annotator').Integration} Integration
*/
/**
* Document type integration for ordinary web pages.
*
* This integration is used for web pages and applications that are not handled
* by a more specific integration (eg. for PDFs).
*
* @implements {Integration}
*/
export class HTMLIntegration {
constructor(container = document.body) {
this.container = container;
......
......@@ -13,8 +13,9 @@ import { PDFMetadata } from './pdf-metadata';
* @typedef {import('../../types/annotator').Anchor} Anchor
* @typedef {import('../../types/annotator').Annotator} Annotator
* @typedef {import('../../types/annotator').HypothesisWindow} HypothesisWindow
* @typedef {import('../../types/annotator').Integration} Integration
* @typedef {import('../../types/annotator').SidebarLayout} SidebarLayout
* @typedef {import('../../types/api').Selector} Selector
* @typedef {import('../sidebar').LayoutState} LayoutState
*/
// The viewport and controls for PDF.js start breaking down below about 670px
......@@ -22,6 +23,11 @@ import { PDFMetadata } from './pdf-metadata';
// is enough room. Otherwise, allow sidebar to overlap PDF
const MIN_PDF_WIDTH = 680;
/**
* Integration that works with PDF.js
*
* @implements {Integration}
*/
export class PDFIntegration {
/**
* @param {Annotator} annotator
......@@ -274,7 +280,7 @@ export class PDFIntegration {
* for the sidebar, and prompt PDF.js to re-render the PDF pages to scale
* within that resized container.
*
* @param {LayoutState} sidebarLayout
* @param {SidebarLayout} sidebarLayout
* @return {boolean} - True if side-by-side mode was activated
*/
fitSideBySide(sidebarLayout) {
......
......@@ -72,6 +72,36 @@
* @prop {(ann: AnnotationData) => Promise<Anchor[]>} anchor
*/
/**
* @typedef SidebarLayout
* @prop {boolean} expanded
* @prop {number} width
*/
/**
* Interface for document type/viewer integrations that handle all the details
* of supporting a specific document type (web page, PDF, ebook etc.).
*
* @typedef Integration
* @prop {(root: HTMLElement, selectors: Selector[]) => Promise<Range>} anchor -
* Attempt to resolve a set of serialized selectors to the corresponding content in the
* current document.
* @prop {(root: HTMLElement, range: Range) => Selector[]|Promise<Selector[]>} describe -
* Generate a list of serializable selectors which represent the content in
* `range`.
* @prop {() => HTMLElement} contentContainer -
* Return the main element that contains the document content. This is used
* by controls such as the bucket bar to know when the content might have scrolled.
* @prop {() => void} destroy -
* Clean up the integration and remove any event listeners, caches etc.
* @prop {(layout: SidebarLayout) => boolean} fitSideBySide -
* Attempt to resize the content so that it is visible alongside the sidebar.
* Returns `true` if the sidebar and content are displayed side-by-side or
* false otherwise.
* @prop {() => Promise<object>} getMetadata
* @prop {() => Promise<string>} uri - Return the URL of the currently loaded document
*/
/**
* @typedef DocumentMetadata
* @prop {string} title
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment