@@ -210,49 +210,76 @@ const padeditor = (() => {
210210
211211exports . padeditor = padeditor ;
212212
213- exports . focusOnLine = ( ace ) => {
214- // If a number is in the URI IE #L124 go to that line number
213+ const getHashedLineNumber = ( ) => {
215214 const lineNumber = window . location . hash . substr ( 1 ) ;
216- if ( lineNumber ) {
217- if ( lineNumber [ 0 ] === 'L' ) {
218- const $outerdoc = $ ( 'iframe[name="ace_outer"]' ) . contents ( ) . find ( '#outerdocbody' ) ;
219- const lineNumberInt = parseInt ( lineNumber . substr ( 1 ) ) ;
220- if ( lineNumberInt ) {
221- const $inner = $ ( 'iframe[name="ace_outer"]' ) . contents ( ) . find ( 'iframe' )
222- . contents ( ) . find ( '#innerdocbody' ) ;
223- const line = $inner . find ( `div:nth-child(${ lineNumberInt } )` ) ;
224- if ( line . length !== 0 ) {
225- let offsetTop = line . offset ( ) . top ;
226- offsetTop += parseInt ( $outerdoc . css ( 'padding-top' ) . replace ( 'px' , '' ) ) ;
227- const hasMobileLayout = $ ( 'body' ) . hasClass ( 'mobile-layout' ) ;
228- if ( ! hasMobileLayout ) {
229- offsetTop += parseInt ( $inner . css ( 'padding-top' ) . replace ( 'px' , '' ) ) ;
230- }
231- const $outerdocHTML = $ ( 'iframe[name="ace_outer"]' ) . contents ( )
232- . find ( '#outerdocbody' ) . parent ( ) ;
233- $outerdoc . css ( { top : `${ offsetTop } px` } ) ; // Chrome
234- $outerdocHTML . animate ( { scrollTop : offsetTop } ) ; // needed for FF
235- const node = line [ 0 ] ;
236- ace . callWithAce ( ( ace ) => {
237- const selection = {
238- startPoint : {
239- index : 0 ,
240- focusAtStart : true ,
241- maxIndex : 1 ,
242- node,
243- } ,
244- endPoint : {
245- index : 0 ,
246- focusAtStart : true ,
247- maxIndex : 1 ,
248- node,
249- } ,
250- } ;
251- ace . ace_setSelection ( selection ) ;
252- } ) ;
253- }
254- }
215+ if ( ! lineNumber || lineNumber [ 0 ] !== 'L' ) return null ;
216+ const lineNumberInt = parseInt ( lineNumber . substr ( 1 ) ) ;
217+ return Number . isInteger ( lineNumberInt ) && lineNumberInt > 0 ? lineNumberInt : null ;
218+ } ;
219+
220+ const focusOnHashedLine = ( ace , lineNumberInt ) => {
221+ const $aceOuter = $ ( 'iframe[name="ace_outer"]' ) ;
222+ const $outerdoc = $aceOuter . contents ( ) . find ( '#outerdocbody' ) ;
223+ const $inner = $aceOuter . contents ( ) . find ( 'iframe' ) . contents ( ) . find ( '#innerdocbody' ) ;
224+ const line = $inner . find ( `div:nth-child(${ lineNumberInt } )` ) ;
225+ if ( line . length === 0 ) return false ;
226+
227+ let offsetTop = line . offset ( ) . top ;
228+ offsetTop += parseInt ( $outerdoc . css ( 'padding-top' ) . replace ( 'px' , '' ) ) ;
229+ const hasMobileLayout = $ ( 'body' ) . hasClass ( 'mobile-layout' ) ;
230+ if ( ! hasMobileLayout ) offsetTop += parseInt ( $inner . css ( 'padding-top' ) . replace ( 'px' , '' ) ) ;
231+ const $outerdocHTML = $aceOuter . contents ( ) . find ( '#outerdocbody' ) . parent ( ) ;
232+ $outerdoc . css ( { top : `${ offsetTop } px` } ) ; // Chrome
233+ $outerdocHTML . scrollTop ( offsetTop ) ;
234+ const node = line [ 0 ] ;
235+ ace . callWithAce ( ( ace ) => {
236+ const selection = {
237+ startPoint : {
238+ index : 0 ,
239+ focusAtStart : true ,
240+ maxIndex : 1 ,
241+ node,
242+ } ,
243+ endPoint : {
244+ index : 0 ,
245+ focusAtStart : true ,
246+ maxIndex : 1 ,
247+ node,
248+ } ,
249+ } ;
250+ ace . ace_setSelection ( selection ) ;
251+ } ) ;
252+ return true ;
253+ } ;
254+
255+ exports . focusOnLine = ( ace ) => {
256+ const lineNumberInt = getHashedLineNumber ( ) ;
257+ if ( lineNumberInt == null ) return ;
258+ const getCurrentTargetOffset = ( ) => {
259+ const $aceOuter = $ ( 'iframe[name="ace_outer"]' ) ;
260+ const $inner = $aceOuter . contents ( ) . find ( 'iframe' ) . contents ( ) . find ( '#innerdocbody' ) ;
261+ const line = $inner . find ( `div:nth-child(${ lineNumberInt } )` ) ;
262+ if ( line . length === 0 ) return null ;
263+ return line . offset ( ) . top ;
264+ } ;
265+
266+ const maxSettleDuration = 10000 ;
267+ const settleInterval = 250 ;
268+ const startTime = Date . now ( ) ;
269+ let intervalId = null ;
270+
271+ const focusUntilStable = ( ) => {
272+ if ( Date . now ( ) - startTime >= maxSettleDuration ) {
273+ window . clearInterval ( intervalId ) ;
274+ return ;
255275 }
256- }
276+ const currentOffsetTop = getCurrentTargetOffset ( ) ;
277+ if ( currentOffsetTop == null ) return ;
278+
279+ focusOnHashedLine ( ace , lineNumberInt ) ;
280+ } ;
281+
282+ focusUntilStable ( ) ;
283+ intervalId = window . setInterval ( focusUntilStable , settleInterval ) ;
257284 // End of setSelection / set Y position of editor
258285} ;
0 commit comments