import escape from "escape-html" ; const ANNOTATION_IGNORE = ".no-glossary,code,pre,a,script,h1,h2,h3,h4,h5,h6" ; function pregQuote ( str ) { return `${ str }` . replace ( /([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g , "\\$1" ) ; } function replaceText ( $ , el , search , replace , text_only ) { return $ ( el ) . each ( function ( ) { let node = this . firstChild , val , new_val ; const remove = [ ] ; if ( node ) { while ( node ) { if ( node . nodeType === 3 ) { val = node . nodeValue ; new_val = val . replace ( search , replace ) ; if ( new_val !== val ) { if ( ! text_only && /</ . test ( new_val ) ) { $ ( node ) . before ( new_val ) ; remove . push ( node ) ; } else { node . nodeValue = new_val ; } } } node = node . nextSibling ; } } if ( remove . length ) $ ( remove ) . remove ( ) ; } ) ; } param { List < GlossaryEntry > } param { string } glossaryFilePath param { HTMLDom } $ function annotateText ( entries , glossaryFilePath , $ ) { entries . forEach ( ( entry ) => { const entryId = entry . getID ( ) ; const name = entry . getName ( ) ; const description = entry . getDescription ( ) ; const searchRegex = new RegExp ( `\\b(${ pregQuote ( name . toLowerCase ( ) ) })\\b` , "gi" ) ; $ ( "*" ) . each ( function ( ) { const $this = $ ( this ) ; if ( $this . is ( ANNOTATION_IGNORE ) || $this . parents ( ANNOTATION_IGNORE ) . length > 0 ) return ; replaceText ( $ , this , searchRegex , ( match ) => { return ( `<a href="/${ glossaryFilePath }#${ entryId }" ` + `class="glossary-term" title="${ escape ( description ) }">${ match }</a>` ) ; } ) ; } ) ; } ) ; } export default annotateText ;