@@ -28,6 +28,7 @@ export interface MarkdownRenderProps {
2828 codeTheme ?: string ;
2929 onConvertFinish ?: ( html : string ) => any ;
3030 editing ?: boolean ;
31+ shouldShowAds ?: boolean ;
3132}
3233
3334function sanitizeEventScript ( htmlString : string ) {
@@ -208,6 +209,7 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
208209 codeTheme = 'atom-one' ,
209210 onConvertFinish,
210211 editing,
212+ shouldShowAds = false ,
211213} ) => {
212214 const [ html , setHtml ] = useState (
213215 ssrEnabled
@@ -232,6 +234,7 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
232234 const [ element , setElement ] = useState < RenderedElement > ( null ) ;
233235 const [ hasTagError , setHasTagError ] = useState ( false ) ;
234236 const [ delay , setDelay ] = useState ( 25 ) ;
237+ const [ htmlWithAds , setHtmlWithAds ] = useState ( '' ) ;
235238
236239 const throttledUpdate = React . useMemo ( ( ) => {
237240 return throttle ( delay , ( markdown : string ) => {
@@ -288,6 +291,115 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
288291 throttledUpdate ( markdown ) ;
289292 } , [ markdown , throttledUpdate ] ) ;
290293
294+ useEffect ( ( ) => {
295+ if ( ! shouldShowAds || ! html ) {
296+ setHtmlWithAds ( '' ) ;
297+ return ;
298+ }
299+
300+ const parser = new DOMParser ( ) ;
301+ const doc = parser . parseFromString ( html , 'text/html' ) ;
302+ const blockElements = doc . querySelectorAll (
303+ 'p, h1, h2, h3, h4, h5, h6, blockquote, pre, ul, ol, hr, table' ,
304+ ) ;
305+
306+ const blockCount = blockElements . length ;
307+
308+ // Find the position to insert first ad (10~25 범위)
309+ let firstAdPosition = 9 ; // 10th block (0-based index)
310+
311+ // Look for first h1, h2, h3 from 10th to 25th block
312+ for ( let i = 10 ; i <= 25 && i < blockElements . length ; i ++ ) {
313+ const block = blockElements [ i ] ;
314+ if (
315+ block . tagName === 'H1' ||
316+ block . tagName === 'H2' ||
317+ block . tagName === 'H3'
318+ ) {
319+ firstAdPosition = i ;
320+ break ;
321+ }
322+ }
323+
324+ // Find the position to insert second ad (only if blockCount >= 40)
325+ let secondAdPosition = - 1 ;
326+ if ( blockCount >= 40 ) {
327+ // 블록이 40 이상인 경우: 35번째부터 50번째(또는 끝)까지 h1, h2, h3 찾기
328+ secondAdPosition = 34 ; // 35th block (0-based index)
329+
330+ const searchEnd = Math . min ( 50 , blockElements . length ) ;
331+ // Look for first h1, h2, h3 from 35th to searchEnd
332+ for ( let i = 35 ; i < searchEnd ; i ++ ) {
333+ const block = blockElements [ i ] ;
334+ if (
335+ block . tagName === 'H1' ||
336+ block . tagName === 'H2' ||
337+ block . tagName === 'H3'
338+ ) {
339+ secondAdPosition = i ;
340+ break ;
341+ }
342+ }
343+ }
344+
345+ // Insert ads
346+ const firstAdBlock = blockElements [ firstAdPosition ] ;
347+ const secondAdBlock =
348+ secondAdPosition >= 0 ? blockElements [ secondAdPosition ] : null ;
349+
350+ if ( firstAdBlock ) {
351+ // Insert first ad
352+ // const adDiv1 = doc.createElement('ins');
353+ // adDiv1.className = 'adsbygoogle';
354+ // adDiv1.style.display = 'block';
355+ // adDiv1.style.textAlign = 'center';
356+ // adDiv1.setAttribute('data-ad-layout', 'in-article');
357+ // adDiv1.setAttribute('data-ad-format', 'fluid');
358+ // adDiv1.setAttribute('data-ad-client', 'ca-pub-5574866530496701');
359+ // adDiv1.setAttribute('data-ad-slot', '9632367492');
360+ const adDiv1 = doc . createElement ( 'div' ) ;
361+ adDiv1 . setAttribute ( 'data-fuse' , 'incontent_1_articlepage' ) ;
362+ firstAdBlock . parentNode ?. insertBefore ( adDiv1 , firstAdBlock ) ;
363+
364+ // Insert second ad if applicable
365+ if ( secondAdBlock ) {
366+ // const adDiv2 = doc.createElement('ins');
367+ // adDiv2.className = 'adsbygoogle';
368+ // adDiv2.style.display = 'block';
369+ // adDiv2.style.textAlign = 'center';
370+ // adDiv2.setAttribute('data-ad-layout', 'in-article');
371+ // adDiv2.setAttribute('data-ad-format', 'fluid');
372+ // adDiv2.setAttribute('data-ad-client', 'ca-pub-5574866530496701');
373+ // adDiv2.setAttribute('data-ad-slot', '9632367492');
374+ const adDiv2 = doc . createElement ( 'div' ) ;
375+ adDiv2 . setAttribute ( 'data-fuse' , 'incontent_2_articlepage' ) ;
376+ secondAdBlock . parentNode ?. insertBefore ( adDiv2 , secondAdBlock ) ;
377+ }
378+
379+ // Set the modified HTML
380+ const updatedHtml = doc . body . innerHTML ;
381+ setHtmlWithAds ( updatedHtml ) ;
382+
383+ // Push ads after 1 second
384+ setTimeout ( ( ) => {
385+ // (window.adsbygoogle = window.adsbygoogle || []).push({});
386+ // if (secondAdBlock) {
387+ // (window.adsbygoogle = window.adsbygoogle || []).push({});
388+ // }
389+
390+ const fusetag = window . fusetag || ( window . fusetag = { que : [ ] } ) ;
391+
392+ fusetag . que . push ( function ( ) {
393+ const init = ( fusetag as any ) . pageInit ;
394+ if ( ! init ) return ;
395+ init ( { } ) ;
396+ } ) ;
397+ } , 1000 ) ;
398+ } else {
399+ setHtmlWithAds ( '' ) ;
400+ }
401+ } , [ html , shouldShowAds ] ) ;
402+
291403 return (
292404 < Typography >
293405 < Helmet >
@@ -312,7 +424,7 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
312424 ) : (
313425 < MarkdownRenderBlock
314426 className = { codeTheme }
315- dangerouslySetInnerHTML = { { __html : html } }
427+ dangerouslySetInnerHTML = { { __html : htmlWithAds || html } }
316428 />
317429 ) }
318430 </ Typography >
0 commit comments