@@ -54,7 +54,7 @@ function attachFerrises(type) {
5454
5555 let ferris = createFerris ( type , size )
5656 container . appendChild ( ferris ) ;
57- addPadding ( codeBlock , ferris ) ;
57+ giveFerrisSpace ( codeBlock , ferris , size ) ;
5858 }
5959}
6060
@@ -104,75 +104,70 @@ function createFerris(type, size) {
104104}
105105
106106/**
107- *
107+ * Put each line ending in a span. For each of those spans,
108+ * if Ferris might hide it, give it a safety buffer.
108109 * @param {HTMLElement } codeBlock
109110 * @param {HTMLAnchorElement } ferris
111+ * @param {'small' | 'large' } size
110112 */
111- function addPadding ( codeBlock , ferris ) {
112- // console.log("offsetHeight:", ferris.offsetHeight, "offsetWidth:", ferris.offsetWidth, "offsetLeft", ferris.offsetLeft, "offsetTop:", ferris.offsetTop, "offsetParent:", ferris.offsetParent);
113- // console.log(ferris.getBoundingClientRect());
113+ function giveFerrisSpace ( codeBlock , ferris , size ) {
114+ // sanity checking + lint awareness
115+ const ferrisImage = ferris . firstChild ;
116+ if ( ! ( ferrisImage instanceof HTMLImageElement ) ) {
117+ console . error ( "ferris should be <a> containing <img>" , ferris ) ;
118+ return ;
119+ }
114120
115- const suspects = [ ] ; // array of spans which *might* be hidden by Ferris
121+ /** @type {HTMLSpanElement[] } */
122+ const lineEndings = [ ] ; // line endings which might be hidden by Ferris
116123
117124 const walker = document . createTreeWalker ( codeBlock , NodeFilter . SHOW_TEXT ) ;
118125 const re = / ^ ( .* ?) \n ( .* ) $ / s
119126
120- let linebreaksToFix = 10 ;
121- while ( linebreaksToFix > 0 && walker . nextNode ( ) ) {
127+ while ( walker . nextNode ( ) ) {
122128 const current = walker . currentNode ;
123129 const parent = current . parentNode ;
124130
125- // sanity checking + lint fixes
126- if ( ! ( current instanceof Text ) ) {
127- console . log ( "!(current instanceof Text) shouldn't happen" ) ;
128- continue ;
129- }
130- if ( ! parent ) {
131- console . log ( "!parent shouldn't happen" ) ;
131+ // sanity checking + lint awareness
132+ if ( ! ( current instanceof Text ) || ! parent ) {
132133 continue ;
133134 }
134135
135136 let re_results ;
136- // I know nodeValue is not null because current is Text
137- current . splitText
138- while ( re_results = current . nodeValue . match ( re ) ) {
139- linebreaksToFix -- ;
140- if ( ! linebreaksToFix ) { break ; }
137+ while ( re_results = current . textContent . match ( re ) ) {
138+ // text node contains newline
139+ const [ _ , beforeNewline , afterNewline ] = re_results ;
141140
142- let [ _ , before , after ] = re_results ;
141+ // line ending gets a span
142+ const lineEnd = document . createElement ( "span" ) ;
143+ lineEnd . textContent = beforeNewline ;
144+ lineEndings . push ( lineEnd ) ;
145+ parent . insertBefore ( lineEnd , current ) ;
143146
144- let elemBefore = document . createElement ( "span" ) ;
145- elemBefore . innerText = before ;
146- suspects . push ( elemBefore ) ;
147-
148- parent . insertBefore ( elemBefore , current ) ;
147+ // newline now stands alone
149148 parent . insertBefore ( document . createTextNode ( "\n" ) , current ) ;
150- current . nodeValue = after ;
149+
150+ // rest of the text
151+ current . textContent = afterNewline ;
152+ // current might still contain newlines, so we go again until it doesn't
151153 }
152154 }
153155
154156 codeBlock . normalize ( ) ; // not strictly necessary, but good practice to leave the DOM normalized
155157
156- const actual_ferris = ferris . firstChild ;
157-
158- setTimeout ( detectOverlap , 0 , suspects , actual_ferris ) ;
159- }
160-
161- /**
162- *
163- * @param {[HTMLSpanElement] } suspects
164- * @param {HTMLAnchorElement } ferris
165- */
166- function detectOverlap ( suspects , ferris ) {
167- const f = ferris . getBoundingClientRect ( ) ;
168- suspects . forEach ( ( s ) => {
169- const { bottom, top} = s . getBoundingClientRect ( ) ;
170- if ( // vertical overlap between ferris and span
171- ( bottom >= f . top && bottom <= f . bottom )
172- || ( top >= f . top && top <= f . bottom )
173- || ( f . top >= top && f . top <= bottom )
174- ) {
175- s . classList . add ( "ferris-buffer" ) ;
176- }
158+ // setTimeout so getBoundingClientRect returns valid results
159+ setTimeout ( ( ) => {
160+ const f = ferrisImage . getBoundingClientRect ( ) ;
161+ lineEndings . forEach ( ( s ) => {
162+ const { bottom, top} = s . getBoundingClientRect ( ) ;
163+ if ( // vertical overlap between ferris and span
164+ ( bottom >= f . top && bottom <= f . bottom )
165+ || ( top >= f . top && top <= f . bottom )
166+ || ( f . top >= top && f . top <= bottom )
167+ ) {
168+ // buffer needed!
169+ s . classList . add ( "ferris-buffer-" + size ) ;
170+ }
171+ } ) ;
177172 } ) ;
178173}
0 commit comments