feat(koreader): one conversion route for every feature; bookmarks get web CFIs
Release / build-and-push (push) Successful in 2m14s
Release / build-and-push (push) Successful in 2m14s
Progress, highlights, notes, and bookmarks entered position conversion through three different doors: progress converted inline with an uncached converter, annotations through the facade, bookmarks not at all (the raw xpointer was stored verbatim, cfi_position stayed empty, and the web drawer's goToBookmark silently no-ops on cfi-less entries). Unify on the facade (ConvertToCanonical/ConvertFromCanonical): - annotationEpub context resolved once per push: media item + EPUB path shared by every annotation instead of re-fetched per entry - progress forward: the inline block becomes one facade call; non-reflowable formats pass through unchanged, and the cached converter stops re-parsing the book on every sync - progress reverse: convertCFIToXPointer delegates to reverseConvertCFI, keeping the stored percentage in play for the fallback ladder - bookmarks (bulk progress and /sync-bookmarks): pos0 resolves structural-only — bookmark text is a display label, never book text, so no context is supplied; webUsableCFI stores the result only for structural/exact epubcfi landings, discarding href/percentage results rather than storing dead drawer links. Also records percentage_location and origin_source on the legacy endpoint. - percentages thread through: highlights/notes/bookmarks pass the device percentage or the derived section percentage instead of a hardcoded 0, so the last-resort fallback lands near the true position instead of the document start - extendCFIByLength end-derivation now also fires on structural starts (it had silently stopped matching when the structural rung began landing starts with precision 'structural' rather than 'exact') Tests: the drop-cap xpointer through the facade with empty context (the bookmark scenario) must land structurally, not doc-start; webUsableCFI table covers the store/discard gate.
This commit is contained in:
@@ -666,3 +666,24 @@ func TestReverseIgnoresSingleCharContext(t *testing.T) {
|
||||
t.Errorf("single-char reverse context must fall back to percentage, got %s", reverse.Precision)
|
||||
}
|
||||
}
|
||||
|
||||
// The bookmark route supplies no context (bookmark text is a display
|
||||
// label, never book text), so the facade must still resolve the drop-cap
|
||||
// xpointer structurally instead of collapsing to the document start.
|
||||
func TestConvertToCanonical_DropCapEmptyContext(t *testing.T) {
|
||||
epubPath := writeDropCapEPUB(t)
|
||||
xp := "/body/DocFragment[2]/body/p[3]/span[1]/text().0"
|
||||
|
||||
loc := ConvertToCanonical(LocatorSourceKOReader, xp, 0.52, "", string(FormatGroupReflowable), epubPath, "")
|
||||
|
||||
t.Logf("facade drop-cap (no context) → %s (%s)", loc.CFI, loc.Precision)
|
||||
if loc.Precision != "structural" && loc.Precision != "exact" {
|
||||
t.Fatalf("expected structural/exact precision, got %s (%s)", loc.Precision, loc.CFI)
|
||||
}
|
||||
if !strings.HasPrefix(loc.CFI, "epubcfi(") {
|
||||
t.Fatalf("expected standard epubcfi, got %s", loc.CFI)
|
||||
}
|
||||
if strings.HasSuffix(loc.CFI, "/4/2/1:0)") {
|
||||
t.Errorf("empty-context conversion collapsed to doc start: %s", loc.CFI)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user