1/** 2 * Article Read Tracking for GTM 3 * è¨äºæ¬æã®80%ã表示ãããã¿ã¤ãã³ã°ã§article_readã¤ãã³ããéä¿¡ 4 * 5 * @package madameFIGARO.jp 6 */ 7 8(function() { 9 'use strict'; 10 11 /** 12 * è¨äºèªäºãã©ããã³ã°ã¯ã©ã¹ 13 */ 14 class ArticleReadTracking { 15 constructor() { 16 // éä¿¡æ¸ã¿è¨äºIDãè¨é²ï¼éè¤é²æ¢ï¼ 17 this.trackedArticles = new Set(); 18 19 // IntersectionObserverãåæå 20 this.initObserver(); 21 22 // ç¡éã¹ã¯ãã¼ã«ã§æ°ããè¨äºã追å ãããéã®å¯¾å¿ 23 document.addEventListener('contentAdded', (event) => { 24 // å°ãé å»¶ããã¦ããæ°ããè¨äºãç£è¦ 25 setTimeout(() => this.observeAllArticles(), 100); 26 }); 27 } 28 29 /** 30 * IntersectionObserverãåæå 31 */ 32 initObserver() { 33 this.observer = new IntersectionObserver( 34 (entries) => this.handleIntersection(entries), 35 { 36 threshold: 0, // ãã¼ã«ã¼è¦ç´ ã1pxã§ã表示ããããçºç« 37 rootMargin: '0px' 38 } 39 ); 40 41 // å ¨è¨äºãç£è¦å¯¾è±¡ã«è¿½å 42 this.observeAllArticles(); 43 } 44 45 /** 46 * å ¨è¨äºã®æ¬æã¨ãªã¢ãç£è¦å¯¾è±¡ã«è¿½å 47 */ 48 observeAllArticles() { 49 // .b-article.editor-styles-wrapper è¦ç´ ãåå¾ 50 const articleContents = document.querySelectorAll('.b-article.editor-styles-wrapper'); 51 52 articleContents.forEach(contentElement => { 53 // 親ã®articleè¦ç´ ãåå¾ 54 const articleElement = contentElement.closest('article.p-detail'); 55 if (!articleElement) { 56 console.warn('Article Read Tracking: article.p-detail element not found'); 57 return; 58 } 59 60 // è¨äºIDãåå¾ 61 const postId = articleElement.dataset.postId; 62 if (!postId) { 63 console.warn('Article Read Tracking: data-post-id not found'); 64 return; 65 } 66 67 // æ¢ã«éä¿¡æ¸ã¿ã®å ´åã¯ã¹ããã 68 if (this.trackedArticles.has(postId)) { 69 return; 70 } 71 72 // æ¬æã¨ãªã¢ã®80%å°ç¹ã«ãã¼ã«ã¼è¦ç´ ãæ¿å ¥ 73 const marker = this.createMarker(postId, contentElement); 74 if (marker) { 75 this.observer.observe(marker); 76 } 77 }); 78 } 79 80 /** 81 * æ¬æã¨ãªã¢ã®80%å°ç¹ã«ãã¼ã«ã¼è¦ç´ ãä½æã»æ¿å ¥ 82 * 83 * @param {string} postId è¨äºID 84 * @param {HTMLElement} contentElement æ¬æã¨ãªã¢è¦ç´ 85 * @returns {HTMLElement|null} ãã¼ã«ã¼è¦ç´ 86 */ 87 createMarker(postId, contentElement) { 88 // æ¢ã«ãã¼ã«ã¼ãåå¨ããå ´åã¯ã¹ããã 89 const existingMarker = contentElement.querySelector('.article-read-marker'); 90 if (existingMarker) { 91 return existingMarker; 92 } 93 94 // æ¬æã¨ãªã¢ã®é«ããåå¾ 95 const contentHeight = contentElement.scrollHeight; 96 if (contentHeight === 0) { 97 console.warn('Article Read Tracking: content height is 0'); 98 return null; 99 } 100 101 // 80%ã®ä½ç½®ãè¨ç® 102 const eightyPercentPosition = contentHeight * 0.8; 103 104 // ãããã°æ å ±ãåºå 105 console.log(`Article Read Tracking [Post ID: ${postId}]:`, { 106 contentHeight: contentHeight + 'px', 107 eightyPercentPosition: eightyPercentPosition + 'px', 108 percentage: '80%' 109 }); 110 111 // ãã¼ã«ã¼è¦ç´ ã使ï¼ç®ã«è¦ããªã1pxã®è¦ç´ ï¼ 112 const marker = document.createElement('div'); 113 marker.className = 'article-read-marker'; 114 marker.dataset.postId = postId; 115 marker.style.cssText = 'position: absolute; height: 1px; width: 100%; opacity: 0; pointer-events: none;'; 116 marker.style.top = eightyPercentPosition + 'px'; 117 118 // æ¬æã¨ãªã¢ã«position:relativeã追å ï¼ãã¼ã«ã¼ã®çµ¶å¯¾ä½ç½®æå®ã®ããï¼ 119 const computedStyle = window.getComputedStyle(contentElement); 120 if (computedStyle.position === 'static') { 121 contentElement.style.position = 'relative'; 122 } 123 124 // ãã¼ã«ã¼ãæ¿å ¥ 125 contentElement.appendChild(marker); 126 127 return marker; 128 } 129 130 /** 131 * Intersection Observerã®ã³ã¼ã«ãã㯠132 * 133 * @param {IntersectionObserverEntry[]} entries 134 */ 135 handleIntersection(entries) { 136 entries.forEach(entry => { 137 // 表示ãããå ´åã®ã¿å¦ç 138 if (!entry.isIntersecting) return; 139 140 const marker = entry.target; 141 const postId = marker.dataset.postId; 142 143 // æ¢ã«éä¿¡æ¸ã¿ã®å ´åã¯ã¹ããã 144 if (this.trackedArticles.has(postId)) { 145 this.observer.unobserve(marker); 146 return; 147 } 148 149 // éä¿¡æ¸ã¿ã¨ãã¦ãã¼ã¯ 150 this.trackedArticles.add(postId); 151 152 // dataLayerãåå¨ããªãå ´åã¯åæå 153 window.dataLayer = window.dataLayer || []; 154 155 // è¨äºèªäºã¤ãã³ããéä¿¡ 156 // GTM_SETUP_GUIDE.md 4.4 ã«æºæ 157 this.sendArticleReadEvent(postId); 158 159 // ç£è¦è§£é¤ï¼ä¸åº¦ã ãçºç«ãããï¼ 160 this.observer.unobserve(marker); 161 }); 162 } 163 164 /** 165 * è¨äºèªäºã¤ãã³ããdataLayerã«éä¿¡ 166 * 167 * @param {string} postId è¨äºID 168 */ 169 sendArticleReadEvent(postId) { 170 // dataLayerããç¾å¨ã®è¨äºæ å ±ãåå¾ 171 const currentData = this.getCurrentArticleData(); 172 173 // ã¤ãã³ããã¼ã¿ãæ§ç¯ 174 const eventData = { 175 event: 'article_read', 176 article_id: currentData.article_id || postId, 177 article_category: currentData.article_category || '', 178 article_author: currentData.article_author || '', 179 article_read_count: 1, 180 page_location: window.location.href, 181 page_path: window.location.pathname, 182 page_title: document.title 183 }; 184 185 // dataLayerã«push 186 window.dataLayer.push(eventData); 187 188 console.log('article_read event pushed for post ID:', postId, eventData); 189 } 190 191 /** 192 * dataLayerããç¾å¨ã®è¨äºæ å ±ãåå¾ 193 * 194 * @returns {Object} è¨äºæ å ± 195 */ 196 getCurrentArticleData() { 197 const data = { 198 article_id: '', 199 article_category: '', 200 article_author: '' 201 }; 202 203 // dataLayerããææ°ã®è¨äºæ å ±ãåå¾ 204 if (window.dataLayer && Array.isArray(window.dataLayer)) { 205 // dataLayerãéé ã§èµ°æ»ï¼ææ°ã®å¤ãåªå ï¼ 206 for (let i = window.dataLayer.length - 1; i >= 0; i--) { 207 const layer = window.dataLayer[i]; 208 if (layer.article_id && !data.article_id) { 209 data.article_id = layer.article_id; 210 } 211 if (layer.article_category && !data.article_category) { 212 data.article_category = layer.article_category; 213 } 214 if (layer.article_author && !data.article_author) { 215 data.article_author = layer.article_author; 216 } 217 218 // å ¨ã¦ã®æ å ±ãæã£ããçµäº 219 if (data.article_id && data.article_category && data.article_author) { 220 break; 221 } 222 } 223 } 224 225 return data; 226 } 227 } 228
229 /** 230 * åæå颿° 231 */ 232 function init() { 233 // è¨äºãã¼ã¸ã®ã¿å®è¡ 234 if (document.body.classList.contains('single-post') || 235 document.body.classList.contains('single-cityguide') || 236 document.body.classList.contains('single-yukari-weekly') || 237 document.body.classList.contains('single-yukari-yearly') || 238 document.body.classList.contains('single-yukari-sora') || 239 document.body.classList.contains('single-celebrity-weekly') || 240 document.body.classList.contains('single-celebrity-yearly') || 241 document.body.classList.contains('single-celebrity-zodiac') || 242 document.body.classList.contains('single-gallery') || 243 document.body.classList.contains('single')) { 244 245 // .b-article.editor-styles-wrapper è¦ç´ ãåå¨ãããç¢ºèª 246 const articleContent = document.querySelector('.b-article.editor-styles-wrapper'); 247 if (articleContent) { 248 new ArticleReadTracking(); 249 console.log('Article Read Tracking initialized'); 250 } else { 251 console.log('Article Read Tracking: .b-article.editor-styles-wrapper not found'); 252 } 253 } 254 } 255 256 // DOMèªã¿è¾¼ã¿å®äºå¾ã«åæå 257 if (document.readyState === 'loading') { 258 document.addEventListener('DOMContentLoaded', init); 259 } else { 260 init(); 261 } 262})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.