@storyteller-platform/uri-fragment
A JavaScript library for parsing, building, and serializing URI fragments.
Supports:
- Anchor fragments (
#paragraph01) - Media fragments
(
#t=3.2,#xywh=25,25,50,50) - Text fragments
(
:~:text=the%20end) - Character fragments
(
#char=100,#char=100,150) - EPUB CFI
(
#epubcfi(/6/4!/4/10/3:10)) - XPointer
(
#xpointer(id("introduction"))) - KOReader crengine "xpointer",
a non-standard fragment to represent KOReader's crengine's non-standard
"xpointer" implementation (has almost nothing to do with the W3C XPointer
spec). (
#crengine(/body/DocFragment/body/div/p[4]/text()[1].64))
Also supports mixing fragments where supported by the spec(s). For example, any
URI fragment may contain one identifier and any number of directives, e.g.,
#paragraph01:~:text=first&text=second. Also, media identifiers may contain
multiple dimensions, e.g., #t=15,75&xywh=percent:25,25,50,50.
Installation
npm:
npm install @storyteller-platform/uri-fragment
yarn:
yarn add @storyteller-platform/uri-fragment
deno:
deno install npm:@storyteller-platform/uri-fragment
About
URI's may terminate with a URI fragment. Different media types have different
specifications regarding how to interpret these fragments, as well as (sometimes
complex) grammars for parsing them. Standard URI parsers (e.g., new URL()) do
not parse the fragment, returning it as is.
The goal of this library is to accept a fragment parsed by a URI parser and further parse it into a semantically useful object that can be inspected and operated on.
Usage
Parsing
// Parsing a text directive
const url = new URL("https://example.com/example#:~:text=permission,.")
const fragment = new UriFragment(url.hash)
console.log(fragment.directive.text[0]?.decodedTextStart)
// => "permission"
console.log(fragment.directive.text[0]?.decodedTextEnd)
// => "."
// Parsing a media identifier
const url = new URL(
"https://example.com/video.mp4#t=01:30,02:15&xywh=percent:25,25,50,50",
)
const fragment = new UriFragment(url.hash)
console.log(fragment.identifier?.kind)
// => "media"
console.log(fragment.identifier?.media.temporal?.parsedTimeStart)
// => 90
console.log(fragment.identifier?.media.spatial?.xCoord)
// => 25
Building
const fragment = new UriFragment()
fragment.directive.appendTextDirective("permission,.")
const media = new MediaDimensions()
media.temporal = new MediaTemporalDimension()
media.temporal.timeStart = "3.5"
fragment.setIdentifier("media", { media })
console.log(fragment.toString())
// => `#t=3.5:~:text=permission,.`
Development
This package lives in the Storyteller monorepo, and is developed alongside the Storyteller platform.
To get started with developing in the Storyteller monorepo, check out the development guides in the docs.