@@ -237,76 +237,49 @@ Ext.extend(GO.form.HtmlEditor, Ext.form.HtmlEditor, {
237237 this . debounceTimeout = setTimeout ( ( ) => {
238238 clearTimeout ( this . debounceTimeout ) ;
239239 this . debounceTimeout = undefined ;
240+ this . convertUrisToAnchors ( ) ;
241+ } , 500 ) ;
242+ } ,
240243
241- const index = this . getCaretCharacterOffsetWithin ( ) ;
242- var h = this . getEditorBody ( ) . innerHTML ;
243- var anchored = Autolinker . link ( h , {
244- stripPrefix : false ,
245- stripTrailingSlash : false ,
246- className : "normal-link" ,
247- newWindow : true ,
248- phone : false ,
249- urls : {
250- schemeMatches : true ,
251- wwwMatches : false ,
252- tldMatches : false
253- }
254- } ) ;
255244
256- if ( h != anchored ) {
245+ convertUrisToAnchors : function ( ) {
246+ const walk = ( node ) => {
257247
258- this . getEditorBody ( ) . innerHTML = anchored ;
259- this . setCaretPosition ( index ) ;
248+ if ( node . nodeType == Node . ELEMENT_NODE && node . tagName == "A" ) {
249+ // don't traverse into anchor tags
250+ return ;
260251 }
261252
262- console . warn ( "autolink" ) ;
263-
264- } , 500 ) ;
265- } ,
266-
267-
268- getCaretCharacterOffsetWithin : function ( ) {
269- const win = this . getWin ( ) , doc = this . getDoc ( ) , element = this . getEditorBody ( ) ;
270- let caretOffset = 0 ;
271- const sel = win . getSelection ( ) ;
272- if ( sel . rangeCount > 0 ) {
273- const range = sel . getRangeAt ( 0 ) ;
274- const preCaretRange = range . cloneRange ( ) ;
275- preCaretRange . selectNodeContents ( element ) ;
276- preCaretRange . setEnd ( range . endContainer , range . endOffset ) ;
277- caretOffset = preCaretRange . toString ( ) . length ;
278- }
279- return caretOffset ;
280- } ,
253+ //walk nodes recursively
254+ node . childNodes . forEach ( walk ) ;
281255
282- setCaretPosition : function ( offset ) {
283- const win = this . getWin ( ) , doc = this . getDoc ( ) , element = this . getEditorBody ( ) ;
284- let currentOffset = 0 ;
285- const nodeStack = [ element ] ;
286- let node , found = false ;
287-
288- while ( nodeStack . length && ! found ) {
289- node = nodeStack . pop ( ) ;
290- if ( node . nodeType === Node . TEXT_NODE ) {
291- const nextOffset = currentOffset + node . length ;
292- if ( offset <= nextOffset ) {
293- const range = win . document . createRange ( ) ;
294- range . setStart ( node , offset - currentOffset ) ;
295- range . collapse ( true ) ;
296- const sel = win . getSelection ( ) ;
297- sel . removeAllRanges ( ) ;
298- sel . addRange ( range ) ;
299- found = true ;
300- } else {
301- currentOffset = nextOffset ;
256+ if ( node . nodeType == Node . TEXT_NODE ) {
257+ if ( node == this . getDoc ( ) . getSelection ( ) . anchorNode ) {
258+ return ;
302259 }
303- } else {
304- let i = node . childNodes . length ;
305- while ( i -- ) {
306- nodeStack . push ( node . childNodes [ i ] ) ;
260+
261+ if ( node . textContent && node . textContent . indexOf ( "http" ) > - 1 ) {
262+ const anchored = this . replaceUriWithAnchor ( node . textContent ) ;
263+ if ( anchored != node . textContent ) {
264+ const tmp = document . createElement ( "span" ) ;
265+ tmp . innerHTML = anchored ;
266+ node . replaceWith ( tmp ) ;
267+ }
307268 }
308269 }
309270 }
271+
272+ walk ( this . getEditorBody ( ) ) ;
273+ } ,
274+
275+ replaceUriWithAnchor : function ( html ) {
276+ // Regular expression to match URIs that are not inside anchor tags
277+ const uriRegex = / ( h t t p s ? : \/ \/ [ ^ \s ] + | f t p : \/ \/ [ ^ \s ] + ) / ig;
278+
279+ // Replace matched URIs with anchor tags
280+ return html . replace ( uriRegex , ( url ) => {
281+ return `<a href="${ url } " target="_blank" rel="noopener noreferrer">${ url } </a>` ;
282+ } ) ;
310283 } ,
311284
312285 onDrop : function ( e ) {
0 commit comments