Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] export annotation set [Round 2] #2704

Merged
merged 37 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
403a942
update readium annotation set model [skip ci]
panaC Dec 11, 2024
bf63fe5
annotation import FIFO queue from main to reader process
panaC Dec 12, 2024
0429d08
update json schema selector
panaC Dec 12, 2024
fff4963
apache-annotator
panaC Dec 13, 2024
6fed198
lint and revert unused addAnnotationToReaderPublicatrion action previ…
panaC Dec 13, 2024
effd92e
fix seachCachePublicationResources from search to ReaderRootState at …
panaC Dec 13, 2024
c06ae34
lint and type fixes on the third-party apache-annotator lib
panaC Dec 13, 2024
05e582d
[skip ci]
panaC Dec 13, 2024
c993d56
set resourceCache to a dedicated file
panaC Dec 16, 2024
e4268a0
apache-annotator remove .js extension and fix type linting
panaC Dec 16, 2024
0304776
export annotation [skip ci]
panaC Dec 16, 2024
1c85520
import annotation
panaC Dec 16, 2024
cef265c
add textQuote in import process [skip ci]
panaC Dec 16, 2024
e6990c0
Merge branch 'develop' into feat/export-annotation-2
panaC Dec 17, 2024
87bdedc
add reader lock protection for importAnnotationSet function
panaC Dec 17, 2024
4245dc7
fix: add actionAcrossRenderer to dispatch action from renderer to
panaC Dec 18, 2024
c284410
fixes importQueue shift first elem immutability
panaC Dec 18, 2024
6a7bc53
remove unused addAnnotationToReaderPublication action
panaC Dec 18, 2024
69f4c91
lint and change xmlDom xhtml root to document.body @danielweck need …
panaC Dec 18, 2024
cd89bf0
when annotation import add locatorExtended.locations info (rangeInfo and
panaC Dec 18, 2024
a3fa129
Merge branch 'develop' into feat/export-annotation-2
danielweck Dec 20, 2024
7cf31fa
fix: add cssSelector and progressionSelector, and apply it to
panaC Dec 20, 2024
7738eab
fix: old annotation imported from updated annotation, now update the …
panaC Dec 30, 2024
b3a39cd
fix: import dialog labels
panaC Dec 30, 2024
c9184f7
fixes en/fr i18n annotation dialog
panaC Dec 30, 2024
8e9bb59
up: origin label annotation import modal
panaC Dec 30, 2024
c4b4516
Merge branch 'develop' into feat/export-annotation-2
danielweck Dec 30, 2024
29d0b52
Merge branch 'develop' into feat/export-annotation-2
danielweck Dec 30, 2024
8271ae4
Merge branch 'develop' into feat/export-annotation-2
danielweck Jan 8, 2025
a1de16a
Merge branch 'develop' into feat/export-annotation-2
danielweck Jan 29, 2025
fee85e7
fix: guard against undefined/null TextQuoteSelector during annotation…
danielweck Jan 29, 2025
71874f3
removed range normalisation as this can modify the original text boun…
danielweck Jan 29, 2025
d4a413f
added code comments about DOM Range document order (start/end points)…
danielweck Jan 29, 2025
ea00f54
[skip ci] added code comments about DOM Range document order contract
danielweck Jan 29, 2025
8aa456b
Merge branch 'develop' into feat/export-annotation-2
danielweck Jan 30, 2025
72132fd
Merge branch 'develop' into feat/export-annotation-2
danielweck Jan 31, 2025
3abeaf0
English localisation improvements
danielweck Jan 31, 2025
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
7 changes: 7 additions & 0 deletions src/common/models/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ export interface WithDestination {
destination: WindowReaderDestination;
}

export interface AcrossRenderer {
sendActionAcrossRenderer: boolean;
}

// tslint:disable-next-line: max-line-length
export interface ActionWithSender<Type extends string = string, Payload = undefined, Meta = undefined> extends Action<Type, Payload, Meta>, WithSender {
}

export interface ActionWithDestination<Type extends string = string, Payload = undefined, Meta = undefined> extends Action<Type, Payload, Meta>, WithDestination {
}

export interface ActionAcrossRenderer<Type extends string = string, Payload = undefined, Meta = undefined> extends Action<Type, Payload, Meta>, AcrossRenderer {
}
269 changes: 143 additions & 126 deletions src/common/readium/annotation/annotationModel.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@
import Ajv from "ajv";
import addFormats from "ajv-formats";

export interface IReadiumAnnotationModel {
export interface IReadiumAnnotationSet {
"@context": "http://www.w3.org/ns/anno.jsonld";
id: string;
type: "AnnotationSet";
generator?: Generator;
generated?: string;
title?: string;
about: About;
items: IReadiumAnnotation[];
}

export interface IReadiumAnnotation {
"@context": "http://www.w3.org/ns/anno.jsonld";
id: string;
created: string;
Expand Down Expand Up @@ -39,15 +50,38 @@ export interface IReadiumAnnotationModel {
page?: string;
};
selector: Array<(
ITextQuoteSelector
| IProgressionSelector
| IDomRangeSelector
| IFragmentSelector
ISelector
// ITextQuoteSelector
// | ITextPositionSelector
// | IFragmentSelector
)>;
};
}

export interface ITextQuoteSelector {
export interface ISelector<T extends ISelector = undefined> {
type: string;
refinedBy?: T;
}

/**
{
"type": "TextPositionSelector",
"start": 50,
"end": 55
}
*/
export interface ITextPositionSelector extends ISelector {
type: "TextPositionSelector",
start: number,
end: number,
}
export function isTextPositionSelector(a: any): a is ITextPositionSelector {
return typeof a === "object" && a.type === "TextPositionSelector"
&& typeof a.start === "number"
&& typeof a.end === "number";
}

export interface ITextQuoteSelector extends ISelector {
type: "TextQuoteSelector";
exact: string;
prefix: string;
Expand All @@ -60,7 +94,7 @@ export function isTextQuoteSelector(a: any): a is ITextQuoteSelector {
&& typeof a.suffix === "string";
}

export interface IProgressionSelector {
export interface IProgressionSelector extends ISelector {
type: "ProgressionSelector";
value: number;
}
Expand All @@ -69,27 +103,39 @@ export function isProgressionSelector(a: any): a is IProgressionSelector {
&& typeof a.value === "number";
}

export interface IDomRangeSelector {
type: "DomRangeSelector";
startContainerElementCssSelector: string;
startContainerChildTextNodeIndex: number;
startOffset: number;
endContainerElementCssSelector: string;
endContainerChildTextNodeIndex: number;
endOffset: number;
export interface ICssSelector<T extends ISelector = any> extends ISelector<T> {
type: "CssSelector";
value: string;
}
export function isDomRangeSelector(a: any): a is IDomRangeSelector {
return typeof a === "object"
&& a.type === "DomRangeSelector"
&& typeof a.startContainerElementCssSelector === "string"
&& typeof a.startContainerChildTextNodeIndex === "number"
&& typeof a.startOffset === "number"
&& typeof a.endContainerElementCssSelector === "string"
&& typeof a.endContainerChildTextNodeIndex === "number"
&& typeof a.endOffset === "number";
export function isCssSelector(a: any): a is ICssSelector<undefined> {
return typeof a === "object" && a.type === "CssSelector"
&& typeof a.value === "string";
}

export interface IFragmentSelector {
// not used anymore
// internal DOMRange selector not shared across annotation selector
// We prefer EPUB-CFI nowadays when official library will be choosen
// export interface IDomRangeSelector {
// type: "DomRangeSelector";
// startContainerElementCssSelector: string;
// startContainerChildTextNodeIndex: number;
// startOffset: number;
// endContainerElementCssSelector: string;
// endContainerChildTextNodeIndex: number;
// endOffset: number;
// }
// export function isDomRangeSelector(a: any): a is IDomRangeSelector {
// return typeof a === "object"
// && a.type === "DomRangeSelector"
// && typeof a.startContainerElementCssSelector === "string"
// && typeof a.startContainerChildTextNodeIndex === "number"
// && typeof a.startOffset === "number"
// && typeof a.endContainerElementCssSelector === "string"
// && typeof a.endContainerChildTextNodeIndex === "number"
// && typeof a.endOffset === "number";
// }

export interface IFragmentSelector extends ISelector {
type: "FragmentSelector";
conformsTo: string;
value: string;
Expand All @@ -101,6 +147,14 @@ export function isFragmentSelector(a: any): a is IFragmentSelector {
&& typeof a.value === "string";
}

export interface ICFIFragmentSelector extends IFragmentSelector {
conformsTo: "http://www.idpf.org/epub/linking/cfi/epub-cfi.html",
}
export function isCFIFragmentSelector(a: any): a is ICFIFragmentSelector {
return isFragmentSelector(a)
&& a.conformsTo === "http://www.idpf.org/epub/linking/cfi/epub-cfi.html";
}

interface Generator {
id: string;
type: string;
Expand All @@ -117,20 +171,9 @@ interface About {
"dc:date"?: string;
}

export interface IReadiumAnnotationModelSet {
"@context": "http://www.w3.org/ns/anno.jsonld";
id: string;
type: "AnnotationSet";
generator?: Generator;
generated?: string;
title?: string;
about: About;
items: IReadiumAnnotationModel[];
}

export const readiumAnnotationModelSetJSONSchema3 = {
export const readiumAnnotationSetSchema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IReadiumAnnotationModelSet",
"title": "IReadiumAnnotationSet",
"type": "object",
"properties": {
"@context": {
Expand Down Expand Up @@ -214,15 +257,15 @@ export const readiumAnnotationModelSetJSONSchema3 = {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/IReadiumAnnotationModel",
"$ref": "#/definitions/IReadiumAnnotation",
},
},
},
"required": ["@context", "id", "type", "about", "items"],
"definitions": {
"IReadiumAnnotationModel": {
"IReadiumAnnotation": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IReadiumAnnotationModelSet",
"title": "IReadiumAnnotationSet",
"type": "object",
"properties": {
"@context": {
Expand Down Expand Up @@ -340,17 +383,14 @@ export const readiumAnnotationModelSetJSONSchema3 = {
"items": {
"oneOf": [
{
"$ref": "#/definitions/ITextQuoteSelector",
},
{
"$ref": "#/definitions/IProgressionSelector",
},
{
"$ref": "#/definitions/IDomRangeSelector",
},
{
"$ref": "#/definitions/IFragmentSelector",
"$ref": "#/definitions/Selector",
},
// {
// "$ref": "#/definitions/ITextPositionSelector",
// },
// {
// "$ref": "#/definitions/IFragmentSelector",
// },
],
},
},
Expand All @@ -360,97 +400,74 @@ export const readiumAnnotationModelSetJSONSchema3 = {
},
"required": ["@context", "id", "created", "type", "target"],
},
"ITextQuoteSelector": {
"Selector": {
"type": "object",
"properties": {
"type": {
"const": "TextQuoteSelector",
},
"exact": {
"type": "string",
},
"prefix": {
"type": "string",
},
"suffix": {
"type": "string",
},
},
"required": ["type", "exact", "prefix", "suffix"],
},
"IProgressionSelector": {
"type": "object",
"properties": {
"type": {
"const": "ProgressionSelector",
},
"value": {
"type": "number",
},
},
"required": ["type", "value"],
},
"IDomRangeSelector": {
"type": "object",
"properties": {
"type": {
"const": "DomRangeSelector",
},
"startContainerElementCssSelector": {
"type": "string",
},
"startContainerChildTextNodeIndex": {
"type": "number",
},
"startOffset": {
"type": "number",
},
"endContainerElementCssSelector": {
"type": "string",
},
"endContainerChildTextNodeIndex": {
"type": "number",
},
"endOffset": {
"type": "number",
},
},
"required": [
"type",
"startContainerElementCssSelector",
"startContainerChildTextNodeIndex",
"startOffset",
"endContainerElementCssSelector",
"endContainerChildTextNodeIndex",
"endOffset",
],
},
"IFragmentSelector": {
"type": "object",
"properties": {
"type": {
"const": "FragmentSelector",
},
"conformsTo": {
"type": "string",
},
"value": {
"type": "string",
},
},
"required": ["type", "conformsTo", "value"],
"required": ["type"],
},
// "ITextQuoteSelector": {
// "type": "object",
// "properties": {
// "type": {
// "const": "TextQuoteSelector",
// },
// "exact": {
// "type": "string",
// },
// "prefix": {
// "type": "string",
// },
// "suffix": {
// "type": "string",
// },
// },
// "required": ["type", "exact", "prefix", "suffix"],
// },
// "ITextPositionSelector": {
// "type": "object",
// "properties": {
// "type": {
// "const": "TextPositionSelector",
// },
// "start": {
// "type": "number",
// },
// "end": {
// "type": "number",
// },
// },
// "required": ["type", "start", "end"],
// },
// "IFragmentSelector": {
// "type": "object",
// "properties": {
// "type": {
// "const": "FragmentSelector",
// },
// "conformsTo": {
// "type": "string",
// },
// "value": {
// "type": "string",
// },
// },
// "required": ["type", "conformsTo", "value"],
// },
},
};


export let __READIUM_ANNOTATION_AJV_ERRORS = "";
export function isIReadiumAnnotationModelSet(data: any): data is IReadiumAnnotationModelSet {
export function isIReadiumAnnotationSet(data: any): data is IReadiumAnnotationSet {

const ajv = new Ajv();
addFormats(ajv);

const valid = ajv.validate(readiumAnnotationModelSetJSONSchema3, data);
const valid = ajv.validate(readiumAnnotationSetSchema, data);

__READIUM_ANNOTATION_AJV_ERRORS = ajv.errors?.length ? JSON.stringify(ajv.errors, null, 2) : "";

Expand Down
Loading
Loading