├── .gitattributes ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── hast-annotations-match ├── add-parent-props.js ├── add-props-to-node.js ├── css-selector.js ├── full-html-schema.json ├── generate-full-html-schema.js ├── get-node.js ├── index.js ├── process-positions.js ├── process-quotations.js ├── range-selector.js ├── render-templates.js └── simple-xpath-selector.js ├── index.js ├── logger.js ├── package-lock.json ├── package.json ├── tap-snapshots ├── tests-index.js-TAP.test.js └── tests │ └── index.js.test.cjs └── tests ├── fixtures ├── annotations-template.json ├── css-single.annotations.json ├── css-single.input.html ├── css-single.output.html ├── fragment-multibody.annotations.json ├── fragment-multibody.input.html ├── fragment-multibody.output.html ├── poetry-linebreaks.annotations.json ├── poetry-linebreaks.input.html ├── poetry-linebreaks.output.html ├── range.annotations.json ├── range.input.html ├── range.output.html ├── refinedby.annotations.json ├── refinedby.input.html ├── refinedby.output.html ├── template.html ├── text-position-values.reference.txt ├── text-position.annotations.json ├── text-position.input.html ├── text-position.output.html ├── text-position.string.reference.txt ├── text-quote.annotations.json ├── text-quote.input.html ├── text-quote.output.html ├── xpath-single.annotations.json ├── xpath-single.input.html └── xpath-single.output.html └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: npm ci 27 | - run: npm run build --if-present 28 | - run: npm test 29 | - uses: codecov/codecov-action@v1 30 | with: 31 | fail_ci_if_error: false # optional (default = false) 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `rehype-annotate` 2 | 3 | ## Version 1.0 and ESM support 4 | 5 | With version 1.0+ this module is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): Node 12+ is needed to use it and it must be imported instead of required. 6 | 7 | ## Introduction 8 | 9 | This [`rehype`](https://github.com/rehypejs/rehype) plugin matches [W3C-style annotations](https://www.w3.org/TR/annotation-model/) to their targets in the parsed HTML file. It wraps text range selections in `mark` elements and adds attributes and hooks to matched locations that can be used in other processors or browser scripts to implement further behaviours. 10 | 11 | Note: this modifies the original tree and in some cases can add class attributes. Make sure to sanitise the tree afterwards. 12 | 13 | The script _does not_ embed annotation-provided styles, although that is on the roadmap. We do assign the values of the `styleClass` property to the annotated nodes so the client can provide their own stylesheet. 14 | 15 | ## License 16 | 17 | Apache 2.0 18 | 19 | ## Install 20 | 21 | We haven't yet published this package on `npm` but you can install it directly from the GitHub repository. 22 | 23 | [`npm`](https://docs.npmjs.com/cli/install): 24 | 25 | ```sh 26 | npm install RebusFoundation/rehype-annotate 27 | ``` 28 | 29 | ## Use 30 | 31 | `rehype-annotate` should be used as a `rehype` or `unified` plugin to match annotations to a `hast` syntax tree. 32 | 33 | ```js 34 | const vfile = require("to-vfile"); 35 | const unified = require("unified"); 36 | const annotate = require("rehype-annotate"); 37 | const parse = require("rehype-parse"); 38 | const stringify = require("rehype-stringify"); 39 | const report = require("vfile-reporter"); 40 | const glob = require("glob"); 41 | const path = require("path"); 42 | 43 | async function process(file, options) { 44 | return unified() 45 | .use(parse) 46 | .use(annotate, options) 47 | .use(stringify) 48 | .process(await vfile.read(file)); 49 | } 50 | 51 | const options = { 52 | // Should be an array of W3C Web Annotations 53 | annotations: require("./path/to/annotations/json"), 54 | // the base url for the original html 55 | url: "https://syndicated.example.com/annotated.html", 56 | // the canonical url for the html 57 | canonical: "https://example.org/annotated.html", 58 | }; 59 | 60 | process("path/to/example/htmlfile.html", options) 61 | .then((file) => { 62 | console.log(report(file)); 63 | console.log(String(file)); 64 | }) 65 | .catch((err) => console.error(err)); 66 | ``` 67 | 68 | The above code will print whatever issues are found out to the console, followed by the processed HTML. 69 | 70 | The `file.data.annotations` property will contain the annotations that have been matched to the HTML, in the order that the appear in the HTML file itself. 71 | 72 | ## API 73 | 74 | ### `processor.use(annotate[, options])` 75 | 76 | Configure `processor` to modify the [**hast**][hast] syntax tree to match annotations to their target locations in the HTML. 77 | 78 | The following attributes are added when an element node is matched by a selector: 79 | 80 | - `data-annotation-id`: the id of the matched annotation 81 | - `data-annotation-motivation`: space-separated list of the motivations from the annotation [`motivation`](https://www.w3.org/TR/annotation-model/#motivation-and-purpose) property. 82 | - `data-annotation-purpose` space-separated list of the purposes from the annotation _body's_ [`purpose`](https://www.w3.org/TR/annotation-model/#motivation-and-purpose) property. 83 | - `class` the value of the annotation's [`styleClass`](https://www.w3.org/TR/annotation-model/#styles) property is added when present. 84 | 85 | #### Example (single node match): 86 | 87 | If the source HTML is as follows: 88 | 89 | ```html 90 |

Stirs ending exceeding fond muster fall Bagshot.

91 | ``` 92 | 93 | And `rehype-annotate` is run with the following annotation: 94 | 95 | ```json 96 | { 97 | "id": "http://example.com/annotations1", 98 | "type": "Annotation", 99 | "motivation": "bookmarking", 100 | "creator": { 101 | "id": "http://example.org/user1", 102 | "type": "Person", 103 | "name": "A. Person", 104 | "nickname": "user1" 105 | }, 106 | "created": "2015-10-13T13:00:00Z", 107 | "stylesheet": { 108 | "id": "http://example.org/stylesheet1", 109 | "type": "CssStylesheet" 110 | }, 111 | "body": [ 112 | { 113 | "type": "TextualBody", 114 | "purpose": "tagging", 115 | "value": "love" 116 | }, 117 | { 118 | "type": "TextualBody", 119 | "value": "

j'adore !

", 120 | "format": "text/html", 121 | "language": "fr", 122 | "purpose": "describing" 123 | } 124 | ], 125 | "target": { 126 | "source": "https://example.com/tests/fixtures/fragment-multibody.input.html", 127 | "styleClass": "Bookmarked", 128 | "selector": { 129 | "type": "FragmentSelector", 130 | "value": "test-id" 131 | } 132 | } 133 | } 134 | ``` 135 | 136 | Then the result should be (provided the `url` or `canonical` options match the `source`): 137 | 138 | ```html 139 |

146 | Stirs ending exceeding fond muster fall Bagshot. 147 |

148 | ``` 149 | 150 | #### Example (text range match): 151 | 152 | If the source HTML is as follows: 153 | 154 | ```html 155 |

156 | Resilient Garulf key quest abandon knives lifted niceties tonight disappeared 157 | strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes 158 | Shadowfax nearly lesser south deceive hates 22nd missing others! 159 |

160 | ``` 161 | 162 | And `rehype-annotate` is run with the following annotation: 163 | 164 | ```json 165 | { 166 | "id": "http://example.com/annotations1", 167 | "type": "Annotation", 168 | "motivation": "highlighting", 169 | "created": "2015-10-13T13:00:00Z", 170 | "body": [ 171 | { 172 | "type": "TextualBody", 173 | "value": "

j'adore !

", 174 | "format": "text/html", 175 | "language": "fr", 176 | "purpose": "commenting" 177 | } 178 | ], 179 | "target": { 180 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 181 | "styleClass": "Bookmarked", 182 | "selector": { 183 | "type": "TextQuoteSelector", 184 | "exact": "Resilient Garulf key quest abandon knives" 185 | } 186 | } 187 | } 188 | ``` 189 | 190 | Then the result should be (provided the `url` or `canonical` options match the `source`): 191 | 192 | ```html 193 |

194 | Resilient Garulf key quest abandon knives 201 | lifted niceties tonight disappeared strongest plates. Farthing ginger large. 202 | Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd 203 | missing others! 204 |

205 | ``` 206 | 207 | #### `options` 208 | 209 | ##### `options.annotations` 210 | 211 | An array of annotations that conform to the [W3C Web Annotations Data Model](https://www.w3.org/TR/annotation-model/). See note below on selector support. 212 | 213 | ##### `options.canonical` and `options.url` 214 | 215 | The annotation is only matched to the html source if the `annotation.target.source` property matches either `canonical` or `url`. 216 | 217 | ## Selector Support 218 | 219 | - `CssSelector`: limited to the selectors supported by [`hast-util-select`](https://github.com/syntax-tree/hast-util-select#support) 220 | - `XPathSelector`: because `rehype`/`hast` doesn't come with built-in `xpath` support, these selectors only work when they are very simple. E.g. `/html/body/p[1]` 221 | - `FragmentSelector`: supports only HTML fragment ids. 222 | - `RangeSelector`: supported when both `startSelector` and `endSelector` resolve to element nodes. 223 | - `TextQuoteSelector`: implementation is loosely based on the excellent [`dom-anchor-text-quote`](https://github.com/tilgovi/dom-anchor-text-quote) by Randall Leeds. 224 | - `TextPositionSelector` 225 | 226 | For performance reasons text quote and text position selectors that overlap each other in the document are not supported. 227 | 228 | ### `refinedBy` 229 | 230 | You can use the `refinedBy` property on a selector that resolves to a single element node (`CssSelector`, `XPathSelector`, `FragmentSelector`) to create a new scope or root for a another selector, including the `TextPositionSelector` or the `TextQuoteSelector`. 231 | -------------------------------------------------------------------------------- /hast-annotations-match/add-parent-props.js: -------------------------------------------------------------------------------- 1 | import { find, svg } from "property-information"; 2 | import pixelWidth from "string-pixel-width"; 3 | import toString from "hast-util-to-string"; 4 | 5 | /* 6 | ## Props 7 | * `data-annotation-id` 8 | * `data-selector-index`: index of mark in total number of marks for this selector 9 | * `data-annotation-motivation`: annotations motivations 10 | * `class` : styleClass 11 | * `data-annotation-purpose`: body purposes 12 | */ 13 | const props = [ 14 | "x", 15 | "y", 16 | "width", 17 | "height", 18 | "textLength", 19 | "font-size", 20 | "data-annotation-x", 21 | "data-annotation-y", 22 | "data-annotation-width", 23 | "data-annotation-height", 24 | "data-annotation-offset", 25 | "data-annotation-highlight", 26 | "data-annotation-transform", 27 | "transform", 28 | ]; 29 | const attributes = {}; 30 | for (const prop of props) { 31 | attributes[prop] = find(svg, prop).property; 32 | } 33 | 34 | export function addParentProps(svg, node, parent) { 35 | if (!svg) return; 36 | const fontSize = Number.parseFloat( 37 | parent.properties[attributes["font-size"]] || 16 38 | ); 39 | const parentPixelWidth = pixelWidth(toString(parent), { 40 | size: fontSize, 41 | font: "helvetica", 42 | }); 43 | const nodePixelWidth = pixelWidth(toString(node), { 44 | size: fontSize, 45 | font: "helvetica", 46 | }); 47 | // const offset = parentLength - nodeLength; 48 | const width = Number.parseFloat( 49 | parent.properties[attributes.textLength] || parentPixelWidth 50 | ); 51 | const nodeWidth = (nodePixelWidth / parentPixelWidth) * width; 52 | const offsetWidth = width - nodeWidth; 53 | const height = fontSize + 40; 54 | const x = Number.parseFloat(parent.properties[attributes.x] || 0); 55 | const y = 56 | Number.parseFloat(parent.properties[attributes.y] || 0) - 20 - fontSize; 57 | node.properties[attributes["data-annotation-x"]] = String( 58 | x + offsetWidth - 20 59 | ); 60 | node.properties[attributes["data-annotation-y"]] = String(y); 61 | node.properties[attributes["data-annotation-width"]] = String(nodeWidth + 40); 62 | node.properties[attributes["data-annotation-height"]] = String(height); 63 | node.properties[attributes["data-annotation-transform"]] = 64 | node.properties[attributes.transform]; 65 | } 66 | -------------------------------------------------------------------------------- /hast-annotations-match/add-props-to-node.js: -------------------------------------------------------------------------------- 1 | import { find, html } from "property-information"; 2 | 3 | /* 4 | ## Props 5 | * `data-annotation-id` 6 | * `data-selector-index`: index of mark in total number of marks for this selector 7 | * `data-annotation-motivation`: annotations motivations 8 | * `class` : styleClass 9 | * `data-annotation-purpose`: body purposes 10 | */ 11 | const props = [ 12 | "data-annotation-id", 13 | "data-controller", 14 | "data-annotation-motivation", 15 | "class", 16 | "data-annotation-purpose", 17 | "data-annotation-type", 18 | "data-target", 19 | ]; 20 | const attributes = {}; 21 | for (const prop of props) { 22 | attributes[prop] = find(html, prop).property; 23 | } 24 | 25 | export function addPropsToNode(node, annotation) { 26 | // console.log("does this get called?: ", node, annotation); 27 | const { target } = annotation; 28 | const { body = [] } = annotation; 29 | let purposes = body.map((item) => item.purpose); 30 | purposes = [].concat(...purposes); 31 | node.properties[attributes["data-annotation-id"]] = annotation.id; 32 | node.properties[attributes["data-annotation-motivation"]] = [] 33 | .concat(annotation.motivation) 34 | .join(" ,"); 35 | if (target.styleClass) { 36 | const classes = node.properties[attributes.class] || []; 37 | node.properties[attributes.class] = classes 38 | .concat(target.styleClass) 39 | .filter((item) => item); 40 | } 41 | if (purposes.length !== 0) { 42 | node.properties[attributes["data-annotation-purpose"]] = purposes; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /hast-annotations-match/css-selector.js: -------------------------------------------------------------------------------- 1 | import { select } from "hast-util-select"; 2 | import { addPropsToNode } from "./add-props-to-node.js"; 3 | 4 | /** 5 | * 6 | * @param {{tree: Object, value: string, annotation: Object, addProps: undefined | boolean}} param0 - selector options 7 | */ 8 | export function nodeSelector({ tree, value, annotation, addProps = true }) { 9 | const node = select(value, tree); 10 | if (node && addProps) { 11 | addPropsToNode(node, annotation); 12 | } 13 | return node; 14 | } 15 | -------------------------------------------------------------------------------- /hast-annotations-match/full-html-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "strip": ["script", "object", "applet", "foreignObject"], 3 | "clobberPrefix": "user-content-", 4 | "clobber": ["name", "id"], 5 | "ancestors": { 6 | "li": ["ol", "ul"], 7 | "tbody": ["table"], 8 | "tfoot": ["table"], 9 | "thead": ["table"], 10 | "td": ["table"], 11 | "th": ["table"], 12 | "tr": ["table"] 13 | }, 14 | "protocols": { 15 | "href": ["http", "https", "mailto", "xmpp", "irc", "ircs"], 16 | "cite": ["http", "https"], 17 | "src": ["http", "https"], 18 | "longDesc": ["http", "https"] 19 | }, 20 | "tagNames": [ 21 | "a", 22 | "abbr", 23 | "acronym", 24 | "address", 25 | "area", 26 | "article", 27 | "aside", 28 | "audio", 29 | "b", 30 | "bdi", 31 | "bdo", 32 | "big", 33 | "blink", 34 | "blockquote", 35 | "body", 36 | "br", 37 | "button", 38 | "canvas", 39 | "caption", 40 | "center", 41 | "cite", 42 | "code", 43 | "col", 44 | "colgroup", 45 | "content", 46 | "data", 47 | "datalist", 48 | "dd", 49 | "decorator", 50 | "del", 51 | "details", 52 | "dfn", 53 | "dir", 54 | "div", 55 | "dl", 56 | "dt", 57 | "element", 58 | "em", 59 | "fieldset", 60 | "figcaption", 61 | "figure", 62 | "font", 63 | "footer", 64 | "form", 65 | "h1", 66 | "h2", 67 | "h3", 68 | "h4", 69 | "h5", 70 | "h6", 71 | "head", 72 | "header", 73 | "hgroup", 74 | "hr", 75 | "html", 76 | "i", 77 | "img", 78 | "input", 79 | "ins", 80 | "kbd", 81 | "label", 82 | "legend", 83 | "li", 84 | "main", 85 | "map", 86 | "mark", 87 | "marquee", 88 | "menu", 89 | "menuitem", 90 | "meter", 91 | "nav", 92 | "nobr", 93 | "ol", 94 | "optgroup", 95 | "option", 96 | "output", 97 | "p", 98 | "pre", 99 | "progress", 100 | "q", 101 | "rp", 102 | "rt", 103 | "ruby", 104 | "s", 105 | "samp", 106 | "section", 107 | "select", 108 | "shadow", 109 | "small", 110 | "source", 111 | "spacer", 112 | "span", 113 | "strike", 114 | "strong", 115 | "style", 116 | "sub", 117 | "summary", 118 | "sup", 119 | "table", 120 | "tbody", 121 | "td", 122 | "template", 123 | "textarea", 124 | "tfoot", 125 | "th", 126 | "thead", 127 | "time", 128 | "tr", 129 | "track", 130 | "tt", 131 | "u", 132 | "ul", 133 | "var", 134 | "video", 135 | "wbr", 136 | "svg", 137 | "altglyph", 138 | "altglyphdef", 139 | "altglyphitem", 140 | "animatecolor", 141 | "animatemotion", 142 | "animatetransform", 143 | "circle", 144 | "clippath", 145 | "defs", 146 | "desc", 147 | "ellipse", 148 | "filter", 149 | "g", 150 | "glyph", 151 | "glyphref", 152 | "hkern", 153 | "image", 154 | "line", 155 | "lineargradient", 156 | "marker", 157 | "mask", 158 | "metadata", 159 | "mpath", 160 | "path", 161 | "pattern", 162 | "polygon", 163 | "polyline", 164 | "radialgradient", 165 | "rect", 166 | "stop", 167 | "switch", 168 | "symbol", 169 | "text", 170 | "textpath", 171 | "title", 172 | "tref", 173 | "tspan", 174 | "view", 175 | "vkern", 176 | "feBlend", 177 | "feColorMatrix", 178 | "feComponentTransfer", 179 | "feComposite", 180 | "feConvolveMatrix", 181 | "feDiffuseLighting", 182 | "feDisplacementMap", 183 | "feDistantLight", 184 | "feFlood", 185 | "feFuncA", 186 | "feFuncB", 187 | "feFuncG", 188 | "feFuncR", 189 | "feGaussianBlur", 190 | "feMerge", 191 | "feMergeNode", 192 | "feMorphology", 193 | "feOffset", 194 | "fePointLight", 195 | "feSpecularLighting", 196 | "feSpotLight", 197 | "feTile", 198 | "feTurbulence", 199 | "math", 200 | "menclose", 201 | "merror", 202 | "mfenced", 203 | "mfrac", 204 | "mglyph", 205 | "mi", 206 | "mlabeledtr", 207 | "mmultiscripts", 208 | "mn", 209 | "mo", 210 | "mover", 211 | "mpadded", 212 | "mphantom", 213 | "mroot", 214 | "mrow", 215 | "ms", 216 | "mspace", 217 | "msqrt", 218 | "mstyle", 219 | "msub", 220 | "msup", 221 | "msubsup", 222 | "mtable", 223 | "mtd", 224 | "mtext", 225 | "mtr", 226 | "munder", 227 | "munderover" 228 | ], 229 | "attributes": { 230 | "a": ["href"], 231 | "img": ["src", "longDesc"], 232 | "input": [ 233 | ["type", "checkbox"], 234 | ["disabled", true] 235 | ], 236 | "li": [["className", "task-list-item"]], 237 | "div": ["itemScope", "itemType"], 238 | "blockquote": ["cite"], 239 | "del": ["cite"], 240 | "ins": ["cite"], 241 | "q": ["cite"], 242 | "*": [ 243 | "abbr", 244 | "accept", 245 | "acceptCharset", 246 | "accessKey", 247 | "action", 248 | "align", 249 | "alt", 250 | "ariaDescribedBy", 251 | "ariaHidden", 252 | "ariaLabel", 253 | "ariaLabelledBy", 254 | "axis", 255 | "border", 256 | "cellPadding", 257 | "cellSpacing", 258 | "char", 259 | "charOff", 260 | "charSet", 261 | "checked", 262 | "clear", 263 | "cols", 264 | "colSpan", 265 | "color", 266 | "compact", 267 | "coords", 268 | "dateTime", 269 | "dir", 270 | "disabled", 271 | "encType", 272 | "htmlFor", 273 | "frame", 274 | "headers", 275 | "height", 276 | "hrefLang", 277 | "hSpace", 278 | "isMap", 279 | "id", 280 | "label", 281 | "lang", 282 | "maxLength", 283 | "media", 284 | "method", 285 | "multiple", 286 | "name", 287 | "noHref", 288 | "noShade", 289 | "noWrap", 290 | "open", 291 | "prompt", 292 | "readOnly", 293 | "rel", 294 | "rev", 295 | "rows", 296 | "rowSpan", 297 | "rules", 298 | "scope", 299 | "selected", 300 | "shape", 301 | "size", 302 | "span", 303 | "start", 304 | "summary", 305 | "tabIndex", 306 | "target", 307 | "title", 308 | "type", 309 | "useMap", 310 | "vAlign", 311 | "value", 312 | "vSpace", 313 | "width", 314 | "itemProp", 315 | "className", 316 | "data*", 317 | "about", 318 | "content", 319 | "datatype", 320 | "id", 321 | "lang", 322 | "property", 323 | "rel", 324 | "resource", 325 | "rev", 326 | "tabindex", 327 | "typeof", 328 | "ariaActiveDescendant", 329 | "ariaAtomic", 330 | "ariaAutoComplete", 331 | "ariaBusy", 332 | "ariaChecked", 333 | "ariaColCount", 334 | "ariaColIndex", 335 | "ariaColSpan", 336 | "ariaControls", 337 | "ariaCurrent", 338 | "ariaDescribedBy", 339 | "ariaDetails", 340 | "ariaDisabled", 341 | "ariaDropEffect", 342 | "ariaErrorMessage", 343 | "ariaExpanded", 344 | "ariaFlowTo", 345 | "ariaGrabbed", 346 | "ariaHasPopup", 347 | "ariaHidden", 348 | "ariaInvalid", 349 | "ariaKeyShortcuts", 350 | "ariaLabel", 351 | "ariaLabelledBy", 352 | "ariaLevel", 353 | "ariaLive", 354 | "ariaModal", 355 | "ariaMultiLine", 356 | "ariaMultiSelectable", 357 | "ariaOrientation", 358 | "ariaOwns", 359 | "ariaPlaceholder", 360 | "ariaPosInSet", 361 | "ariaPressed", 362 | "ariaReadOnly", 363 | "ariaRelevant", 364 | "ariaRequired", 365 | "ariaRoleDescription", 366 | "ariaRowCount", 367 | "ariaRowIndex", 368 | "ariaRowSpan", 369 | "ariaSelected", 370 | "ariaSetSize", 371 | "ariaSort", 372 | "ariaValueMax", 373 | "ariaValueMin", 374 | "ariaValueNow", 375 | "ariaValueText", 376 | "role" 377 | ], 378 | "foreignObject": [ 379 | "alignment-baseline", 380 | "baseline-shift", 381 | "clip", 382 | "clip-path", 383 | "clip-rule", 384 | "color", 385 | "color-interpolation", 386 | "color-interpolation-filters", 387 | "color-profile", 388 | "color-rendering", 389 | "cursor", 390 | "direction", 391 | "display", 392 | "dominant-baseline", 393 | "enable-background", 394 | "externalResourcesRequired", 395 | "fill", 396 | "fill-opacity", 397 | "fill-rule", 398 | "filter", 399 | "flood-color", 400 | "flood-opacity", 401 | "focusHighlight", 402 | "focusable", 403 | "font-family", 404 | "font-size", 405 | "font-size-adjust", 406 | "font-stretch", 407 | "font-style", 408 | "font-variant", 409 | "font-weight", 410 | "glyph-orientation-horizontal", 411 | "glyph-orientation-vertical", 412 | "height", 413 | "image-rendering", 414 | "kerning", 415 | "letter-spacing", 416 | "lighting-color", 417 | "marker-end", 418 | "marker-mid", 419 | "marker-start", 420 | "mask", 421 | "nav-down", 422 | "nav-down-left", 423 | "nav-down-right", 424 | "nav-left", 425 | "nav-next", 426 | "nav-prev", 427 | "nav-right", 428 | "nav-up", 429 | "nav-up-left", 430 | "nav-up-right", 431 | "opacity", 432 | "overflow", 433 | "pointer-events", 434 | "requiredExtensions", 435 | "requiredFeatures", 436 | "requiredFonts", 437 | "requiredFormats", 438 | "shape-rendering", 439 | "stop-color", 440 | "stop-opacity", 441 | "stroke", 442 | "stroke-dasharray", 443 | "stroke-dashoffset", 444 | "stroke-linecap", 445 | "stroke-linejoin", 446 | "stroke-miterlimit", 447 | "stroke-opacity", 448 | "stroke-width", 449 | "systemLanguage", 450 | "text-anchor", 451 | "text-decoration", 452 | "text-rendering", 453 | "transform", 454 | "unicode-bidi", 455 | "visibility", 456 | "width", 457 | "word-spacing", 458 | "writing-mode", 459 | "x", 460 | "y" 461 | ], 462 | "script": [ 463 | "async", 464 | "charSet", 465 | "crossOrigin", 466 | "defer", 467 | "integrity", 468 | "language", 469 | "noModule", 470 | "nonce", 471 | "referrerPolicy", 472 | "src", 473 | "type" 474 | ], 475 | "applet": [ 476 | "align", 477 | "alt", 478 | "archive", 479 | "code", 480 | "codeBase", 481 | "height", 482 | "hSpace", 483 | "name", 484 | "object", 485 | "vSpace", 486 | "width" 487 | ], 488 | "object": [ 489 | "align", 490 | "archive", 491 | "border", 492 | "classId", 493 | "codeBase", 494 | "codeType", 495 | "data", 496 | "declare", 497 | "form", 498 | "height", 499 | "hSpace", 500 | "name", 501 | "standby", 502 | "tabIndex", 503 | "type", 504 | "typeMustMatch", 505 | "useMap", 506 | "vSpace", 507 | "width" 508 | ] 509 | }, 510 | "required": { 511 | "input": { 512 | "type": "checkbox", 513 | "disabled": true 514 | } 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /hast-annotations-match/generate-full-html-schema.js: -------------------------------------------------------------------------------- 1 | const merge = require("deepmerge"); 2 | const gh = require("hast-util-sanitize/lib/github"); 3 | const info = require("property-information"); 4 | const svgElementAttributes = require("svg-element-attributes"); 5 | const ariaAttributes = require("aria-attributes").map( 6 | (attr) => info.find(info.html, attr).property 7 | ); 8 | const htmlElementAttributes = require("html-element-attributes"); 9 | const fs = require("fs"); 10 | 11 | let schema = gh; 12 | schema.tagNames = [ 13 | "a", 14 | "abbr", 15 | "acronym", 16 | "address", 17 | "area", 18 | "article", 19 | "aside", 20 | "audio", 21 | "b", 22 | "bdi", 23 | "bdo", 24 | "big", 25 | "blink", 26 | "blockquote", 27 | "body", 28 | "br", 29 | "button", 30 | "canvas", 31 | "caption", 32 | "center", 33 | "cite", 34 | "code", 35 | "col", 36 | "colgroup", 37 | "content", 38 | "data", 39 | "datalist", 40 | "dd", 41 | "decorator", 42 | "del", 43 | "details", 44 | "dfn", 45 | "dir", 46 | "div", 47 | "dl", 48 | "dt", 49 | "element", 50 | "em", 51 | "fieldset", 52 | "figcaption", 53 | "figure", 54 | "font", 55 | "footer", 56 | "form", 57 | "h1", 58 | "h2", 59 | "h3", 60 | "h4", 61 | "h5", 62 | "h6", 63 | "head", 64 | "header", 65 | "hgroup", 66 | "hr", 67 | "html", 68 | "i", 69 | "img", 70 | "input", 71 | "ins", 72 | "kbd", 73 | "label", 74 | "legend", 75 | "li", 76 | "main", 77 | "map", 78 | "mark", 79 | "marquee", 80 | "menu", 81 | "menuitem", 82 | "meter", 83 | "nav", 84 | "nobr", 85 | "ol", 86 | "optgroup", 87 | "option", 88 | "output", 89 | "p", 90 | "pre", 91 | "progress", 92 | "q", 93 | "rp", 94 | "rt", 95 | "ruby", 96 | "s", 97 | "samp", 98 | "section", 99 | "select", 100 | "shadow", 101 | "small", 102 | "source", 103 | "spacer", 104 | "span", 105 | "strike", 106 | "strong", 107 | "style", 108 | "sub", 109 | "summary", 110 | "sup", 111 | "table", 112 | "tbody", 113 | "td", 114 | "template", 115 | "textarea", 116 | "tfoot", 117 | "th", 118 | "thead", 119 | "time", 120 | "tr", 121 | "track", 122 | "tt", 123 | "u", 124 | "ul", 125 | "var", 126 | "video", 127 | "wbr", 128 | "svg", 129 | "a", 130 | "altglyph", 131 | "altglyphdef", 132 | "altglyphitem", 133 | "animatecolor", 134 | "animatemotion", 135 | "animatetransform", 136 | "audio", 137 | "canvas", 138 | "circle", 139 | "clippath", 140 | "defs", 141 | "desc", 142 | "ellipse", 143 | "filter", 144 | "font", 145 | "g", 146 | "glyph", 147 | "glyphref", 148 | "hkern", 149 | "image", 150 | "line", 151 | "lineargradient", 152 | "marker", 153 | "mask", 154 | "metadata", 155 | "mpath", 156 | "path", 157 | "pattern", 158 | "polygon", 159 | "polyline", 160 | "radialgradient", 161 | "rect", 162 | "stop", 163 | "style", 164 | "switch", 165 | "symbol", 166 | "text", 167 | "textpath", 168 | "title", 169 | "tref", 170 | "tspan", 171 | "video", 172 | "view", 173 | "vkern", 174 | "feBlend", 175 | "feColorMatrix", 176 | "feComponentTransfer", 177 | "feComposite", 178 | "feConvolveMatrix", 179 | "feDiffuseLighting", 180 | "feDisplacementMap", 181 | "feDistantLight", 182 | "feFlood", 183 | "feFuncA", 184 | "feFuncB", 185 | "feFuncG", 186 | "feFuncR", 187 | "feGaussianBlur", 188 | "feMerge", 189 | "feMergeNode", 190 | "feMorphology", 191 | "feOffset", 192 | "fePointLight", 193 | "feSpecularLighting", 194 | "feSpotLight", 195 | "feTile", 196 | "feTurbulence", 197 | "math", 198 | "menclose", 199 | "merror", 200 | "mfenced", 201 | "mfrac", 202 | "mglyph", 203 | "mi", 204 | "mlabeledtr", 205 | "mmultiscripts", 206 | "mn", 207 | "mo", 208 | "mover", 209 | "mpadded", 210 | "mphantom", 211 | "mroot", 212 | "mrow", 213 | "ms", 214 | "mspace", 215 | "msqrt", 216 | "mstyle", 217 | "msub", 218 | "msup", 219 | "msubsup", 220 | "mtable", 221 | "mtd", 222 | "mtext", 223 | "mtr", 224 | "munder", 225 | "munderover", 226 | ]; 227 | 228 | schema = merge(schema, { 229 | attributes: { 230 | "*": Array.from( 231 | new Set( 232 | [ 233 | "className", 234 | "data*", 235 | "about", 236 | "content", 237 | "datatype", 238 | "id", 239 | "lang", 240 | "property", 241 | "rel", 242 | "resource", 243 | "rev", 244 | "tabindex", 245 | "typeof", 246 | ].concat(ariaAttributes) 247 | ) 248 | ), 249 | }, 250 | }); 251 | 252 | schema.strip = ["script", "object", "applet", "foreignObject"]; 253 | for (const element of Object.keys(svgElementAttributes)) { 254 | if (element !== "*" && schema.strip.indexOf(element) !== -1) { 255 | schema.attributes[element] = svgElementAttributes[element].map( 256 | (attr) => info.find(info.html, attr).property 257 | ); 258 | } 259 | } 260 | for (const element of Object.keys(htmlElementAttributes)) { 261 | if (element !== "*" && schema.strip.indexOf(element) !== -1) { 262 | schema.attributes[element] = htmlElementAttributes[element].map( 263 | (attr) => info.find(info.html, attr).property 264 | ); 265 | } 266 | } 267 | 268 | schema.tagNames = Array.from(new Set(schema.tagNames)); 269 | 270 | module.exports = schema; 271 | 272 | fs.writeFileSync( 273 | "hast-annotations-match/full-html-schema.json", 274 | JSON.stringify(schema, null, 4) 275 | ); 276 | -------------------------------------------------------------------------------- /hast-annotations-match/get-node.js: -------------------------------------------------------------------------------- 1 | // const debug = require("../logger")("hast-annotations-match"); 2 | import { nodeSelector } from "./css-selector.js"; 3 | import { simpleXpathSelector } from "./simple-xpath-selector.js"; 4 | import { processPositions } from "./process-positions.js"; 5 | import { processQuotations } from "./process-quotations.js"; 6 | const selectors = { 7 | XPathSelector: simpleXpathSelector, 8 | CssSelector: nodeSelector, 9 | FragmentSelector: ({ tree, value, annotation, addProps = true }) => { 10 | return nodeSelector({ 11 | tree, 12 | value: "#" + value, 13 | annotation, 14 | addProps, 15 | }); 16 | }, 17 | }; 18 | 19 | /** 20 | * 21 | * @param {{tree: Object, selector: Object, annotation: Object}} param0 - selector options 22 | */ 23 | export function getNode({ tree, selector, annotation }) { 24 | // Need to check `refinedBy`. If so and refining selector is quote or text-position then process using node as root tree 25 | if (selector.refinedBy) { 26 | const node = selectors[selector.type]({ 27 | tree, 28 | value: selector.value, 29 | annotation, 30 | addProps: false, 31 | }); 32 | const target = { ...annotation.target, selector: selector.refinedBy }; 33 | if (selector.refinedBy.type === "TextQuoteSelector") { 34 | processQuotations(node, [{ ...annotation, target }]); 35 | } else if (selector.refinedBy.type === "TextPositionSelector") { 36 | processPositions(node, [{ ...annotation, target }]); 37 | } else { 38 | return selectors[selector.refinedBy.type]({ 39 | tree: node, 40 | value: selector.refinedBy.value, 41 | annotation: { 42 | ...annotation, 43 | target, 44 | }, 45 | }); 46 | } 47 | } else { 48 | return selectors[selector.type]({ 49 | tree, 50 | value: selector.value, 51 | annotation, 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /hast-annotations-match/index.js: -------------------------------------------------------------------------------- 1 | // const debug = require("../logger")("hast-annotations-match"); 2 | import { rangeSelector } from "./range-selector.js"; 3 | import { getNode } from "./get-node.js"; 4 | import { processPositions } from "./process-positions.js"; 5 | import { processQuotations } from "./process-quotations.js"; 6 | import { selectAll } from "hast-util-select"; 7 | import { find, svg } from "property-information"; 8 | import { h } from "hastscript"; 9 | 10 | function debug(...args) { 11 | // console.log(...args); 12 | } 13 | 14 | const props = [ 15 | "x", 16 | "y", 17 | "width", 18 | "height", 19 | "textLength", 20 | "font-size", 21 | "data-annotation-id", 22 | "data-annotation-x", 23 | "data-annotation-y", 24 | "data-annotation-width", 25 | "data-annotation-height", 26 | "data-annotation-offset", 27 | "data-annotation-highlight", 28 | "data-annotation-transform", 29 | "data-annotation-highlight-box", 30 | "pointer-events", 31 | "transform", 32 | "fill", 33 | "class", 34 | ]; 35 | const attributes = {}; 36 | for (const prop of props) { 37 | attributes[prop] = find(svg, prop).property; 38 | } 39 | 40 | /* 41 | ## `hast-annotations-match` 42 | _called with -> (tree, annotations) -> modified tree with annotations data prop_ 43 | 44 | Modifies the hast tree to include annotations properties and marks for highlights. Returns a modified tree with a sorted annotations collection under `data.annotations` on the root element. 45 | 46 | For each selector: 47 | 1. Match to node: 48 | * Node-based: select node and add properties (id, index, motivation, styleClass). 49 | * If has refinedBy, call Quote-based processing with selected node as root. 50 | * Quote-based: convert to text positions 51 | 2. Visit tree with parents: 52 | 1. If highlight motivation 53 | 1. Node-based: if highlight motivation, add marks to all text children. Add props to marks 54 | 2. If text position, split at offsets and wrap selected in marks, then links (if it has linking purpose). Do not wrap Text nodes that already have mark parents. Add props to marks. 55 | 3. Add included stylesheets to head. 56 | 4. Add default annotations stylesheet to head. 57 | 5. Add link to annotations collection id in head 58 | 59 | ## Props 60 | 61 | * `data-annotations-id` 62 | * `data-selector-index`: index of mark in total number of marks for this selector 63 | * `data-annotations-motivation`: annotations motivations 64 | * `class` : styleClass 65 | * `data-annotations-purpose`: body purposes 66 | * `data-annotations-creator` 67 | 68 | */ 69 | 70 | export function matchAnnotations( 71 | tree, 72 | file, 73 | { annotations, url, canonical, notes } 74 | ) { 75 | // iterate through annotations 76 | let positionAnnotations = []; 77 | let quoteAnnotations = []; 78 | for (const annotation of annotations) { 79 | const { target } = annotation; 80 | if (testSource(target.source)) { 81 | const { selector } = target; 82 | switch (selector.type) { 83 | case "TextQuoteSelector": 84 | debug("using TextQuoteSelector"); 85 | quoteAnnotations = quoteAnnotations.concat(annotation); 86 | break; 87 | case "TextPositionSelector": 88 | debug("using TextPositionSelector"); 89 | positionAnnotations = positionAnnotations.concat(annotation); 90 | break; 91 | case "RangeSelector": 92 | debug("using RangeSelector"); 93 | rangeSelector({ tree, selector, annotation }); 94 | break; 95 | default: 96 | getNode({ tree, selector, annotation }); 97 | break; 98 | } 99 | } 100 | } 101 | processPositions(tree, positionAnnotations); 102 | processQuotations(tree, quoteAnnotations); 103 | selectAll("svg", tree).forEach((svg) => { 104 | const svgHighlights = selectAll("tspan[data-annotation-id]", svg).map( 105 | (node) => { 106 | const rect = h("rect"); 107 | rect.properties[attributes["data-annotation-highlight-box"]] = 108 | node.properties[attributes["data-annotation-id"]]; 109 | rect.properties[attributes.x] = 110 | node.properties[attributes["data-annotation-x"]]; 111 | rect.properties[attributes.y] = 112 | node.properties[attributes["data-annotation-y"]]; 113 | rect.properties[attributes.width] = 114 | node.properties[attributes["data-annotation-width"]]; 115 | rect.properties[attributes.height] = 116 | node.properties[attributes["data-annotation-height"]]; 117 | rect.properties[attributes.transform] = 118 | node.properties[attributes["data-annotation-transform"]]; 119 | rect.properties[attributes.fill] = "rgba(255, 255, 0, 0.35)"; 120 | const classes = []; 121 | rect.properties[attributes.class] = classes.concat( 122 | node.properties[attributes.class] 123 | ); 124 | rect.properties[attributes["pointer-events"]] = "none"; 125 | return rect; 126 | } 127 | ); 128 | svg.children = svg.children.concat(svgHighlights); 129 | }); 130 | const sortedAnnotationsId = selectAll("[data-annotation-id]", tree).map( 131 | (node) => node.properties.dataAnnotationId 132 | ); 133 | const sortedAnnotations = Array.from(new Set(sortedAnnotationsId)).map((id) => 134 | annotations.find((annotation) => annotation.id === id) 135 | ); 136 | file.data.annotations = sortedAnnotations; 137 | function testSource(source) { 138 | return source === url || source === canonical; 139 | } 140 | return tree; 141 | } 142 | 143 | // function addHighlights (node, ancestors) { 144 | // if (node.tagName === "tspan" && node.properties[attributes["data-annotation-id"]]) { 145 | // const rect = h("rect[data-annotation-highlight-box]") 146 | // rect.properties[attributes.x] = node.properties[attributes["data-annotation-x"]]; 147 | // rect.properties[attributes.y] = node.properties[attributes["data-annotation-y"]]; 148 | // rect.properties[attributes.width] = node.properties[attributes["data-annotation-width"]]; 149 | // rect.properties[attributes.height] = node.properties[attributes["data-annotation-height"]]; 150 | // rect.properties[attributes.transform] = node.properties[attributes["data-annotation-transform"]]; 151 | // rect.properties[attributes.fill] = "rgba(255, 255, 0, 0.5)" 152 | // const classes = []; 153 | // node.properties[attributes.class] = classes 154 | // .concat(node.properties[attributes.class]) 155 | // } 156 | // } 157 | 158 | export default matchAnnotations; 159 | -------------------------------------------------------------------------------- /hast-annotations-match/process-positions.js: -------------------------------------------------------------------------------- 1 | import { visitParents as visit } from "unist-util-visit-parents"; 2 | import { addPropsToNode } from "./add-props-to-node.js"; 3 | import { h } from "hastscript"; 4 | import { addParentProps } from "./add-parent-props.js"; 5 | import { encode } from "universal-base64url"; 6 | 7 | function getId(id) { 8 | return `id-${encode(id)}`; 9 | } 10 | // const debug = require("../logger")("process-positions"); 11 | 12 | /* 13 | ## `hast-annotations-match` 14 | _called with -> (tree, annotations) -> modified tree with annotations data prop_ 15 | 16 | Modifies the hast tree to include annotations properties and marks for highlights. Returns a modified tree with a sorted annotations collection under `data.annotations` on the root element. 17 | 18 | For each selector: 19 | 1. Match to node: 20 | * Node-based: select node and add properties (id, index, motivation, styleClass). 21 | * If has refinedBy, call Quote-based processing with selected node as root. 22 | * Quote-based: convert to text positions 23 | 2. Visit tree with parents: 24 | 1. If highlight motivation 25 | 1. Node-based: if highlight motivation, add marks to all text children. Add props to marks 26 | 2. If text position, split at offsets and wrap selected in marks, then links (if it has linking purpose). Do not wrap Text nodes that already have mark parents. Add props to marks. 27 | 3. Add included stylesheets to head. 28 | 4. Add default annotations stylesheet to head. 29 | 5. Add link to annotations collection id in head 30 | */ 31 | 32 | export function processPositions(tree, positionAnnotations) { 33 | // Sort annotations based on selector.start 34 | positionAnnotations.sort( 35 | (a, b) => a.target.selector.start - b.target.selector.start 36 | ); 37 | // shift first annotation 38 | let annotation = getAnnotation(positionAnnotations); 39 | // visit tree with parents, filtering on text nodes, maintaining character count 40 | let count = 0; 41 | const replacementActions = []; 42 | visit(tree, "text", visitor); 43 | replacementActions.forEach((fn) => fn()); 44 | function visitor(node, ancestors) { 45 | if (!annotation) return; 46 | visitNode({ 47 | count, 48 | currentAnnotation: annotation, 49 | node, 50 | ancestors, 51 | }); 52 | count = count + node.value.length; 53 | } 54 | function visitNode({ count, currentAnnotation, node, ancestors }) { 55 | const parent = ancestors[ancestors.length - 1]; 56 | const textElement = ancestors.find((node) => node.tagName === "text"); 57 | // One thing that would be useful here is the ability to select elements using the position/quotation selector 58 | // The way this would work could be to have two new options: highlightingPurposes and highlightingSelectors. 59 | // The selector only highlights if both are true. Export a config.js module that lists all known purposes and selectors. 60 | // Also need an injectAnnotation option that injects the HTML commenting body adjacent to the selected node. 61 | // How would it work 62 | const { end } = currentAnnotation.target.selector; 63 | const startInNode = startIsInNode(count, currentAnnotation, node); 64 | const endInNode = endIsInNode(count, currentAnnotation, node); 65 | const { replacement, suffix } = processNode({ 66 | startInNode, 67 | endInNode, 68 | count, 69 | node, 70 | svg: ancestors[ancestors.map((node) => node.tagName).lastIndexOf("svg")], 71 | currentAnnotation, 72 | parent: textElement, 73 | }); 74 | if (replacement) { 75 | replacementActions.push(() => { 76 | const newIndex = parent.children.indexOf(node); 77 | parent.children.splice(newIndex, 1, ...replacement); 78 | }); 79 | } 80 | if (endInNode) { 81 | annotation = getAnnotation(positionAnnotations); 82 | if (suffix && annotation) { 83 | visitNode({ 84 | count: end, 85 | currentAnnotation: annotation, 86 | node: suffix, 87 | ancestors, 88 | }); 89 | } 90 | } 91 | } 92 | } 93 | 94 | function wrapNode(text, annotation, svg, parent) { 95 | // If we decide to support linking purposes by rendering actual links then we need to change this and make sure we don't render nested links. 96 | // It's actually simpler in the meantime to support linking purposes by rendering a link button either after highlight or in sidebar. 97 | const node = h(svg ? "tspan" : "mark", text); 98 | addPropsToNode(node, annotation); 99 | addParentProps(svg, node, parent); 100 | return node; 101 | } 102 | function getAnnotation(positionAnnotations) { 103 | const annotation = positionAnnotations.shift(); 104 | return annotation; 105 | } 106 | 107 | function startIsInNode(count, currentAnnotation, node) { 108 | const { start } = currentAnnotation.target.selector; 109 | let startInNode = false; 110 | if (count <= start && start <= count + node.value.length) { 111 | startInNode = true; 112 | // debug("start is in node"); 113 | } 114 | return startInNode; 115 | } 116 | 117 | function endIsInNode(count, currentAnnotation, node) { 118 | const { end } = currentAnnotation.target.selector; 119 | let endInNode = false; 120 | if (count <= end && end <= count + node.value.length) { 121 | endInNode = true; 122 | // debug("end is in node"); 123 | } 124 | return endInNode; 125 | } 126 | 127 | function processNode({ 128 | startInNode, 129 | endInNode, 130 | count, 131 | node, 132 | currentAnnotation, 133 | svg, 134 | parent, 135 | }) { 136 | const { start, end } = currentAnnotation.target.selector; 137 | let replacement; 138 | let suffix; 139 | if (startInNode && endInNode) { 140 | const firstSplit = start - count; 141 | const secondSplit = end - count; 142 | const prefix = { type: "text", value: node.value.slice(0, firstSplit) }; 143 | const nodeValue = node.value.slice(firstSplit, secondSplit); 144 | if (nodeValue.trim()) { 145 | const wrappedNode = wrapNode( 146 | node.value.slice(firstSplit, secondSplit), 147 | currentAnnotation, 148 | svg, 149 | parent 150 | ); 151 | const suffixValue = node.value.slice(secondSplit); 152 | suffix = { type: "text", value: suffixValue }; 153 | wrappedNode.properties.id = getId(currentAnnotation.id); 154 | replacement = [prefix, wrappedNode, suffix]; 155 | } 156 | // else if (start) split at start, wrap the rest 157 | } else if (startInNode) { 158 | const firstSplit = start - count; 159 | const prefix = { type: "text", value: node.value.slice(0, firstSplit) }; 160 | const nodeValue = node.value.slice(firstSplit); 161 | if (nodeValue.trim()) { 162 | const wrappedNode = wrapNode( 163 | node.value.slice(firstSplit), 164 | currentAnnotation, 165 | svg, 166 | parent 167 | ); 168 | wrappedNode.properties.id = getId(currentAnnotation.id); 169 | replacement = [prefix, wrappedNode]; 170 | } 171 | // else if (end) split at end, wrap beginning 172 | } else if (endInNode) { 173 | const secondSplit = end - count; 174 | const wrappedNode = wrapNode( 175 | node.value.slice(0, secondSplit), 176 | currentAnnotation, 177 | svg, 178 | parent 179 | ); 180 | suffix = { type: "text", value: node.value.slice(secondSplit) }; 181 | replacement = [wrappedNode, suffix]; 182 | // if node is entirely within selector range, wrap contents 183 | } else if ( 184 | start < count && 185 | count + node.value.length < end && 186 | node.value.trim() 187 | ) { 188 | // debug("whitespace: ", !node.value.trim()); 189 | replacement = [wrapNode(node.value, currentAnnotation, svg, parent)]; 190 | } 191 | return { replacement, suffix }; 192 | } 193 | -------------------------------------------------------------------------------- /hast-annotations-match/process-quotations.js: -------------------------------------------------------------------------------- 1 | import { processPositions } from "./process-positions.js"; 2 | import DiffMatchPatch from "diff-match-patch"; 3 | import toString from "hast-util-to-string"; 4 | 5 | // Based on https://github.com/tilgovi/dom-anchor-text-quote/blob/master/src/index.js MIT Licensed 6 | 7 | // The DiffMatchPatch bitap has a hard 32-character pattern length limit. 8 | const SLICE_LENGTH = 32; 9 | const SLICE_RE = new RegExp("(.|[\r\n]){1," + String(SLICE_LENGTH) + "}", "g"); 10 | 11 | export function processQuotations(tree, quoteAnnotations) { 12 | let positionAnnotations = quoteAnnotations.map(processQuote); 13 | function processQuote(annotation, index) { 14 | return processor(tree, annotation); 15 | } 16 | positionAnnotations = positionAnnotations.filter((item) => item); 17 | processPositions(tree, positionAnnotations); 18 | } 19 | 20 | function processor(tree, annotation, options = {}) { 21 | const { selector } = annotation.target; 22 | const { prefix, exact, suffix } = selector; 23 | 24 | const dmp = new DiffMatchPatch(); 25 | 26 | const textContent = toString(tree); 27 | dmp.Match_Distance = textContent.length * 2; 28 | 29 | // Work around a hard limit of the DiffMatchPatch bitap implementation. 30 | // The search pattern must be no more than SLICE_LENGTH characters. 31 | const slices = exact.match(SLICE_RE); 32 | let loc = 0; 33 | let start = Number.POSITIVE_INFINITY; 34 | let end = Number.NEGATIVE_INFINITY; 35 | let result = -1; 36 | const havePrefix = prefix !== undefined; 37 | const haveSuffix = suffix !== undefined; 38 | let foundPrefix = false; 39 | 40 | // If the prefix is known then search for that first. 41 | if (havePrefix) { 42 | result = dmp.match_main(textContent, prefix, loc); 43 | if (result > -1) { 44 | loc = result + prefix.length; 45 | foundPrefix = true; 46 | } 47 | } 48 | 49 | // If we have a suffix, and the prefix wasn't found, then search for it. 50 | if (haveSuffix && !foundPrefix) { 51 | result = dmp.match_main(textContent, suffix, loc + exact.length); 52 | if (result > -1) { 53 | loc = result - exact.length; 54 | } 55 | } 56 | 57 | // Search for the first slice. 58 | const firstSlice = slices.shift(); 59 | result = dmp.match_main(textContent, firstSlice, loc); 60 | if (result > -1) { 61 | start = result; 62 | loc = end = start + firstSlice.length; 63 | } else { 64 | return null; 65 | } 66 | 67 | // Create a fold function that will reduce slices to positional extents. 68 | const foldSlices = (acc, slice) => { 69 | if (!acc) { 70 | // A search for an earlier slice of the pattern failed to match. 71 | return null; 72 | } 73 | 74 | const result = dmp.match_main(textContent, slice, acc.loc); 75 | if (result === -1) { 76 | return null; 77 | } 78 | 79 | // The next slice should follow this one closely. 80 | acc.loc = result + slice.length; 81 | 82 | // Expand the start and end to a quote that includes all the slices. 83 | acc.start = Math.min(acc.start, result); 84 | acc.end = Math.max(acc.end, result + slice.length); 85 | 86 | return acc; 87 | }; 88 | // Use the fold function to establish the full quote extents. 89 | // Expect the slices to be close to one another. 90 | // This distance is deliberately generous for now. 91 | dmp.Match_Distance = 64; 92 | const acc = slices.reduce(foldSlices, { start, end, loc }); 93 | if (!acc) { 94 | return null; 95 | } 96 | const target = { 97 | ...annotation.target, 98 | selector: { 99 | type: "TextPositionSelector", 100 | start: acc.start, 101 | end: acc.end, 102 | }, 103 | }; 104 | return { ...annotation, target }; 105 | } 106 | -------------------------------------------------------------------------------- /hast-annotations-match/range-selector.js: -------------------------------------------------------------------------------- 1 | import { visit } from "unist-util-visit"; 2 | import { is } from "unist-util-is"; 3 | import { getNode } from "./get-node.js"; 4 | import { addPropsToNode } from "./add-props-to-node.js"; 5 | 6 | /** 7 | * 8 | * @param {{tree: Object, selector: Object, annotation: Object}} param0 - selector options 9 | */ 10 | export function rangeSelector({ tree, selector, annotation }) { 11 | const { startSelector, endSelector } = selector; 12 | const startNode = getNode({ 13 | tree, 14 | selector: startSelector, 15 | annotation, 16 | }); 17 | const endNode = getNode({ 18 | tree, 19 | selector: endSelector, 20 | annotation, 21 | }); 22 | let controlStart = false; 23 | let controlEnd = false; 24 | let selectedNodes = [startNode]; 25 | if (!startNode || !endNode) return; 26 | visit(tree, "element", (node, index, parent) => { 27 | if (controlStart && !controlEnd) { 28 | selectedNodes = selectedNodes.concat(node); 29 | } 30 | if (is(node, startNode)) { 31 | controlStart = true; 32 | } 33 | if (is(node, endNode)) { 34 | controlEnd = true; 35 | } 36 | }); 37 | selectedNodes = [...selectedNodes, endNode]; 38 | selectedNodes.map((node) => { 39 | addPropsToNode(node, annotation); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /hast-annotations-match/render-templates.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | const gh = require("hast-util-sanitize/lib/github"); 3 | const sanitize = require("rehype-sanitize"); 4 | const unified = require("unified"); 5 | const parse = require("rehype-parse"); 6 | const info = require("property-information"); 7 | const markdown = require("remark-parse"); 8 | const remark2rehype = require("remark-rehype"); 9 | const stringify = require("rehype-stringify"); 10 | const raw = require("rehype-raw"); 11 | const h = require("hastscript"); 12 | 13 | /* 14 | ## Props 15 | * `data-annotation-id` 16 | * `data-selector-index`: index of mark in total number of marks for this selector 17 | * `data-annotation-motivation`: annotations motivations 18 | * `class` : styleClass 19 | * `data-annotation-purpose`: body purposes 20 | */ 21 | const props = [ 22 | "data-template-id", 23 | "data-controller", 24 | "data-template-purpose", 25 | "class", 26 | "lang", 27 | "data-target", 28 | ]; 29 | const attributes = {}; 30 | for (const prop of props) { 31 | attributes[prop] = info.find(info.html, prop).property; 32 | } 33 | const htmlProcessor = unified() 34 | .use(parse, { fragment: true }) 35 | .use(sanitize, gh); 36 | 37 | const markdownProcessor = unified() 38 | .use(markdown, { commonmark: true, footnotes: true }) 39 | .use(remark2rehype, { allowDangerousHTML: true, commonmark: true }) 40 | .use(raw) 41 | .use(stringify); 42 | 43 | module.exports = function renderTemplates(annotations) { 44 | // This line flattens the resulting map and filters out undefineds/nulls. 45 | return Array.prototype.concat 46 | .apply([], annotations.map(renderTemplate)) 47 | .filter((item) => item); 48 | }; 49 | 50 | function renderTemplate(annotation) { 51 | if (annotation.body) { 52 | return annotation.body.map(renderBody); 53 | } 54 | function renderBody(body, index) { 55 | if (body.type === "TextualBody") { 56 | let wrapper; 57 | if (body.format === "text/html") { 58 | wrapper = htmlProcessor.parse(``) 59 | .children[0]; 60 | } else if (body.format === "text/markdown") { 61 | const html = markdownProcessor.processSync(`${body.value}`); 62 | wrapper = htmlProcessor.parse(``) 63 | .children[0]; 64 | } else { 65 | wrapper = h("template", body.value); 66 | } 67 | wrapper.properties[attributes["data-template-id"]] = `${annotation.id}`; 68 | wrapper.properties[attributes["data-controller"]] = "template"; 69 | if (body.purpose) { 70 | wrapper.properties[attributes["data-template-purpose"]] = body.purpose; 71 | } 72 | if (body.language) { 73 | wrapper.properties[attributes.lang] = body.language; 74 | } 75 | wrapper.properties[attributes["data-target"]] = "annotations.template"; 76 | return wrapper; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /hast-annotations-match/simple-xpath-selector.js: -------------------------------------------------------------------------------- 1 | import { addPropsToNode } from "./add-props-to-node.js"; 2 | 3 | // Based on simple-xpath-selector from https://github.com/tilgovi/simple-xpath-position/blob/master/src/xpath.js MIT license 4 | 5 | /** 6 | * 7 | * @param {{tree: Object, value: string, annotation: Object, addProps: undefined | boolean}} param0 - selector options 8 | */ 9 | export function simpleXpathSelector({ 10 | tree, 11 | value, 12 | annotation, 13 | addProps = true, 14 | }) { 15 | const node = fallbackResolve(value, tree); 16 | if (node && addProps) { 17 | addPropsToNode(node, annotation); 18 | } 19 | return node; 20 | } 21 | 22 | /** 23 | * 24 | * @param {string} path - the xpath string 25 | * @param {*} root 26 | */ 27 | function fallbackResolve(path, root) { 28 | const steps = path.split("/"); 29 | let node = root; 30 | while (node) { 31 | const step = steps.shift(); 32 | if (step === undefined) break; 33 | if (step === ".") continue; 34 | // eslint-disable-next-line 35 | let [name, xpathPosition] = step.split(/[\[\]]/); // prettier-ignore 36 | name = name.replace("_default_:", ""); 37 | const position = xpathPosition ? parseInt(xpathPosition) : 1; 38 | node = findChild(node, name, position); 39 | } 40 | return node; 41 | } 42 | function findChild(node, name, position) { 43 | const parent = node; 44 | while (node) { 45 | if (nodeName(node) === name && --position === 0) break; 46 | node = nextNode(node, parent); 47 | } 48 | return node; 49 | } 50 | 51 | function nextNode(node, parent) { 52 | const index = parent.children.indexOf(node); 53 | if (parent.children[index + 1]) { 54 | return parent.children[index + 1]; 55 | } else { 56 | return null; 57 | } 58 | } 59 | 60 | function nodeName(node) { 61 | if (node.tagName) { 62 | return node.tagName.toLowerCase(); 63 | } 64 | return ""; 65 | } 66 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { matchAnnotations } from "./hast-annotations-match/index.js"; 2 | 3 | export function attacher(options) { 4 | return transformer; 5 | function transformer(node, file) { 6 | return matchAnnotations(node, file, options); 7 | } 8 | } 9 | 10 | export default attacher; 11 | -------------------------------------------------------------------------------- /logger.js: -------------------------------------------------------------------------------- 1 | module.exports = function log(path) { 2 | return function (...args) { 3 | if (process.env.NODE_ENV !== "production") { 4 | console.log(`${path}: `, ...args); 5 | } 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rehype-annotate", 3 | "version": "1.0.0", 4 | "description": "ReHype plugin to match W3C Web Annotations to source locations", 5 | "license": "Apache-2.0", 6 | "type": "module", 7 | "scripts": { 8 | "lint": "tsc --module es2020 --checkJs --allowJs --noEmit --lib es2015 --moduleResolution node index.js && healthier && prettier --write --plugin-search-dir=. '**/*.{js,json,css,yml,svelte}'", 9 | "pretest": "npm run lint", 10 | "prepublishOnly": "npm run lint", 11 | "test": "c8 tap --no-cov tests/index.js && c8 report --reporter=lcov", 12 | "snapshots": "TAP_SNAPSHOT=1 npm run test" 13 | }, 14 | "engines": { 15 | "node": ">14.0.0" 16 | }, 17 | "healthier": { 18 | "ignore": [ 19 | "__sapper__", 20 | "rollup.config.js" 21 | ] 22 | }, 23 | "dependencies": { 24 | "@types/node": "^16.0.1", 25 | "aria-attributes": "^2.0.0", 26 | "deepmerge": "^4.2.2", 27 | "diff-match-patch": "^1.0.5", 28 | "glob": "^7.1.7", 29 | "hast-util-sanitize": "^4.0.0", 30 | "hast-util-select": "^5.0.0", 31 | "hast-util-to-string": "^1.0.4", 32 | "hastscript": "^7.0.1", 33 | "html-element-attributes": "^3.0.0", 34 | "property-information": "^6.0.1", 35 | "rehype-parse": "^7.0.1", 36 | "rehype-raw": "^5.1.0", 37 | "rehype-sanitize": "^4.0.0", 38 | "rehype-stringify": "^8.0.0", 39 | "remark-parse": "^9.0.0", 40 | "remark-rehype": "^8.1.0", 41 | "string-pixel-width": "^1.10.0", 42 | "svg-element-attributes": "^2.0.0", 43 | "to-vfile": "^7.1.0", 44 | "unified": "^9.2.1", 45 | "unist-util-is": "^5.1.0", 46 | "unist-util-visit": "^3.1.0", 47 | "unist-util-visit-parents": "^4.1.1", 48 | "universal-base64url": "^1.1.0", 49 | "vfile-reporter": "^7.0.1" 50 | }, 51 | "devDependencies": { 52 | "c8": "^7.7.3", 53 | "healthier": "^4.0.0", 54 | "prettier": "^2.3.2", 55 | "tap": "^15.0.9", 56 | "typescript": "^4.3.5" 57 | }, 58 | "private": true 59 | } 60 | -------------------------------------------------------------------------------- /tests/fixtures/annotations-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "http://www.w3.org/ns/anno.jsonld", 3 | "id": "http://example.org/collection1", 4 | "type": "AnnotationCollection", 5 | "label": "Annotations Collection", 6 | "total": 2, 7 | "first": { 8 | "id": "http://example.org/page1", 9 | "type": "AnnotationPage", 10 | "label": "Annotations Page", 11 | "items": [ 12 | { 13 | "id": "http://example.com/annotations1", 14 | "type": "Annotation", 15 | "motivation": "bookmarking", 16 | "creator": { 17 | "id": "http://example.org/user1", 18 | "type": "Person", 19 | "name": "A. Person", 20 | "nickname": "user1" 21 | }, 22 | "created": "2015-10-13T13:00:00Z", 23 | "stylesheet": { 24 | "id": "http://example.org/stylesheet1", 25 | "type": "CssStylesheet" 26 | }, 27 | "target": { 28 | "source": "http://example.com/document1", 29 | "styleClass": "Bookmark", 30 | "selector": { 31 | "type": "CssSelector", 32 | "value": "h3:first-of-type" 33 | } 34 | } 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/fixtures/css-single.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1", 8 | "type": "Annotation", 9 | "motivation": "bookmarking", 10 | "creator": { 11 | "id": "http://example.org/user1", 12 | "type": "Person", 13 | "name": "A. Person", 14 | "nickname": "user1" 15 | }, 16 | "created": "2015-10-13T13:00:00Z", 17 | "stylesheet": { 18 | "id": "http://example.org/stylesheet1", 19 | "type": "CssStylesheet" 20 | }, 21 | "target": { 22 | "source": "https://example.com/tests/fixtures/css-single.input.html", 23 | "selector": { 24 | "type": "CssSelector", 25 | "value": "h3:first-of-type" 26 | } 27 | } 28 | }, 29 | { 30 | "id": "http://example.com/annotations1", 31 | "type": "Annotation", 32 | "motivation": "bookmarking", 33 | "creator": { 34 | "id": "http://example.org/user1", 35 | "type": "Person", 36 | "name": "A. Person", 37 | "nickname": "user1" 38 | }, 39 | "created": "2015-10-13T13:00:00Z", 40 | "stylesheet": { 41 | "id": "http://example.org/stylesheet1", 42 | "type": "CssStylesheet" 43 | }, 44 | "target": { 45 | "source": "https://example.com/tests/fixtures/test-that-unmatched-sources-are-not-processed", 46 | "selector": { 47 | "type": "CssSelector", 48 | "value": "h3:first-of-type" 49 | } 50 | } 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /tests/fixtures/css-single.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/css-single.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/fragment-multibody.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1", 8 | "type": "Annotation", 9 | "motivation": "bookmarking", 10 | "creator": { 11 | "id": "http://example.org/user1", 12 | "type": "Person", 13 | "name": "A. Person", 14 | "nickname": "user1" 15 | }, 16 | "created": "2015-10-13T13:00:00Z", 17 | "stylesheet": { 18 | "id": "http://example.org/stylesheet1", 19 | "type": "CssStylesheet" 20 | }, 21 | "body": [ 22 | { 23 | "type": "TextualBody", 24 | "purpose": "tagging", 25 | "value": "love" 26 | }, 27 | { 28 | "type": "TextualBody", 29 | "value": "

j'adore !

", 30 | "format": "text/html", 31 | "language": "fr", 32 | "purpose": "describing" 33 | } 34 | ], 35 | "target": { 36 | "source": "https://example.com/tests/fixtures/fragment-multibody.input.html", 37 | "styleClass": "Bookmarked", 38 | "selector": { 39 | "type": "FragmentSelector", 40 | "value": "test-id" 41 | } 42 | } 43 | }, 44 | { 45 | "id": "http://example.com/annotations2-does-not-exist", 46 | "type": "Annotation", 47 | "motivation": "bookmarking", 48 | "creator": { 49 | "id": "http://example.org/user1", 50 | "type": "Person", 51 | "name": "A. Person", 52 | "nickname": "user1" 53 | }, 54 | "created": "2015-10-13T13:00:00Z", 55 | "stylesheet": { 56 | "id": "http://example.org/stylesheet1", 57 | "type": "CssStylesheet" 58 | }, 59 | "body": [ 60 | { 61 | "type": "TextualBody", 62 | "purpose": "tagging", 63 | "value": "love" 64 | }, 65 | { 66 | "type": "TextualBody", 67 | "value": "

j'adore !

", 68 | "format": "text/html", 69 | "language": "fr", 70 | "purpose": "describing" 71 | } 72 | ], 73 | "target": { 74 | "source": "https://example.com/tests/fixtures/fragment-multibody.input.html", 75 | "styleClass": "Bookmarked", 76 | "selector": { 77 | "type": "FragmentSelector", 78 | "value": "this-id-does-not-exist-in-the-text" 79 | } 80 | } 81 | } 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /tests/fixtures/fragment-multibody.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/fragment-multibody.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/poetry-linebreaks.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "https://ink-api-dev-dot-thematic-cider-139815.appspot.com/notes/ePBawQ5aWWfiN6nyLprBmH-9fe723b3cf", 8 | "motivation": "highlighting", 9 | "target": { 10 | "source": "https://example.com/tests/fixtures/poetry-linebreaks.input.html", 11 | "selector": { 12 | "type": "TextQuoteSelector", 13 | "exact": "Notre barque glisse sur l’onde\nQue dorent de brûlants rayons;\nSa marche lente et vagabonde\nTémoigne que des bras mignons,\nPleins d’ardeur, mais encore novices,\nTout fiers de ce nouveau travail,\nMènent au gré de leurs caprices\nLes rames et le gouvernail.", 14 | "prefix": "T TAYLOR, BREAD STREET HILL.\n\n\n\n", 15 | "suffix": "\nSoudain trois cris se font ente" 16 | } 17 | }, 18 | "published": "2020-08-12T11:11:32.527Z", 19 | "updated": "2020-08-12T11:11:32.527Z", 20 | "body": [ 21 | { 22 | "content": "
Notre barque glisse sur l’onde
\nQue dorent de brûlants rayons;
\nSa marche lente et vagabonde
\nTémoigne que des bras mignons,
\nPleins d’ardeur, mais encore novices,
\nTout fiers de ce nouveau travail,
\nMènent au gré de leurs caprices
\nLes rames et le gouvernail.
", 23 | "language": null 24 | } 25 | ], 26 | "tags": [], 27 | "source": { 28 | "id": "https://ink-api-dev-dot-thematic-cider-139815.appspot.com/sources/ePBawQ5aWWfiN6nyLprBmH-f2e212bc7d/", 29 | "name": "Alice", 30 | "type": "Source", 31 | "published": "2020-07-14T16:23:55.125Z", 32 | "updated": "2020-07-14T16:23:55.125Z", 33 | "shortId": "ePBawQ5aWWfiN6nyLprBmH-f2e212bc7d", 34 | "author": [], 35 | "editor": [], 36 | "contributor": [], 37 | "creator": [], 38 | "illustrator": [], 39 | "publisher": [], 40 | "translator": [], 41 | "copyrightHolder": [] 42 | }, 43 | "type": "Note", 44 | "shortId": "ePBawQ5aWWfiN6nyLprBmH-9fe723b3cf" 45 | }, 46 | { 47 | "id": "http://example.com/annotations1", 48 | "type": "Annotation", 49 | "motivation": "bookmarking", 50 | "creator": { 51 | "id": "http://example.org/user1", 52 | "type": "Person", 53 | "name": "A. Person", 54 | "nickname": "user1" 55 | }, 56 | "created": "2015-10-13T13:00:00Z", 57 | "stylesheet": { 58 | "id": "http://example.org/stylesheet1", 59 | "type": "CssStylesheet" 60 | }, 61 | "target": { 62 | "source": "https://example.com/tests/fixtures/test-that-unmatched-sources-are-not-processed", 63 | "selector": { 64 | "type": "CssSelector", 65 | "value": "h3:first-of-type" 66 | } 67 | } 68 | } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /tests/fixtures/range.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1", 8 | "type": "Annotation", 9 | "motivation": "bookmarking", 10 | "creator": { 11 | "id": "http://example.org/user1", 12 | "type": "Person", 13 | "name": "A. Person", 14 | "nickname": "user1" 15 | }, 16 | "created": "2015-10-13T13:00:00Z", 17 | "stylesheet": { 18 | "id": "http://example.org/stylesheet1", 19 | "type": "CssStylesheet" 20 | }, 21 | "target": { 22 | "source": "https://example.com/tests/fixtures/range.input.html", 23 | "selector": { 24 | "type": "RangeSelector", 25 | "startSelector": { 26 | "type": "XPathSelector", 27 | "value": "/html[1]/body[1]/h1[1]" 28 | }, 29 | "endSelector": { 30 | "type": "CssSelector", 31 | "value": "h3:first-of-type" 32 | } 33 | } 34 | } 35 | }, 36 | { 37 | "id": "http://example.com/annotations1", 38 | "type": "Annotation", 39 | "motivation": "bookmarking", 40 | "creator": { 41 | "id": "http://example.org/user1", 42 | "type": "Person", 43 | "name": "A. Person", 44 | "nickname": "user1" 45 | }, 46 | "created": "2015-10-13T13:00:00Z", 47 | "stylesheet": { 48 | "id": "http://example.org/stylesheet1", 49 | "type": "CssStylesheet" 50 | }, 51 | "target": { 52 | "source": "https://example.com/tests/fixtures/range.input.html", 53 | "selector": { 54 | "type": "RangeSelector", 55 | "startSelector": { 56 | "type": "XPathSelector", 57 | "value": "/html[1]/body[1]/h1[2]" 58 | }, 59 | "endSelector": { 60 | "type": "CssSelector", 61 | "value": "h3:first-of-type" 62 | } 63 | } 64 | } 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /tests/fixtures/range.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/range.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/refinedby.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1", 8 | "type": "Annotation", 9 | "motivation": "highlighting", 10 | "created": "2015-10-13T13:00:00Z", 11 | "body": [ 12 | { 13 | "type": "TextualBody", 14 | "value": "

j'adore !

", 15 | "format": "text/html", 16 | "language": "fr", 17 | "purpose": "commenting" 18 | } 19 | ], 20 | "target": { 21 | "source": "https://example.com/tests/fixtures/refinedby.input.html", 22 | "styleClass": "Bookmarked", 23 | "selector": { 24 | "type": "CssSelector", 25 | "value": "h3:first-of-type", 26 | "refinedBy": { 27 | "type": "TextPositionSelector", 28 | "start": 0, 29 | "end": 12 30 | } 31 | } 32 | } 33 | }, 34 | { 35 | "id": "http://example.com/annotations2", 36 | "type": "Annotation", 37 | "motivation": "highlighting", 38 | "created": "2015-10-13T13:00:00Z", 39 | "body": [ 40 | { 41 | "type": "TextualBody", 42 | "value": "

j'adore !

", 43 | "format": "text/html", 44 | "language": "fr", 45 | "purpose": "commenting" 46 | } 47 | ], 48 | "target": { 49 | "source": "https://example.com/tests/fixtures/refinedby.input.html", 50 | "styleClass": "Bookmarked", 51 | "selector": { 52 | "type": "XPathSelector", 53 | "value": "/html[1]/body[1]/h1[1]", 54 | "refinedBy": { 55 | "type": "TextQuoteSelector", 56 | "exact": "entire bygone figure" 57 | } 58 | } 59 | } 60 | }, 61 | { 62 | "id": "http://example.com/annotations3-no-refine-match", 63 | "type": "Annotation", 64 | "motivation": "highlighting", 65 | "created": "2015-10-13T13:00:00Z", 66 | "body": [ 67 | { 68 | "type": "TextualBody", 69 | "value": "

j'adore !

", 70 | "format": "text/html", 71 | "language": "fr", 72 | "purpose": "commenting" 73 | } 74 | ], 75 | "target": { 76 | "source": "https://example.com/tests/fixtures/refinedby.input.html", 77 | "styleClass": "Bookmarked", 78 | "selector": { 79 | "type": "CssSelector", 80 | "value": "ul:first-of-type", 81 | "refinedBy": { 82 | "type": "CssSelector", 83 | "value": "li:first-of-type" 84 | } 85 | } 86 | } 87 | } 88 | ] 89 | } 90 | -------------------------------------------------------------------------------- /tests/fixtures/refinedby.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/refinedby.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/template.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baldurbjarnason/rehype-annotate/071f918e9012e84220d23a4a3b770589dfa409d3/tests/fixtures/template.html -------------------------------------------------------------------------------- /tests/fixtures/text-position-values.reference.txt: -------------------------------------------------------------------------------- 1 | 1. 2 | 3 | pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came. 4 | Stirs ending exceeding fond muster fall Bagshot. 5 | Resilient Garulf key quest abandon knives 6 | 7 | ---- 8 | 2. 9 | 10 | tobacco chicken ridiculous 11 | ---- 12 | 3. 13 | chap. Big grey beard 14 | ---- 15 | 4. 16 | pon windlance 17 | ---- -------------------------------------------------------------------------------- /tests/fixtures/text-position.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations-whitespace", 8 | "type": "Annotation", 9 | "motivation": "highlighting", 10 | "created": "2015-10-13T13:00:00Z", 11 | "body": [ 12 | { 13 | "type": "TextualBody", 14 | "value": "

j'adore !

", 15 | "format": "text/html", 16 | "language": "fr", 17 | "purpose": "commenting" 18 | } 19 | ], 20 | "target": { 21 | "source": "https://example.com/tests/fixtures/text-position.input.html", 22 | "styleClass": "Bookmarked", 23 | "selector": { 24 | "type": "TextPositionSelector", 25 | "start": 5, 26 | "end": 6 27 | } 28 | } 29 | }, 30 | { 31 | "id": "http://example.com/annotations1", 32 | "type": "Annotation", 33 | "motivation": "highlighting", 34 | "created": "2015-10-13T13:00:00Z", 35 | "body": [ 36 | { 37 | "type": "TextualBody", 38 | "value": "

j'adore !

", 39 | "format": "text/html", 40 | "language": "fr", 41 | "purpose": "commenting" 42 | } 43 | ], 44 | "target": { 45 | "source": "https://example.com/tests/fixtures/text-position.input.html", 46 | "styleClass": "Bookmarked", 47 | "selector": { 48 | "type": "TextPositionSelector", 49 | "start": 176, 50 | "end": 368 51 | } 52 | } 53 | }, 54 | { 55 | "id": "http://example.com/annotations2", 56 | "type": "Annotation", 57 | "motivation": "highlighting", 58 | "created": "2015-10-13T13:00:00Z", 59 | "body": [ 60 | { 61 | "type": "TextualBody", 62 | "value": "

j'adore !

", 63 | "format": "text/html", 64 | "language": "fr", 65 | "purpose": "commenting" 66 | } 67 | ], 68 | "target": { 69 | "source": "https://example.com/tests/fixtures/text-position.input.html", 70 | "styleClass": "Bookmarked", 71 | "selector": { 72 | "type": "TextPositionSelector", 73 | "start": 559, 74 | "end": 586 75 | } 76 | } 77 | }, 78 | { 79 | "id": "http://example.com/annotations3", 80 | "type": "Annotation", 81 | "motivation": "highlighting", 82 | "created": "2015-10-13T13:00:00Z", 83 | "body": [ 84 | { 85 | "type": "TextualBody", 86 | "value": "

j'adore !

", 87 | "format": "text/html", 88 | "language": "fr", 89 | "purpose": "commenting" 90 | } 91 | ], 92 | "target": { 93 | "source": "https://example.com/tests/fixtures/text-position.input.html", 94 | "styleClass": "Bookmarked", 95 | "selector": { 96 | "type": "TextPositionSelector", 97 | "start": 1664, 98 | "end": 1684 99 | } 100 | } 101 | }, 102 | { 103 | "id": "http://example.com/annotations4", 104 | "type": "Annotation", 105 | "motivation": "highlighting", 106 | "created": "2015-10-13T13:00:00Z", 107 | "body": [ 108 | { 109 | "type": "TextualBody", 110 | "value": "

j'adore !

", 111 | "format": "text/html", 112 | "language": "fr", 113 | "purpose": "commenting" 114 | } 115 | ], 116 | "target": { 117 | "source": "https://example.com/tests/fixtures/text-position.input.html", 118 | "styleClass": "Bookmarked", 119 | "selector": { 120 | "type": "TextPositionSelector", 121 | "start": 1779, 122 | "end": 1792 123 | } 124 | } 125 | } 126 | ] 127 | } 128 | -------------------------------------------------------------------------------- /tests/fixtures/text-position.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/text-position.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/text-position.string.reference.txt: -------------------------------------------------------------------------------- 1 | Test 2 | 3 | Likes pony painted entire bygone figure Ravenhill ashes. 4 | Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came. 5 | Stirs ending exceeding fond muster fall Bagshot. 6 | Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others! 7 | World bodies gifted tobacco chicken ridiculous wasting. 8 | Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair. 9 | 10 | Muil. 11 | Tom. 12 | Bracegirdles. 13 | Gon. 14 | Bagginses. 15 | 16 | 17 | Webs grog purge hid adventure Elf-maiden gangrel arrived labyrinth. 18 | Bought bower birdsong manners Durin wood lads false. 19 | From withering Thofin slug brings! 20 | Arrives whereabouts who brooded mist outer vile Ingrates responsible. 21 | Courtyard gracious sticky oncoming Théoden's. 22 | 23 | Beer sigh promised enemies abandon know Arod lord's. 24 | Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot. 25 | 26 | Farthing. 27 | Bru-ra-hroom. 28 | Dimrill. 29 | Defiler. 30 | Bert. 31 | 32 | 33 | Nenya enjoy rallying stuffing one's well-earned machine? 34 | Skins fouler Rhosgobel you've about values question heirloom? 35 | Feeling panic troublemakers stings heads Aragorn reckoning spent. 36 | Halt knives quarry Bilbo captive tail losing anchored hasn't. 37 | Outscoring circles throat wanes Arkenstone festers endure three. 38 | 39 | Caretaker saws raised reaction vines lanterns Eldar imaginable. 40 | Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot. 41 | 42 | 43 | 44 | 45 | Defeated 46 | Concludes 47 | Ceremonial 48 | Hang 49 | Rue 50 | 51 | 52 | 53 | 54 | Invitations 55 | branch 56 | firm 57 | evil 58 | grumbling 59 | dressed 60 | 61 | 62 | Relight 63 | wearied 64 | ignoring 65 | came 66 | safety 67 | give 68 | 69 | 70 | Profit 71 | linger 72 | else 73 | enemy's 74 | fitted 75 | motion 76 | 77 | 78 | Warrior 79 | gathered 80 | any 81 | secure 82 | daylight 83 | razor-sharp 84 | 85 | 86 | Racket 87 | travel 88 | astride 89 | firm 90 | courage 91 | named 92 | 93 | 94 | Long-forgotten 95 | frightening 96 | stayed 97 | change 98 | outer 99 | evacuate 100 | 101 | 102 | 103 | 104 | pony 105 | pauses 106 | board 107 | bite 108 | again 109 | up 110 | 111 | 112 | 113 | Fate rumor swiftly knife endure sense Mithril lands. 114 | Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden! 115 | 116 | You shall be the Fellowship of the Ring. 117 | —Gríma, well wept hometown behalf 118 | 119 | Quietly answering down landlord Girion watchtower closed? 120 | Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance! 121 | Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog! 122 | Chap Samwise mouths descendant princeling breathing fiery. 123 | Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained lippy Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms. 124 | 125 | 126 | Slug 127 | Upset sending stench Undómiel neck charming name's overcrowd. 128 | Fleet 129 | Employment watched Galion tracers bled irregular buy rides brigands. 130 | Country servant eight blunt caves legends Fells source! 131 | Glass 132 | Prisoner King's moldy disturbing 3434 host chiefest crevice. 133 | Licensed hewn suspect sway Elfling wounded separate knowledge. 134 | Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing. 135 | 136 | 137 | 138 | Short game count 139 | 140 | Text 141 | 142 | 143 | 144 | Email 145 | 146 | 147 | 148 | Password 149 | 150 | 151 | 152 | Url 153 | 154 | 155 | 156 | Number 157 | 158 | 159 | 160 | Tel 161 | 162 | 163 | 164 | Search 165 | 166 | 167 | 168 | Time 169 | 170 | 171 | 172 | Date 173 | 174 | 175 | 176 | Datetime-local 177 | 178 | 179 | 180 | Week 181 | 182 | 183 | 184 | Textarea 185 | 186 | 187 | 188 | 189 | Twitching taters 190 | 191 | Month 192 | 193 | 194 | 195 | laughing increase 196 | 197 | 198 | Color 199 | 200 | 201 | 202 | File 203 | 204 | 205 | 206 | Hidden 207 | 208 | 209 | 210 | Image 211 | 212 | 213 | 214 | s sword scare hide 215 | vile brats 216 | kept beauty 217 | drown uses 218 | 219 | 220 | Range 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | blimey soul 233 | 234 | Select 235 | 236 | 237 | place 238 | abyss 239 | strangely 240 | 241 | 242 | weak 243 | observation 244 | find 245 | 246 | 247 | 248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /tests/fixtures/text-quote.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1-inexact", 8 | "type": "Annotation", 9 | "motivation": "highlighting", 10 | "created": "2015-10-13T13:00:00Z", 11 | "body": [ 12 | { 13 | "value": "

j'adore !

", 14 | "format": "text/html", 15 | "language": "fr", 16 | "purpose": "commenting" 17 | } 18 | ], 19 | "target": { 20 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 21 | "styleClass": "Bookmarked", 22 | "selector": { 23 | "type": "TextQuoteSelector", 24 | "prefix": "well-earned machine?\n", 25 | "exact": "Skins fouler Rhosgobel you've about values blingon heirloom?", 26 | "suffix": "\nFeeling panic" 27 | } 28 | } 29 | }, 30 | { 31 | "id": "http://example.com/annotations2-inexact", 32 | "type": "Annotation", 33 | "motivation": "highlighting", 34 | "created": "2015-10-13T13:00:00Z", 35 | "body": [ 36 | { 37 | "type": "TextualBody", 38 | "value": "\n\nj'adore !\n\n", 39 | "format": "text/markdown", 40 | "language": "fr", 41 | "purpose": "commenting" 42 | } 43 | ], 44 | "target": { 45 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 46 | "styleClass": "Bookmarked", 47 | "selector": { 48 | "type": "TextQuoteSelector", 49 | "prefix": "bogomips", 50 | "exact": "quarry Bilbo captive", 51 | "suffix": "bogomips" 52 | } 53 | } 54 | }, 55 | { 56 | "id": "http://example.com/annotations1-non-existent", 57 | "type": "Annotation", 58 | "motivation": "highlighting", 59 | "created": "2015-10-13T13:00:00Z", 60 | "body": [ 61 | { 62 | "type": "TextualBody", 63 | "value": "

j'adore !

", 64 | "format": "text/html", 65 | "language": "fr", 66 | "purpose": "commenting" 67 | } 68 | ], 69 | "target": { 70 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 71 | "styleClass": "Bookmarked", 72 | "selector": { 73 | "type": "TextQuoteSelector", 74 | "exact": "gaudeamus igitur" 75 | } 76 | } 77 | }, 78 | { 79 | "id": "http://example.com/annotations2-non-existent", 80 | "type": "Annotation", 81 | "motivation": "highlighting", 82 | "created": "2015-10-13T13:00:00Z", 83 | "body": [ 84 | { 85 | "type": "TextualBody", 86 | "value": "

j'adore !

", 87 | "format": "text/html", 88 | "language": "fr", 89 | "purpose": "commenting" 90 | } 91 | ], 92 | "target": { 93 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 94 | "styleClass": "Bookmarked", 95 | "selector": { 96 | "type": "TextQuoteSelector", 97 | "exact": "Sweeps there's nightshade Gandalyabba dabba dooo" 98 | } 99 | } 100 | }, 101 | { 102 | "id": "http://example.com/annotations3-non-existent", 103 | "type": "Annotation", 104 | "motivation": "highlighting", 105 | "created": "2015-10-13T13:00:00Z", 106 | "body": [ 107 | { 108 | "type": "TextualBody", 109 | "value": "

j'adore !

", 110 | "format": "text/html", 111 | "language": "fr", 112 | "purpose": "commenting" 113 | } 114 | ], 115 | "target": { 116 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 117 | "styleClass": "Bookmarked", 118 | "selector": { 119 | "type": "TextQuoteSelector", 120 | "exact": "Example Use Case: Megan has very limited ability to hear sound, and prefers to read captions when interacting with videos. She uses her annotation client to make a comment on such a video, and to help others in the same situation, the client includes that the video has this accessibility feature." 121 | } 122 | } 123 | }, 124 | { 125 | "id": "http://example.com/annotations4-non-existent", 126 | "type": "Annotation", 127 | "motivation": "highlighting", 128 | "created": "2015-10-13T13:00:00Z", 129 | "body": [ 130 | { 131 | "type": "TextualBody", 132 | "value": "

j'adore !

", 133 | "format": "text/html", 134 | "language": "fr", 135 | "purpose": "commenting" 136 | } 137 | ], 138 | "target": { 139 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 140 | "styleClass": "Bookmarked", 141 | "selector": { 142 | "type": "TextQuoteSelector", 143 | "exact": "Flavor balls Tilda rolls nab beat stammer. *** DOES NOT MATCH*** Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. *** DOES NOT MATCH*** Mouse dwelt regained lippy Noldorin." 144 | } 145 | } 146 | }, 147 | { 148 | "id": "http://example.com/annotations1", 149 | "type": "Annotation", 150 | "motivation": "highlighting", 151 | "created": "2015-10-13T13:00:00Z", 152 | "body": [ 153 | { 154 | "type": "TextualBody", 155 | "value": "

j'adore !

", 156 | "format": "text/plain", 157 | "language": "fr", 158 | "purpose": "commenting" 159 | } 160 | ], 161 | "target": { 162 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 163 | "styleClass": "Bookmarked", 164 | "selector": { 165 | "type": "TextQuoteSelector", 166 | "exact": "pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.\nStirs ending exceeding fond muster fall Bagshot.\nResilient Garulf key quest abandon knives" 167 | } 168 | } 169 | }, 170 | { 171 | "id": "http://example.com/annotations2", 172 | "type": "Annotation", 173 | "motivation": "highlighting", 174 | "created": "2015-10-13T13:00:00Z", 175 | "body": [ 176 | { 177 | "type": "TextualBody", 178 | "value": "

j'adore !

", 179 | "format": "text/html", 180 | "language": "fr", 181 | "purpose": "commenting" 182 | } 183 | ], 184 | "target": { 185 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 186 | "styleClass": "Bookmarked", 187 | "selector": { 188 | "type": "TextQuoteSelector", 189 | "exact": " tobacco chicken ridiculous", 190 | "prefix": "World bodies gifted" 191 | } 192 | } 193 | }, 194 | { 195 | "id": "http://example.com/annotations3", 196 | "type": "Annotation", 197 | "motivation": "highlighting", 198 | "created": "2015-10-13T13:00:00Z", 199 | "body": [ 200 | { 201 | "type": "TextualBody", 202 | "value": "

j'adore !

", 203 | "format": "text/html", 204 | "language": "fr", 205 | "purpose": "commenting" 206 | } 207 | ], 208 | "target": { 209 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 210 | "styleClass": "Bookmarked", 211 | "selector": { 212 | "type": "TextQuoteSelector", 213 | "exact": "chap. Big grey beard", 214 | "prefix": "Elderly ", 215 | "suffix": ", pointy hat." 216 | } 217 | } 218 | }, 219 | { 220 | "id": "http://example.com/annotations4", 221 | "type": "Annotation", 222 | "motivation": "highlighting", 223 | "created": "2015-10-13T13:00:00Z", 224 | "body": [ 225 | { 226 | "type": "TextualBody", 227 | "value": "

I adore!

", 228 | "format": "text/html" 229 | } 230 | ], 231 | "target": { 232 | "source": "https://example.com/tests/fixtures/text-quote.input.html", 233 | "styleClass": "Bookmarked", 234 | "selector": { 235 | "type": "TextQuoteSelector", 236 | "exact": "pon windlance", 237 | "suffix": ". Didn't stage" 238 | } 239 | } 240 | } 241 | ] 242 | } 243 | -------------------------------------------------------------------------------- /tests/fixtures/text-quote.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 | Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came. 6 | Stirs ending exceeding fond muster fall Bagshot. 7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/xpath-single.annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.org/page1", 3 | "type": "AnnotationPage", 4 | "label": "Annotations Page", 5 | "items": [ 6 | { 7 | "id": "http://example.com/annotations1", 8 | "type": "Annotation", 9 | "motivation": "bookmarking", 10 | "creator": { 11 | "id": "http://example.org/user1", 12 | "type": "Person", 13 | "name": "A. Person", 14 | "nickname": "user1" 15 | }, 16 | "created": "2015-10-13T13:00:00Z", 17 | "stylesheet": { 18 | "id": "http://example.org/stylesheet1", 19 | "type": "CssStylesheet" 20 | }, 21 | "target": { 22 | "source": "https://example.com/tests/fixtures/xpath-single.input.html", 23 | "styleClass": "Bookmarked", 24 | "selector": { 25 | "type": "XPathSelector", 26 | "value": "/html[1]/body[1]/h1[1]" 27 | } 28 | } 29 | }, 30 | { 31 | "id": "http://example.com/annotations2", 32 | "type": "Annotation", 33 | "motivation": "bookmarking", 34 | "creator": { 35 | "id": "http://example.org/user1", 36 | "type": "Person", 37 | "name": "A. Person", 38 | "nickname": "user1" 39 | }, 40 | "created": "2015-10-13T13:00:00Z", 41 | "stylesheet": { 42 | "id": "http://example.org/stylesheet1", 43 | "type": "CssStylesheet" 44 | }, 45 | "target": { 46 | "source": "https://example.com/tests/fixtures/xpath-single.input.html", 47 | "styleClass": "Bookmarked", 48 | "selector": { 49 | "type": "XPathSelector", 50 | "value": "/html[1]/./body[1]/h1[2]" 51 | } 52 | } 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /tests/fixtures/xpath-single.input.html: -------------------------------------------------------------------------------- 1 | 2 | Test 3 | 4 |

Likes pony painted entire bygone figure Ravenhill ashes.

5 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

6 |

Stirs ending exceeding fond muster fall Bagshot.

7 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

8 |

World bodies gifted tobacco chicken ridiculous wasting.

9 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

10 | 17 | 24 |

Beer sigh promised enemies abandon know Arod lord's.

25 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

26 |
    27 |
  1. Farthing.
  2. 28 |
  3. Bru-ra-hroom.
  4. 29 |
  5. Dimrill.
  6. 30 |
  7. Defiler.
  8. 31 |
  9. Bert.
  10. 32 |
33 |
    34 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 35 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 36 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 37 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 38 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 39 |
40 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

41 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
114 |

Fate rumor swiftly knife endure sense Mithril lands.

115 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

116 |
117 |

You shall be the Fellowship of the Ring.

118 | 119 |
120 |
Quietly answering down landlord Girion watchtower closed?
121 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

122 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
123 |
Chap Samwise mouths descendant princeling breathing fiery.
124 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

125 |
126 |
127 |
Slug
128 |
Upset sending stench Undómiel neck charming name's overcrowd.
129 |
Fleet
130 |
Employment watched Galion tracers bled irregular buy rides brigands.
131 |
Country servant eight blunt caves legends Fells source!
132 |
Glass
133 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
134 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
135 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
136 |
137 |
138 |
139 | Short game count 140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 151 |
152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 | 170 | 171 |
172 |
173 | 174 | 175 |
176 |
177 | 178 | 179 |
180 |
181 | 182 | 183 |
184 |
185 | 186 | 187 |
188 |
189 |
190 | Twitching taters 191 |
192 | 193 | 194 |
195 |
196 | 197 |
198 |
199 | 200 | 201 |
202 |
203 | 204 | 205 |
206 |
207 | 208 | 209 |
210 |
211 | 212 | 213 |
214 |
215 | 216 | 217 | 218 | 219 |
220 |
221 | 222 | 223 |
224 |
225 | 226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 | 234 |
235 | 236 | 248 |
249 |
250 |
251 | 252 | -------------------------------------------------------------------------------- /tests/fixtures/xpath-single.output.html: -------------------------------------------------------------------------------- 1 | Test 2 | 3 |

Likes pony painted entire bygone figure Ravenhill ashes.

4 |

Hinges lingered Orthanc raid vast tune. Were-worms expert thrush spilt condone terrible makes finds recover come pottery on? It must be taken deep into Mordor and cast back into the fiery chasm from whence it came.

5 |

Stirs ending exceeding fond muster fall Bagshot.

6 |

Resilient Garulf key quest abandon knives lifted niceties tonight disappeared strongest plates. Farthing ginger large. Nobody tosses a Dwarf. Makes Shadowfax nearly lesser south deceive hates 22nd missing others!

7 |

World bodies gifted tobacco chicken ridiculous wasting.

8 |

Forces group relative five her Gamgee master lift river-folk pale. Swords are no more use here. Seeks hanging unpredictable Sam fair.

9 | 16 | 23 |

Beer sigh promised enemies abandon know Arod lord's.

24 |

Rest peace enemy overlook liege person Gibbets year afford. Let the Ring-bearer decide. Gentlemen put shot.

25 |
    26 |
  1. Farthing.
  2. 27 |
  3. Bru-ra-hroom.
  4. 28 |
  5. Dimrill.
  6. 29 |
  7. Defiler.
  8. 30 |
  9. Bert.
  10. 31 |
32 |
    33 |
  1. Nenya enjoy rallying stuffing one's well-earned machine?
  2. 34 |
  3. Skins fouler Rhosgobel you've about values question heirloom?
  4. 35 |
  5. Feeling panic troublemakers stings heads Aragorn reckoning spent.
  6. 36 |
  7. Halt knives quarry Bilbo captive tail losing anchored hasn't.
  8. 37 |
  9. Outscoring circles throat wanes Arkenstone festers endure three.
  10. 38 |
39 |

Caretaker saws raised reaction vines lanterns Eldar imaginable.

40 |

Elderly chap. Big grey beard, pointy hat. Smallest meadow corrupt Khazad-dum cave dragons children taste wriggling pouring pon windlance. Didn't stage Muil to juice foundations fouler two frightened rightfully hoot.

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
DefeatedConcludesCeremonialHangRue
Invitationsbranchfirmevilgrumblingdressed
Relightweariedignoringcamesafetygive
Profitlingerelseenemy'sfittedmotion
Warriorgatheredanysecuredaylightrazor-sharp
Rackettravelastridefirmcouragenamed
Long-forgottenfrighteningstayedchangeouterevacuate
ponypausesboardbiteagainup
113 |

Fate rumor swiftly knife endure sense Mithril lands.

114 |

Way slinker snake sakes Luthien grasped reasonable! You cannot hide. I see you. There is no life in the void. Only death. Seduced avalanche anyone keeper Elf-maiden!

115 |
116 |

You shall be the Fellowship of the Ring.

117 | 118 |
119 |
Quietly answering down landlord Girion watchtower closed?
120 |

Maps Treebeard ranges breached strong forth malcontent reads eat birthright. Gandalf's death was not in vain. Nor would he have you give up hope. Farthing unfriendly tracked crawl whose bearer instance!

121 |
Paths dagger rockets Cirith. Barter sailed ruse advantage sun's Garulf? Brew corks Argonath trumpets seem. Fled servant doubting winter-thickets commoners Azog!
122 |
Chap Samwise mouths descendant princeling breathing fiery.
123 |

Sweeps there's nightshade Gandalf the Grey dragons guarding? Thrice delays boat speed Dwarf-city souls filth. Shattered Orthanc fiery victory broken choice. Flavor balls Tilda rolls nab beat stammer. Ropes ash though guarding Thrain Bucklebury Kili's Ranger? Reaches W wit father's Dwarf-city. Mouse dwelt regained Noldorin. Selfish clearing well Goblin-men gloom. Goblin-town rests brown win throne act otherwise. Tune worry remove deceive Eorlingas. Guard care failed kept unoccupied lowly Sméagol distances brown. Golf coast either Minas Morgul Elfling Radagast Isildur's serpent. Mere chance craftsmen Uruk-hai cracked risked lord's exchanged depend. Bracegirdles sowing loud girl jacketses. Deceit cheat tender behaving brace coneys 600 dragon's Guldur amazing industry. Asking Samwise cooking imaginable keen brewing ales prisoner. Prize spit thumping easy Radagast pass. One's o'clock 24th delayed sell Gorgoroth mushrooms.

124 |
125 |
126 |
Slug
127 |
Upset sending stench Undómiel neck charming name's overcrowd.
128 |
Fleet
129 |
Employment watched Galion tracers bled irregular buy rides brigands.
130 |
Country servant eight blunt caves legends Fells source!
131 |
Glass
132 |
Prisoner King's moldy disturbing 3434 host chiefest crevice.
133 |
Licensed hewn suspect sway Elfling wounded separate knowledge.
134 |
Encourage unhappy accorded bird sack ripe perfectly fireworks Southfarthing.
135 |
136 |
137 |
138 | Short game count 139 |
140 | 141 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 | 157 | 158 |
159 |
160 | 161 | 162 |
163 |
164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 |
175 |
176 | 177 | 178 |
179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | Twitching taters 190 |
191 | 192 | 193 |
194 |
195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 | 208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 | 216 | 217 | 218 |
219 |
220 | 221 | 222 |
223 |
224 | 225 |
226 |
227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 | 247 |
248 |
249 |
250 | 251 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | import { toVFile } from "to-vfile"; 2 | import { reporter } from "vfile-reporter"; 3 | import { attacher } from "../index.js"; 4 | import * as path from "path"; 5 | import glob from "glob"; 6 | import stringify from "rehype-stringify"; 7 | import parse from "rehype-parse"; 8 | import unified from "unified"; 9 | import tap from "tap"; 10 | import { createRequire } from "module"; 11 | import { fileURLToPath } from "url"; 12 | const __filename = fileURLToPath(import.meta.url); 13 | const __dirname = path.dirname(__filename).replace(process.cwd() + "/", ""); 14 | const require = createRequire(import.meta.url); 15 | // const fragment = { fragment: true }; 16 | 17 | async function processAnnotations(filepath, options) { 18 | let file; 19 | const input = await toVFile.read(filepath); 20 | try { 21 | file = await unified() 22 | .use(parse) 23 | .use(attacher, options) 24 | .use(stringify) 25 | .process(input); 26 | console.log(reporter(file)); 27 | } catch (err) { 28 | console.log(err); 29 | console.error(reporter(err)); 30 | } 31 | return file; 32 | } 33 | 34 | tap.test("rehype-annotate", async (t) => { 35 | const fixtures = glob.sync("fixtures/*.input.html", { cwd: __dirname }); 36 | for (const fixture of fixtures) { 37 | await t.test("basic " + fixture, async function (t) { 38 | const result = await processAnnotations(path.join(__dirname, fixture), { 39 | stimulus: fixture.includes("quote") || fixture.includes("xpath"), 40 | annotations: require("./" + 41 | fixture.replace("input.html", "annotations.json")).items, 42 | url: `https://example.com/tests/${fixture.replace(__dirname, "")}`, 43 | canonical: `https://canonical.example.com/tests/${fixture.replace( 44 | __dirname, 45 | "" 46 | )}`, 47 | }); 48 | const expected = String( 49 | toVFile.readSync( 50 | path.join(__dirname, fixture.replace("input.html", "output.html")) 51 | ) 52 | ); 53 | t.matchSnapshot(result.data.annotations, `${fixture} annotations`); 54 | // console.dir(result); 55 | t.equal(String(result.contents), expected); 56 | t.end(); 57 | }); 58 | } 59 | t.end(); 60 | }); 61 | --------------------------------------------------------------------------------