@@ -9,9 +9,11 @@ import debug_ from "debug";
99import { setImageClickHandler } from "@r2-navigator-js/electron/renderer" ;
1010import { takeSpawnEveryChannel } from "readium-desktop/common/redux/sagas/takeSpawnEvery" ;
1111import { eventChannel , buffers } from "redux-saga" ;
12- import { put as putTyped } from "typed-redux-saga" ;
12+ import { put as putTyped , call as callTyped } from "typed-redux-saga" ;
1313import { readerLocalActionSetImageClick } from "../actions" ;
1414import { IEventPayload_R2_EVENT_IMAGE_CLICK } from "@r2-navigator-js/electron/common/events" ;
15+ import { cleanupStr } from "./search/transliteration" ;
16+ import { getResourceCache } from "readium-desktop/common/redux/sagas/resourceCache" ;
1517
1618// Logger
1719const filename_ = "readium-desktop:renderer:reader:saga:img" ;
@@ -44,6 +46,143 @@ function* webviewImageClick(payload: IEventPayload_R2_EVENT_IMAGE_CLICK) {
4446
4547 debug ( "IMAGE_CLICK received :" , payload ) ;
4648 yield * putTyped ( readerLocalActionSetImageClick . build ( payload ) ) ;
49+
50+ const { hostDocumentURL : source , cssSelectorOf_HTMLImg_SVGImage_SVGFragment } = payload ;
51+
52+ const cacheDoc = yield * callTyped ( getResourceCache , source ) ;
53+ const xmlDom = cacheDoc ?. xmlDom ;
54+
55+ const rootElem = xmlDom . body ;
56+ const imgElem = xmlDom . querySelector ( cssSelectorOf_HTMLImg_SVGImage_SVGFragment ) ;
57+ console . log ( "IMGElem" , imgElem ) ;
58+ console . log ( "ImgElem Attributes" , imgElem . attributes ) ;
59+ // const altAttributes = imgElem.getAttribute("alt");
60+ // const titleAttributes = imgElem.getAttribute("title");
61+ // const ariaLabelAttributes = imgElem.getAttribute("aria-label");
62+ const ariaDetailsAttributes = imgElem . getAttribute ( "aria-details" ) ;
63+ console . log ( "ariaDetailsAttributes" , ariaDetailsAttributes ) ;
64+ const ariaDescribedbyAttributes = imgElem . getAttribute ( "aria-describedby" ) ;
65+ console . log ( "ariaDescribedbyAttributes" , ariaDescribedbyAttributes ) ;
66+
67+
68+ // https://kb.daisy.org/publishing/docs/html/images-desc.html
69+
70+ // is Surrounded by a Figure tag ?
71+ let figureElem = undefined ;
72+ {
73+ let currElem = imgElem ;
74+ while ( rootElem !== currElem . parentElement ) {
75+ if ( currElem . nodeName === "FIGURE" || currElem . nodeName === "figure" ) {
76+ figureElem = currElem ;
77+ console . log ( "FIGURE ELEM" , figureElem ) ;
78+ break ;
79+ }
80+ currElem = currElem . parentElement ;
81+ }
82+ }
83+
84+ let detailsText = "" ;
85+ if ( ariaDetailsAttributes ) {
86+ const elem = xmlDom . getElementById ( ariaDetailsAttributes ) ;
87+ if ( elem ) {
88+ detailsText = cleanupStr ( elem . textContent || "" ) ;
89+ console . log ( detailsText ) ;
90+ }
91+ }
92+
93+ let describedbyText = "" ;
94+ if ( ariaDescribedbyAttributes ) {
95+ const elem = xmlDom . getElementById ( ariaDescribedbyAttributes ) ;
96+ if ( elem ) {
97+ describedbyText = cleanupStr ( elem . textContent || "" ) ;
98+ }
99+ }
100+
101+ let labelledByText = "" ;
102+ let figcaptionText = "" ;
103+ if ( figureElem ) {
104+ console . log ( "FigureElement attributes" , figureElem . attributes ) ;
105+ const ariaLabelledByAttributes = figureElem . getAttribute ( "aria-labelledby" ) ;
106+ if ( ariaLabelledByAttributes ) {
107+ const elem = xmlDom . getElementById ( ariaLabelledByAttributes ) ;
108+ if ( elem ) {
109+ labelledByText = cleanupStr ( elem . textContent || "" ) ;
110+ }
111+ }
112+ {
113+ const elem = figureElem . getElementsByTagName ( "figcaption" ) ;
114+ if ( elem ) {
115+ figcaptionText = cleanupStr ( elem [ 0 ] ?. textContent || "" ) ;
116+ }
117+ }
118+ }
119+
120+ const N_CHAR_SIZE = 200 ;
121+ const CUT = N_CHAR_SIZE + 50 ;
122+
123+ let beforeText = "" ;
124+ let afterText = "" ;
125+ // if (!detailsText && !describedbyText && (!(labelledByText && figcaptionText) || !figcaptionText)) {
126+
127+ // TODO: start iterator at imgElem and go forward / backward, instead of rootElem and search down
128+ const iter = xmlDom . createNodeIterator ( rootElem , NodeFilter . SHOW_ALL , { acceptNode : ( ) => NodeFilter . FILTER_ACCEPT } ) ;
129+
130+ const resetImgIterator = ( ) => {
131+ let curEl ;
132+ do {
133+ curEl = iter . nextNode ( ) ;
134+ } while ( curEl && imgElem !== curEl ) ;
135+ // if (curEl != imgElem) {
136+ // return;
137+ // }
138+ } ;
139+
140+ resetImgIterator ( ) ;
141+ while ( beforeText . length < N_CHAR_SIZE ) {
142+
143+ const node = iter . previousNode ( ) ;
144+ if ( ! node ) {
145+ break ;
146+ }
147+ if ( node . nodeType === Node . TEXT_NODE ) {
148+ beforeText = cleanupStr ( node . nodeValue ) + " " + beforeText ;
149+ }
150+ if ( node . nodeName === "IMG" || node . nodeName === "img" ) {
151+ break ;
152+ }
153+ }
154+ resetImgIterator ( ) ;
155+ while ( afterText . length < N_CHAR_SIZE ) {
156+ const node = iter . nextNode ( ) ;
157+ if ( ! node ) {
158+ break ;
159+ }
160+ if ( node . nodeType === Node . TEXT_NODE ) {
161+ afterText += cleanupStr ( node . nodeValue ) + " " ;
162+ }
163+ }
164+
165+ const abs = ( v : number ) => v < 0 ? 0 : - 1 * v ;
166+
167+ beforeText = beforeText . slice ( abs ( beforeText . length - CUT ) , beforeText . length ) ;
168+ afterText = afterText . slice ( 0 , CUT ) ;
169+
170+ beforeText = cleanupStr ( beforeText ) ;
171+ afterText = cleanupStr ( afterText ) ;
172+
173+ const DomParsingTexts = {
174+ dom_beforeText : beforeText ,
175+ dom_afterText : afterText ,
176+ dom_detailsText : detailsText ,
177+ dom_describedbyText : describedbyText ,
178+ dom_labelledByText : labelledByText ,
179+ dom_figcaptionText : figcaptionText ,
180+ } ;
181+ debug ( "IMG_CLICK ImgDomParsed injected to img payload:" , DomParsingTexts ) ;
182+
183+ yield * putTyped ( readerLocalActionSetImageClick . build ( { ...payload , ...DomParsingTexts } ) ) ;
184+
185+ return ;
47186}
48187
49188export function saga ( ) {
0 commit comments