11import * as assert from "node:assert/strict" ;
22import { describe , it } from "node:test" ;
3- import { getBacklinkScrollElement , revealBacklinkReference } from "./backlinkScroll" ;
3+ import { getBacklinkScrollElement , revealBacklinkReference , scrollBacklinkTarget } from "./backlinkScroll" ;
44
55const element = ( classes : string [ ] , parent ?: HTMLElement ) : HTMLElement => {
66 const node = {
77 parentElement : parent ,
88 classList : { contains : ( name : string ) => classes . includes ( name ) } ,
9+ contains ( target : HTMLElement ) {
10+ let current = target ;
11+ while ( current ) {
12+ if ( current === this as unknown as HTMLElement ) {
13+ return true ;
14+ }
15+ current = current . parentElement ;
16+ }
17+ return false ;
18+ } ,
919 closest ( selector : string ) {
1020 let current = this as unknown as HTMLElement ;
1121 while ( current ) {
@@ -21,26 +31,55 @@ const element = (classes: string[], parent?: HTMLElement): HTMLElement => {
2131} ;
2232
2333describe ( "database backlink scrolling" , ( ) => {
24- it ( "scrolls the dock list instead of the expanded inner editor " , ( ) => {
34+ it ( "uses the database viewport inside the dock without selecting the list " , ( ) => {
2535 const panel = element ( [ "sy__backlink" ] ) ;
2636 const list = element ( [ "backlinkList" ] , panel ) ;
2737 const innerEditor = element ( [ "protyle-content" ] , list ) ;
28- assert . equal ( getBacklinkScrollElement ( element ( [ "av" ] , innerEditor ) ) , list ) ;
38+ const database = element ( [ "av" , "av--backlink" ] , innerEditor ) ;
39+ assert . equal ( getBacklinkScrollElement ( database ) , database ) ;
40+ assert . equal ( getBacklinkScrollElement ( element ( [ ] , database ) ) , database ) ;
2941 } ) ;
3042
31- it ( "scrolls the owning document for bottom backlinks" , ( ) => {
43+ it ( "uses the database viewport in bottom backlinks without selecting the owning document " , ( ) => {
3244 const ownerEditor = element ( [ "protyle-content" ] ) ;
3345 const panel = element ( [ "sy__backlink" , "sy__backlink--bottom" ] , ownerEditor ) ;
3446 const list = element ( [ "backlinkList" ] , panel ) ;
3547 const innerEditor = element ( [ "protyle-content" ] , list ) ;
36- assert . equal ( getBacklinkScrollElement ( element ( [ "av" ] , innerEditor ) ) , ownerEditor ) ;
48+ const database = element ( [ "av" , "av--backlink" ] , innerEditor ) ;
49+ assert . equal ( getBacklinkScrollElement ( database ) , database ) ;
3750 } ) ;
3851
3952 it ( "keeps ordinary database locating on the existing editor scroll path" , ( ) => {
4053 const editor = element ( [ "protyle-content" ] ) ;
4154 assert . equal ( getBacklinkScrollElement ( element ( [ "av" ] , editor ) ) , undefined ) ;
4255 } ) ;
4356
57+ it ( "locates each database independently while preserving the outer reading position" , ( ) => {
58+ const outer = element ( [ "backlinkList" ] ) ;
59+ outer . scrollTop = 240 ;
60+ const first = element ( [ "av" , "av--backlink" ] , outer ) ;
61+ const second = element ( [ "av" , "av--backlink" ] , outer ) ;
62+ [ first , second ] . forEach ( database => {
63+ Object . assign ( database , {
64+ scrollTop : 0 , clientHeight : 400 ,
65+ getBoundingClientRect : ( ) => ( { top : 100 } ) ,
66+ } ) ;
67+ } ) ;
68+ const reference = element ( [ ] , first ) ;
69+ reference . getBoundingClientRect = ( ) => ( { top : 1300 } ) as DOMRect ;
70+ assert . equal ( scrollBacklinkTarget ( first , reference ) , true ) ;
71+ assert . equal ( first . scrollTop , 1000 ) ;
72+ assert . equal ( second . scrollTop , 0 ) ;
73+ assert . equal ( outer . scrollTop , 240 ) ;
74+ assert . equal ( scrollBacklinkTarget ( second , reference ) , false ) ;
75+ assert . equal ( second . scrollTop , 0 ) ;
76+ const secondReference = element ( [ ] , second ) ;
77+ secondReference . getBoundingClientRect = reference . getBoundingClientRect ;
78+ assert . equal ( scrollBacklinkTarget ( second , secondReference ) , true ) ;
79+ assert . equal ( second . scrollTop , 1000 ) ;
80+ assert . equal ( outer . scrollTop , 240 ) ;
81+ } ) ;
82+
4483 it ( "reveals a clipped reference inside a long field without scrolling outside the cell" , ( ) => {
4584 const cell = element ( [ "av__cell" ] ) ;
4685 Object . assign ( cell , {
0 commit comments