@readium/navigator-html-injectables 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +13 -0
- package/dist/index.js +3144 -0
- package/dist/index.umd.cjs +69 -0
- package/package.json +58 -0
- package/src/Loader.ts +85 -0
- package/src/comms/comms.ts +168 -0
- package/src/comms/index.ts +3 -0
- package/src/comms/keys.ts +42 -0
- package/src/comms/mid.ts +5 -0
- package/src/helpers/animation.ts +5 -0
- package/src/helpers/css.ts +16 -0
- package/src/helpers/document.ts +43 -0
- package/src/helpers/dom.ts +126 -0
- package/src/helpers/locator.ts +67 -0
- package/src/helpers/rect.ts +301 -0
- package/src/helpers/scrollSnapperHelper.ts +43 -0
- package/src/index.ts +3 -0
- package/src/modules/Decorator.ts +462 -0
- package/src/modules/Module.ts +23 -0
- package/src/modules/ModuleLibrary.ts +44 -0
- package/src/modules/Peripherals.ts +148 -0
- package/src/modules/index.ts +3 -0
- package/src/modules/setup/FixedSetup.ts +73 -0
- package/src/modules/setup/ReflowableSetup.ts +65 -0
- package/src/modules/setup/Setup.ts +131 -0
- package/src/modules/snapper/ColumnSnapper.ts +468 -0
- package/src/modules/snapper/ScrollSnapper.ts +168 -0
- package/src/modules/snapper/Snapper.ts +49 -0
- package/src/vendor/approx-string-match/LICENSE +21 -0
- package/src/vendor/approx-string-match/README.MD +1 -0
- package/src/vendor/approx-string-match/index.ts +362 -0
- package/src/vendor/hypothesis/README.MD +1 -0
- package/src/vendor/hypothesis/anchoring/api-types.ts +309 -0
- package/src/vendor/hypothesis/anchoring/html.ts +134 -0
- package/src/vendor/hypothesis/anchoring/match-quote.ts +163 -0
- package/src/vendor/hypothesis/anchoring/placeholder.ts +59 -0
- package/src/vendor/hypothesis/anchoring/text-range.ts +327 -0
- package/src/vendor/hypothesis/anchoring/trim-range.ts +220 -0
- package/src/vendor/hypothesis/anchoring/types.ts +377 -0
- package/src/vendor/hypothesis/anchoring/xpath.ts +164 -0
- package/src/vendor/hypothesis/tsconfig.json +33 -0
- package/src/vendor/hypothesis/types/shared.ts +40 -0
- package/types/src/Loader.d.ts +33 -0
- package/types/src/comms/comms.d.ts +40 -0
- package/types/src/comms/index.d.ts +3 -0
- package/types/src/comms/keys.d.ts +2 -0
- package/types/src/comms/mid.d.ts +1 -0
- package/types/src/helpers/animation.d.ts +1 -0
- package/types/src/helpers/css.d.ts +4 -0
- package/types/src/helpers/document.d.ts +8 -0
- package/types/src/helpers/dom.d.ts +15 -0
- package/types/src/helpers/locator.d.ts +2 -0
- package/types/src/helpers/rect.d.ts +10 -0
- package/types/src/helpers/scrollSnapperHelper.d.ts +5 -0
- package/types/src/index.d.ts +3 -0
- package/types/src/modules/Decorator.d.ts +43 -0
- package/types/src/modules/Module.d.ts +11 -0
- package/types/src/modules/ModuleLibrary.d.ts +5 -0
- package/types/src/modules/Peripherals.d.ts +39 -0
- package/types/src/modules/ReflowablePeripherals.d.ts +37 -0
- package/types/src/modules/index.d.ts +3 -0
- package/types/src/modules/setup/FixedSetup.d.ts +9 -0
- package/types/src/modules/setup/ReflowableSetup.d.ts +9 -0
- package/types/src/modules/setup/Setup.d.ts +17 -0
- package/types/src/modules/snapper/ColumnSnapper.d.ts +41 -0
- package/types/src/modules/snapper/ScrollSnapper.d.ts +16 -0
- package/types/src/modules/snapper/Snapper.d.ts +11 -0
- package/types/src/vendor/approx-string-match/index.d.ts +54 -0
- package/types/src/vendor/hypothesis/anchoring/api-types.d.ts +266 -0
- package/types/src/vendor/hypothesis/anchoring/html.d.ts +17 -0
- package/types/src/vendor/hypothesis/anchoring/match-quote.d.ts +30 -0
- package/types/src/vendor/hypothesis/anchoring/placeholder.d.ts +32 -0
- package/types/src/vendor/hypothesis/anchoring/text-range.d.ts +103 -0
- package/types/src/vendor/hypothesis/anchoring/trim-range.d.ts +17 -0
- package/types/src/vendor/hypothesis/anchoring/types.d.ts +102 -0
- package/types/src/vendor/hypothesis/anchoring/xpath.d.ts +15 -0
- package/types/src/vendor/hypothesis/types/shared.d.ts +32 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implementation of Myers' online approximate string matching algorithm [1],
|
|
3
|
+
* with additional optimizations suggested by [2].
|
|
4
|
+
*
|
|
5
|
+
* This has O((k/w) * n) expected-time where `n` is the length of the
|
|
6
|
+
* text, `k` is the maximum number of errors allowed (always <= the pattern
|
|
7
|
+
* length) and `w` is the word size. Because JS only supports bitwise operations
|
|
8
|
+
* on 32 bit integers, `w` is 32.
|
|
9
|
+
*
|
|
10
|
+
* As far as I am aware, there aren't any online algorithms which are
|
|
11
|
+
* significantly better for a wide range of input parameters. The problem can be
|
|
12
|
+
* solved faster using "filter then verify" approaches which first filter out
|
|
13
|
+
* regions of the text that cannot match using a "cheap" check and then verify
|
|
14
|
+
* the remaining potential matches. The verify step requires an algorithm such
|
|
15
|
+
* as this one however.
|
|
16
|
+
*
|
|
17
|
+
* The algorithm's approach is essentially to optimize the classic dynamic
|
|
18
|
+
* programming solution to the problem by computing columns of the matrix in
|
|
19
|
+
* word-sized chunks (ie. dealing with 32 chars of the pattern at a time) and
|
|
20
|
+
* avoiding calculating regions of the matrix where the minimum error count is
|
|
21
|
+
* guaranteed to exceed the input threshold.
|
|
22
|
+
*
|
|
23
|
+
* The paper consists of two parts, the first describes the core algorithm for
|
|
24
|
+
* matching patterns <= the size of a word (implemented by `advanceBlock` here).
|
|
25
|
+
* The second uses the core algorithm as part of a larger block-based algorithm
|
|
26
|
+
* to handle longer patterns.
|
|
27
|
+
*
|
|
28
|
+
* [1] G. Myers, “A Fast Bit-Vector Algorithm for Approximate String Matching
|
|
29
|
+
* Based on Dynamic Programming,” vol. 46, no. 3, pp. 395–415, 1999.
|
|
30
|
+
*
|
|
31
|
+
* [2] Šošić, M. (2014). An simd dynamic programming c/c++ library (Doctoral
|
|
32
|
+
* dissertation, Fakultet Elektrotehnike i računarstva, Sveučilište u Zagrebu).
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Represents a match returned by a call to `search`.
|
|
36
|
+
*/
|
|
37
|
+
export interface Match {
|
|
38
|
+
/** Start offset of match in text. */
|
|
39
|
+
start: number;
|
|
40
|
+
/** End offset of match in text. */
|
|
41
|
+
end: number;
|
|
42
|
+
/**
|
|
43
|
+
* The number of differences (insertions, deletions or substitutions) between
|
|
44
|
+
* the pattern and the approximate match in the text.
|
|
45
|
+
*/
|
|
46
|
+
errors: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Search for the closest matches for `pattern` in `text`.
|
|
50
|
+
*
|
|
51
|
+
* Returns all matches that have the lowest number of errors, or an empty
|
|
52
|
+
* array if no match was found with `maxErrors` or fewer errors.
|
|
53
|
+
*/
|
|
54
|
+
export default function search(text: string, pattern: string, maxErrors: number): Match[];
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import type { ClientAnnotationData } from '../types/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Type definitions for objects returned from the Hypothesis API.
|
|
4
|
+
*
|
|
5
|
+
* The canonical reference is the API documentation at
|
|
6
|
+
* https://h.readthedocs.io/en/latest/api-reference/
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Metadata specifying how to call an API route.
|
|
10
|
+
*/
|
|
11
|
+
export type RouteMetadata = {
|
|
12
|
+
/** HTTP method */
|
|
13
|
+
method: string;
|
|
14
|
+
/** URL template */
|
|
15
|
+
url: string;
|
|
16
|
+
/** Description of API route */
|
|
17
|
+
desc: string;
|
|
18
|
+
};
|
|
19
|
+
/** A nested map of API route name to route metadata. */
|
|
20
|
+
export type RouteMap = {
|
|
21
|
+
[key: string]: RouteMap | RouteMetadata;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Structure of the API index response (`/api`).
|
|
25
|
+
*/
|
|
26
|
+
export type IndexResponse = {
|
|
27
|
+
links: RouteMap;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Structure of the Hypothesis links response (`/api/links`).
|
|
31
|
+
*
|
|
32
|
+
* This is a map of link name (eg. "account.settings") to URL. The URL may
|
|
33
|
+
* include ":"-prefixed placeholders/variables.
|
|
34
|
+
*/
|
|
35
|
+
export type LinksResponse = Record<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Selector which indicates the time range within a video or audio file that
|
|
38
|
+
* an annotation refers to.
|
|
39
|
+
*/
|
|
40
|
+
export type MediaTimeSelector = {
|
|
41
|
+
type: 'MediaTimeSelector';
|
|
42
|
+
/** Offset from start of media in seconds. */
|
|
43
|
+
start: number;
|
|
44
|
+
/** Offset from start of media in seconds. */
|
|
45
|
+
end: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Selector which identifies a document region using the selected text plus
|
|
49
|
+
* the surrounding context.
|
|
50
|
+
*/
|
|
51
|
+
export type TextQuoteSelector = {
|
|
52
|
+
type: 'TextQuoteSelector';
|
|
53
|
+
exact: string;
|
|
54
|
+
prefix?: string;
|
|
55
|
+
suffix?: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Selector which identifies a document region using UTF-16 character offsets
|
|
59
|
+
* in the document body's `textContent`.
|
|
60
|
+
*/
|
|
61
|
+
export type TextPositionSelector = {
|
|
62
|
+
type: 'TextPositionSelector';
|
|
63
|
+
start: number;
|
|
64
|
+
end: number;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Selector which identifies a document region using XPaths and character offsets.
|
|
68
|
+
*/
|
|
69
|
+
export type RangeSelector = {
|
|
70
|
+
type: 'RangeSelector';
|
|
71
|
+
startContainer: string;
|
|
72
|
+
endContainer: string;
|
|
73
|
+
startOffset: number;
|
|
74
|
+
endOffset: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Selector which identifies the Content Document within an EPUB that an
|
|
78
|
+
* annotation was made in.
|
|
79
|
+
*/
|
|
80
|
+
export type EPUBContentSelector = {
|
|
81
|
+
type: 'EPUBContentSelector';
|
|
82
|
+
/**
|
|
83
|
+
* URL of the content document. This should be an absolute HTTPS URL if
|
|
84
|
+
* available, but may be relative to the root of the EPUB.
|
|
85
|
+
*/
|
|
86
|
+
url: string;
|
|
87
|
+
/**
|
|
88
|
+
* EPUB Canonical Fragment Identifier for the table of contents entry that
|
|
89
|
+
* corresponds to the content document.
|
|
90
|
+
*/
|
|
91
|
+
cfi?: string;
|
|
92
|
+
/** Title of the content document. */
|
|
93
|
+
title?: string;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Selector which identifies the page of a document that an annotation was made
|
|
97
|
+
* on.
|
|
98
|
+
*
|
|
99
|
+
* This selector is only applicable for document types where the association of
|
|
100
|
+
* content and page numbers can be done in a way that is independent of the
|
|
101
|
+
* viewer and display settings. This includes inherently paginated documents
|
|
102
|
+
* such as PDFs, but also content such as EPUBs when they include information
|
|
103
|
+
* about the location of page breaks in printed versions of a book. It does
|
|
104
|
+
* not include ordinary web pages or EPUBs without page break information
|
|
105
|
+
* however.
|
|
106
|
+
*/
|
|
107
|
+
export type PageSelector = {
|
|
108
|
+
type: 'PageSelector';
|
|
109
|
+
/** The zero-based index of the page in the document's page sequence. */
|
|
110
|
+
index: number;
|
|
111
|
+
/**
|
|
112
|
+
* Either the page number that is displayed on the page, or the 1-based
|
|
113
|
+
* number of the page in the document's page sequence, if the pages do not
|
|
114
|
+
* have numbers on them.
|
|
115
|
+
*/
|
|
116
|
+
label?: string;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Serialized representation of a region of a document which an annotation
|
|
120
|
+
* pertains to.
|
|
121
|
+
*/
|
|
122
|
+
export type Selector = TextQuoteSelector | TextPositionSelector | RangeSelector | EPUBContentSelector | MediaTimeSelector | PageSelector;
|
|
123
|
+
/**
|
|
124
|
+
* An entry in the `target` field of an annotation which identifies the document
|
|
125
|
+
* and region of the document that it refers to.
|
|
126
|
+
*/
|
|
127
|
+
export type Target = {
|
|
128
|
+
/** URI of the document */
|
|
129
|
+
source: string;
|
|
130
|
+
/** Region of the document */
|
|
131
|
+
selector?: Selector[];
|
|
132
|
+
};
|
|
133
|
+
export type UserInfo = {
|
|
134
|
+
display_name: string | null;
|
|
135
|
+
};
|
|
136
|
+
export type APIAnnotationData = {
|
|
137
|
+
/**
|
|
138
|
+
* The server-assigned ID for the annotation. This is only set once the
|
|
139
|
+
* annotation has been saved to the backend.
|
|
140
|
+
*/
|
|
141
|
+
id?: string;
|
|
142
|
+
references?: string[];
|
|
143
|
+
created: string;
|
|
144
|
+
flagged?: boolean;
|
|
145
|
+
group: string;
|
|
146
|
+
updated: string;
|
|
147
|
+
tags: string[];
|
|
148
|
+
text: string;
|
|
149
|
+
uri: string;
|
|
150
|
+
user: string;
|
|
151
|
+
hidden: boolean;
|
|
152
|
+
document: {
|
|
153
|
+
title: string;
|
|
154
|
+
};
|
|
155
|
+
permissions: {
|
|
156
|
+
read: string[];
|
|
157
|
+
update: string[];
|
|
158
|
+
delete: string[];
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* The document and region this annotation refers to.
|
|
162
|
+
*
|
|
163
|
+
* The Hypothesis API structure allows for multiple targets, but the h
|
|
164
|
+
* server only supports one target per annotation.
|
|
165
|
+
*/
|
|
166
|
+
target: Target[];
|
|
167
|
+
moderation?: {
|
|
168
|
+
flagCount: number;
|
|
169
|
+
};
|
|
170
|
+
links: {
|
|
171
|
+
/**
|
|
172
|
+
* A "bouncer" URL that takes the user to see the annotation in context
|
|
173
|
+
*/
|
|
174
|
+
incontext?: string;
|
|
175
|
+
/** URL to view the annotation by itself. */
|
|
176
|
+
html?: string;
|
|
177
|
+
};
|
|
178
|
+
user_info?: UserInfo;
|
|
179
|
+
};
|
|
180
|
+
export type Annotation = ClientAnnotationData & APIAnnotationData;
|
|
181
|
+
/**
|
|
182
|
+
* An annotation which has been saved to the backend and assigned an ID.
|
|
183
|
+
*/
|
|
184
|
+
export type SavedAnnotation = Annotation & {
|
|
185
|
+
id: string;
|
|
186
|
+
};
|
|
187
|
+
export type Profile = {
|
|
188
|
+
userid: string | null;
|
|
189
|
+
preferences: {
|
|
190
|
+
show_sidebar_tutorial?: boolean;
|
|
191
|
+
};
|
|
192
|
+
features: Record<string, boolean>;
|
|
193
|
+
user_info?: UserInfo;
|
|
194
|
+
};
|
|
195
|
+
export type Organization = {
|
|
196
|
+
name: string;
|
|
197
|
+
logo: string;
|
|
198
|
+
id: string;
|
|
199
|
+
default?: boolean;
|
|
200
|
+
};
|
|
201
|
+
export type GroupScopes = {
|
|
202
|
+
enforced: boolean;
|
|
203
|
+
uri_patterns: string[];
|
|
204
|
+
};
|
|
205
|
+
export type Group = {
|
|
206
|
+
/** The "pubid" of the group, unique per authority. */
|
|
207
|
+
id: string;
|
|
208
|
+
/** Fully-qualified ID with authority. */
|
|
209
|
+
groupid?: string;
|
|
210
|
+
type: 'private' | 'open';
|
|
211
|
+
/**
|
|
212
|
+
* Note: This field is nullable in the API, but we assign a default organization in the client.
|
|
213
|
+
*/
|
|
214
|
+
organization: Organization;
|
|
215
|
+
scopes: GroupScopes | null;
|
|
216
|
+
links: {
|
|
217
|
+
html?: string;
|
|
218
|
+
};
|
|
219
|
+
logo: string;
|
|
220
|
+
isMember: boolean;
|
|
221
|
+
isScopedToUri: boolean;
|
|
222
|
+
name: string;
|
|
223
|
+
canLeave: boolean;
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* All Groups have an `id`, which is a server-assigned identifier. This is the
|
|
227
|
+
* primary field used to identify a Group.
|
|
228
|
+
*
|
|
229
|
+
* In some cases, specifically LMS, it is necessary for an outside service to
|
|
230
|
+
* be able to specify its own identifier. This gets stored in the `groupid`
|
|
231
|
+
* field of a Group. Only some Groups have a `groupid`.
|
|
232
|
+
*
|
|
233
|
+
* Application logic operates on `id`s, but we may receive `groupid`s in some
|
|
234
|
+
* cases from outside sevices, e.g. the `changeFocusModeUser` RPC method.
|
|
235
|
+
*/
|
|
236
|
+
export type GroupIdentifier = NonNullable<Group['id'] | Group['groupid']>;
|
|
237
|
+
/**
|
|
238
|
+
* Query parameters for an `/api/search` API call.
|
|
239
|
+
*
|
|
240
|
+
* This type currently includes params that we've actually used.
|
|
241
|
+
*
|
|
242
|
+
* See https://h.readthedocs.io/en/latest/api-reference/#tag/annotations/paths/~1search/get
|
|
243
|
+
* for the complete list and usage of each.
|
|
244
|
+
*/
|
|
245
|
+
export type SearchQuery = {
|
|
246
|
+
limit?: number;
|
|
247
|
+
uri?: string[];
|
|
248
|
+
group?: string;
|
|
249
|
+
order?: string;
|
|
250
|
+
references?: string;
|
|
251
|
+
search_after?: string;
|
|
252
|
+
sort?: string;
|
|
253
|
+
/** Undocument param that causes replies to be returned in a separate `replies` field. */
|
|
254
|
+
_separate_replies?: boolean;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Response to an `/api/search` API call.
|
|
258
|
+
*
|
|
259
|
+
* See https://h.readthedocs.io/en/latest/api-reference/#tag/annotations/paths/~1search/get
|
|
260
|
+
*/
|
|
261
|
+
export type SearchResponse = {
|
|
262
|
+
total: number;
|
|
263
|
+
rows: Annotation[];
|
|
264
|
+
/** Undocumented property that is populated if `_separate_replies` query param was specified. */
|
|
265
|
+
replies?: Annotation[];
|
|
266
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MediaTimeSelector, RangeSelector, Selector, TextPositionSelector, TextQuoteSelector } from './api-types';
|
|
2
|
+
type Options = {
|
|
3
|
+
hint?: number;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Anchor a set of selectors.
|
|
7
|
+
*
|
|
8
|
+
* This function converts a set of selectors into a document range.
|
|
9
|
+
* It encapsulates the core anchoring algorithm, using the selectors alone or
|
|
10
|
+
* in combination to establish the best anchor within the document.
|
|
11
|
+
*
|
|
12
|
+
* @param root - The root element of the anchoring context
|
|
13
|
+
* @param selectors - The selectors to try
|
|
14
|
+
*/
|
|
15
|
+
export declare function anchor(root: Element, selectors: Selector[], options?: Options): Promise<Range>;
|
|
16
|
+
export declare function describe(root: Element, range: Range): (MediaTimeSelector | TextQuoteSelector | TextPositionSelector | RangeSelector)[];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type Match = {
|
|
2
|
+
/** Start offset of match in text */
|
|
3
|
+
start: number;
|
|
4
|
+
/** End offset of match in text */
|
|
5
|
+
end: number;
|
|
6
|
+
/**
|
|
7
|
+
* Score for the match between 0 and 1.0, where 1.0 indicates a perfect match
|
|
8
|
+
* for the quote and context.
|
|
9
|
+
*/
|
|
10
|
+
score: number;
|
|
11
|
+
};
|
|
12
|
+
type Context = {
|
|
13
|
+
/** Expected text before the quote */
|
|
14
|
+
prefix?: string;
|
|
15
|
+
/** Expected text after the quote */
|
|
16
|
+
suffix?: string;
|
|
17
|
+
/** Expected offset of match within text */
|
|
18
|
+
hint?: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Find the best approximate match for `quote` in `text`.
|
|
22
|
+
*
|
|
23
|
+
* @param text - Document text to search
|
|
24
|
+
* @param quote - String to find within `text`
|
|
25
|
+
* @param context - Context in which the quote originally appeared. This is
|
|
26
|
+
* used to choose the best match.
|
|
27
|
+
* @return `null` if no match exceeding the minimum quality threshold was found.
|
|
28
|
+
*/
|
|
29
|
+
export declare function matchQuote(text: string, quote: string, context?: Context): Match | null;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create or return a placeholder element for anchoring.
|
|
3
|
+
*
|
|
4
|
+
* In document viewers such as PDF.js which only render a subset of long
|
|
5
|
+
* documents at a time, it may not be possible to anchor annotations to the
|
|
6
|
+
* actual text in pages which are off-screen. For these non-rendered pages,
|
|
7
|
+
* a "placeholder" element is created in the approximate X/Y location (eg.
|
|
8
|
+
* middle of the page) where the content will appear. Any highlights for that
|
|
9
|
+
* page are then rendered inside the placeholder.
|
|
10
|
+
*
|
|
11
|
+
* When the viewport is scrolled to the non-rendered page, the placeholder
|
|
12
|
+
* is removed and annotations are re-anchored to the real content.
|
|
13
|
+
*
|
|
14
|
+
* @param container - The container element for the page or tile which is not
|
|
15
|
+
* rendered.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createPlaceholder(container: HTMLElement): Element;
|
|
18
|
+
/**
|
|
19
|
+
* Return true if a page/tile container has a placeholder.
|
|
20
|
+
*/
|
|
21
|
+
export declare function hasPlaceholder(container: HTMLElement): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Remove the placeholder element in `container`, if present.
|
|
24
|
+
*/
|
|
25
|
+
export declare function removePlaceholder(container: HTMLElement): void;
|
|
26
|
+
/**
|
|
27
|
+
* Return true if `node` is inside a placeholder element created with `createPlaceholder`.
|
|
28
|
+
*
|
|
29
|
+
* This is typically used to test if a highlight element associated with an
|
|
30
|
+
* anchor is inside a placeholder.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isInPlaceholder(node: Node): boolean;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When resolving a TextPosition, specifies the direction to search for the
|
|
3
|
+
* nearest text node if `offset` is `0` and the element has no text.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum ResolveDirection {
|
|
6
|
+
FORWARDS = 1,
|
|
7
|
+
BACKWARDS = 2
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Represents an offset within the text content of an element.
|
|
11
|
+
*
|
|
12
|
+
* This position can be resolved to a specific descendant node in the current
|
|
13
|
+
* DOM subtree of the element using the `resolve` method.
|
|
14
|
+
*/
|
|
15
|
+
export declare class TextPosition {
|
|
16
|
+
element: Element;
|
|
17
|
+
offset: number;
|
|
18
|
+
constructor(element: Element, offset: number);
|
|
19
|
+
/**
|
|
20
|
+
* Return a copy of this position with offset relative to a given ancestor
|
|
21
|
+
* element.
|
|
22
|
+
*
|
|
23
|
+
* @param parent - Ancestor of `this.element`
|
|
24
|
+
*/
|
|
25
|
+
relativeTo(parent: Element): TextPosition;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the position to a specific text node and offset within that node.
|
|
28
|
+
*
|
|
29
|
+
* Throws if `this.offset` exceeds the length of the element's text. In the
|
|
30
|
+
* case where the element has no text and `this.offset` is 0, the `direction`
|
|
31
|
+
* option determines what happens.
|
|
32
|
+
*
|
|
33
|
+
* Offsets at the boundary between two nodes are resolved to the start of the
|
|
34
|
+
* node that begins at the boundary.
|
|
35
|
+
*
|
|
36
|
+
* @param options.direction - Specifies in which direction to search for the
|
|
37
|
+
* nearest text node if `this.offset` is `0` and
|
|
38
|
+
* `this.element` has no text. If not specified an
|
|
39
|
+
* error is thrown.
|
|
40
|
+
*
|
|
41
|
+
* @throws {RangeError}
|
|
42
|
+
*/
|
|
43
|
+
resolve(options?: {
|
|
44
|
+
direction?: ResolveDirection;
|
|
45
|
+
}): {
|
|
46
|
+
node: Text;
|
|
47
|
+
offset: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Construct a `TextPosition` that refers to the `offset`th character within
|
|
51
|
+
* `node`.
|
|
52
|
+
*/
|
|
53
|
+
static fromCharOffset(node: Node, offset: number): TextPosition;
|
|
54
|
+
/**
|
|
55
|
+
* Construct a `TextPosition` representing the range start or end point (node, offset).
|
|
56
|
+
*
|
|
57
|
+
* @param node
|
|
58
|
+
* @param offset - Offset within the node
|
|
59
|
+
*/
|
|
60
|
+
static fromPoint(node: Node, offset: number): TextPosition;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Represents a region of a document as a (start, end) pair of `TextPosition` points.
|
|
64
|
+
*
|
|
65
|
+
* Representing a range in this way allows for changes in the DOM content of the
|
|
66
|
+
* range which don't affect its text content, without affecting the text content
|
|
67
|
+
* of the range itself.
|
|
68
|
+
*/
|
|
69
|
+
export declare class TextRange {
|
|
70
|
+
start: TextPosition;
|
|
71
|
+
end: TextPosition;
|
|
72
|
+
constructor(start: TextPosition, end: TextPosition);
|
|
73
|
+
/**
|
|
74
|
+
* Create a new TextRange whose `start` and `end` are computed relative to
|
|
75
|
+
* `element`. `element` must be an ancestor of both `start.element` and
|
|
76
|
+
* `end.element`.
|
|
77
|
+
*/
|
|
78
|
+
relativeTo(element: Element): TextRange;
|
|
79
|
+
/**
|
|
80
|
+
* Resolve this TextRange to a (DOM) Range.
|
|
81
|
+
*
|
|
82
|
+
* The resulting DOM Range will always start and end in a `Text` node.
|
|
83
|
+
* Hence `TextRange.fromRange(range).toRange()` can be used to "shrink" a
|
|
84
|
+
* range to the text it contains.
|
|
85
|
+
*
|
|
86
|
+
* May throw if the `start` or `end` positions cannot be resolved to a range.
|
|
87
|
+
*/
|
|
88
|
+
toRange(): Range;
|
|
89
|
+
/**
|
|
90
|
+
* Create a TextRange from a (DOM) Range
|
|
91
|
+
*/
|
|
92
|
+
static fromRange(range: Range): TextRange;
|
|
93
|
+
/**
|
|
94
|
+
* Create a TextRange representing the `start`th to `end`th characters in
|
|
95
|
+
* `root`
|
|
96
|
+
*/
|
|
97
|
+
static fromOffsets(root: Element, start: number, end: number): TextRange;
|
|
98
|
+
/**
|
|
99
|
+
* Return a new Range representing `range` trimmed of any leading or trailing
|
|
100
|
+
* whitespace
|
|
101
|
+
*/
|
|
102
|
+
static trimmedRange(range: Range): Range;
|
|
103
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return a new DOM Range that adjusts the start and end positions of `range` as
|
|
3
|
+
* needed such that:
|
|
4
|
+
*
|
|
5
|
+
* - `startContainer` and `endContainer` text nodes both contain at least one
|
|
6
|
+
* non-whitespace character within the Range's text content
|
|
7
|
+
* - `startOffset` and `endOffset` both reference non-whitespace characters,
|
|
8
|
+
* with `startOffset` immediately before the first non-whitespace character
|
|
9
|
+
* and `endOffset` immediately after the last
|
|
10
|
+
*
|
|
11
|
+
* Whitespace characters are those that are removed by `String.prototype.trim()`
|
|
12
|
+
*
|
|
13
|
+
* @param range - A DOM Range that whose `startContainer` and `endContainer` are
|
|
14
|
+
* both text nodes, and which contains at least one non-whitespace character.
|
|
15
|
+
* @throws {RangeError}
|
|
16
|
+
*/
|
|
17
|
+
export declare function trimRange(range: Range): Range;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module exports a set of classes for converting between DOM `Range`
|
|
3
|
+
* objects and different types of selectors. It is mostly a thin wrapper around a
|
|
4
|
+
* set of anchoring libraries. It serves two main purposes:
|
|
5
|
+
*
|
|
6
|
+
* 1. Providing a consistent interface across different types of anchors.
|
|
7
|
+
* 2. Insulating the rest of the code from API changes in the underlying anchoring
|
|
8
|
+
* libraries.
|
|
9
|
+
*/
|
|
10
|
+
import type { MediaTimeSelector, RangeSelector, TextPositionSelector, TextQuoteSelector } from './api-types';
|
|
11
|
+
/**
|
|
12
|
+
* Converts between `RangeSelector` selectors and `Range` objects.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RangeAnchor {
|
|
15
|
+
root: Node;
|
|
16
|
+
range: Range;
|
|
17
|
+
/**
|
|
18
|
+
* @param root - A root element from which to anchor.
|
|
19
|
+
* @param range - A range describing the anchor.
|
|
20
|
+
*/
|
|
21
|
+
constructor(root: Node, range: Range);
|
|
22
|
+
/**
|
|
23
|
+
* @param root - A root element from which to anchor.
|
|
24
|
+
* @param range - A range describing the anchor.
|
|
25
|
+
*/
|
|
26
|
+
static fromRange(root: Node, range: Range): RangeAnchor;
|
|
27
|
+
/**
|
|
28
|
+
* Create an anchor from a serialized `RangeSelector` selector.
|
|
29
|
+
*
|
|
30
|
+
* @param root - A root element from which to anchor.
|
|
31
|
+
*/
|
|
32
|
+
static fromSelector(root: Element, selector: RangeSelector): RangeAnchor;
|
|
33
|
+
toRange(): Range;
|
|
34
|
+
toSelector(): RangeSelector;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Converts between `TextPositionSelector` selectors and `Range` objects.
|
|
38
|
+
*/
|
|
39
|
+
export declare class TextPositionAnchor {
|
|
40
|
+
root: Element;
|
|
41
|
+
start: number;
|
|
42
|
+
end: number;
|
|
43
|
+
constructor(root: Element, start: number, end: number);
|
|
44
|
+
static fromRange(root: Element, range: Range): TextPositionAnchor;
|
|
45
|
+
static fromSelector(root: Element, selector: TextPositionSelector): TextPositionAnchor;
|
|
46
|
+
toSelector(): TextPositionSelector;
|
|
47
|
+
toRange(): Range;
|
|
48
|
+
}
|
|
49
|
+
type QuoteMatchOptions = {
|
|
50
|
+
/** Expected position of match in text. See `matchQuote`. */
|
|
51
|
+
hint?: number;
|
|
52
|
+
};
|
|
53
|
+
export type TextQuoteAnchorContext = {
|
|
54
|
+
prefix?: string;
|
|
55
|
+
suffix?: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Converts between `TextQuoteSelector` selectors and `Range` objects.
|
|
59
|
+
*/
|
|
60
|
+
export declare class TextQuoteAnchor {
|
|
61
|
+
root: Element;
|
|
62
|
+
exact: string;
|
|
63
|
+
context: TextQuoteAnchorContext;
|
|
64
|
+
/**
|
|
65
|
+
* @param root - A root element from which to anchor.
|
|
66
|
+
*/
|
|
67
|
+
constructor(root: Element, exact: string, context?: TextQuoteAnchorContext);
|
|
68
|
+
/**
|
|
69
|
+
* Create a `TextQuoteAnchor` from a range.
|
|
70
|
+
*
|
|
71
|
+
* Will throw if `range` does not contain any text nodes.
|
|
72
|
+
*/
|
|
73
|
+
static fromRange(root: Element, range: Range): TextQuoteAnchor;
|
|
74
|
+
static fromSelector(root: Element, selector: TextQuoteSelector): TextQuoteAnchor;
|
|
75
|
+
toSelector(): TextQuoteSelector;
|
|
76
|
+
toRange(options?: QuoteMatchOptions): Range;
|
|
77
|
+
toPositionAnchor(options?: QuoteMatchOptions): TextPositionAnchor;
|
|
78
|
+
}
|
|
79
|
+
export declare class MediaTimeAnchor {
|
|
80
|
+
root: Element;
|
|
81
|
+
/** Offset from start of media in seconds. */
|
|
82
|
+
start: number;
|
|
83
|
+
/** Offset from end of media in seconds. */
|
|
84
|
+
end: number;
|
|
85
|
+
constructor(root: Element, start: number, end: number);
|
|
86
|
+
/**
|
|
87
|
+
* Return a {@link MediaTimeAnchor} that represents a range, or `null` if
|
|
88
|
+
* no time range information is present on elements in the range.
|
|
89
|
+
*/
|
|
90
|
+
static fromRange(root: Element, range: Range): MediaTimeAnchor | null;
|
|
91
|
+
/**
|
|
92
|
+
* Convert this anchor to a DOM range.
|
|
93
|
+
*
|
|
94
|
+
* This returned range will start from the beginning of the element whose
|
|
95
|
+
* associated time range includes `start` and continue to the end of the
|
|
96
|
+
* element whose associated time range includes `end`.
|
|
97
|
+
*/
|
|
98
|
+
toRange(): Range;
|
|
99
|
+
static fromSelector(root: Element, selector: MediaTimeSelector): MediaTimeAnchor;
|
|
100
|
+
toSelector(): MediaTimeSelector;
|
|
101
|
+
}
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple XPath generator which can generate XPaths of the form
|
|
3
|
+
* /tag[index]/tag[index].
|
|
4
|
+
*
|
|
5
|
+
* @param node - The node to generate a path to
|
|
6
|
+
* @param root - Root node to which the returned path is relative
|
|
7
|
+
*/
|
|
8
|
+
export declare function xpathFromNode(node: Node, root: Node): string;
|
|
9
|
+
/**
|
|
10
|
+
* Finds an element node using an XPath relative to `root`
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* node = nodeFromXPath('/main/article[1]/p[3]', document.body)
|
|
14
|
+
*/
|
|
15
|
+
export declare function nodeFromXPath(xpath: string, root?: Element): Node | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clusters provide the client application a mechanism for categorizing
|
|
3
|
+
* annotations so that their drawn anchor highlights may be styled distinctively
|
|
4
|
+
* in the annotated document. An annotation can only belong to one cluster.
|
|
5
|
+
*/
|
|
6
|
+
export type HighlightCluster = 'other-content' | 'user-annotations' | 'user-highlights';
|
|
7
|
+
/**
|
|
8
|
+
* Annotation properties not present on API objects, but added by the client
|
|
9
|
+
*/
|
|
10
|
+
export type ClientAnnotationData = {
|
|
11
|
+
$cluster?: HighlightCluster;
|
|
12
|
+
/**
|
|
13
|
+
* Client-side identifier: set even if annotation does not have a
|
|
14
|
+
* server-provided `id` (i.e. is unsaved)
|
|
15
|
+
*/
|
|
16
|
+
$tag: string;
|
|
17
|
+
/**
|
|
18
|
+
* Flag indicating whether waiting for the annotation to anchor timed out
|
|
19
|
+
*/
|
|
20
|
+
$anchorTimeout?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Flag indicating that this annotation was created using the "Highlight" button,
|
|
23
|
+
* as opposed to "Annotate".
|
|
24
|
+
*/
|
|
25
|
+
$highlight?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Flag indicating that this annotation was not found in the document.
|
|
28
|
+
* It is initially `undefined` while anchoring is in progress and then set to
|
|
29
|
+
* `true` if anchoring failed or `false` if it succeeded.
|
|
30
|
+
*/
|
|
31
|
+
$orphan?: boolean;
|
|
32
|
+
};
|