1/** 2 * ì ì ì íëì ë°ë¥¸ ìí ë°ì´í° ìì§ 3 * 4 * 1. í´ë¦ ì´ë²¤í¸ attachOnClickEvent 5 * 2. ë ¸ì¶ ì´ë²¤í¸ trackImpression 6 */ 7class ProductTracker { 8 constructor($list_wrap = null) { 9 // $list_wrapì´ ì ë¬ëì§ ììê±°ë ì í¨íì§ ìì ê²½ì° document ì¬ì© 10 this.$list_wrap = $list_wrap || $(document); 11 12 // jQuery ê°ì²´ê° ìë ê²½ì° jQueryë¡ ë³í 13 if (this.$list_wrap && typeof this.$list_wrap.jquery === 'undefined') { 14 this.$list_wrap = $(this.$list_wrap); 15 } 16 17 this.impressedProducts = []; 18 this.debounceTimer = null; // Debounce íì´ë¨¸ ID 19 this.DEBOUNCE_DELAY = 1000; // Debounce ì§ì° ìê° (ë°ë¦¬ì´) 20 this.debouncedTrackImpression = null; // Debounced í¨ì를 ì ì¥í ìì± 21 } 22 23 init() { 24 if (typeof BrandScope === 'undefined') { 25 throw new Error('BrandScope is undefined'); 26 } 27 28 this.debouncedTrackImpression = () => { 29 clearTimeout(this.debounceTimer); 30 this.debounceTimer = setTimeout(() => { 31 this.trackImpression(); 32 }, this.DEBOUNCE_DELAY); 33 } 34 35 this.attachOnClickEvent(); 36 this.observeImpression(); 37 } 38 39 attachOnClickEvent() { 40 this.$list_wrap.find('._shop_item').one('mouseup', function(e) { 41 // ë§ì°ì¤ ì¼ìª½ ëë í í´ë¦ì´ ìëë©´ ì´ë²¤í¸ ì¢ ë£ 42 if (e.which !== 1 && e.which !== 2) { 43 return; 44 } 45 46 const productData = $(this).data('product-properties'); 47 48 if (productData === undefined) { 49 throw new Error('productData is undefined'); 50 } 51 52 BrandScope.track({ 53 eventType: 'Select', 54 props: { 55 ownership: 'behavior-tracking-analytics', 56 selectedType: 'PRODUCT', 57 selectedNo: productData.idx, 58 selectedCode: productData.code, 59 selectedName: productData.name, 60 selectedImageUrl: productData.image_url, 61 productPrice: productData.price, 62 productOriginPrice: productData.original_price, 63 } 64 }); 65 }); 66 } 67 68 trackImpression() { 69 const productsToTrack = [...this.impressedProducts]; 70 71 if (productsToTrack.length === 0) { 72 return; 73 } 74 75 this.impressedProducts = []; 76 77 const data = productsToTrack.map(product => ({ 78 productNo: product.idx, 79 productCode: product.code, 80 productName: product.name, 81 productImageUrl: product.image_url, 82 productPrice: product.price, 83 productOriginPrice: product.original_price, 84 })) 85 86 BrandScope.track({ 87 eventType: 'ProductImpression', 88 props: { 89 ownership: 'behavior-tracking-analytics', 90 impressedTarget: 'product_item', 91 impressionType: 'PRODUCT', 92 products: data 93 } 94 }); 95 } 96 97 /** 98 * ë ¸ì¶ ì¶ì ê´ì°°ì ì¤ì 99 * DELAY ì´ì ë ¸ì¶ ë ìíì ëí´ìë§ ë ¸ì¶ ì¶ì ì´ë²¤í¸ ë°ì 100 */ 101 observeImpression() { 102 const DELAY = 500; 103 const intersectionTimer = new Map(); // ê° ìíì íì´ë¨¸ë¥¼ ì ì¥í Map 104 105 const observer = new IntersectionObserver((entries, observer) => { 106 entries.forEach(entry => { 107 try { 108 const productData = JSON.parse(entry.target.dataset.productProperties); 109 110 const idx = productData.idx; 111 112 if (idx === undefined) { 113 return; 114 } 115 116 if (entry.isIntersecting) { 117 if (intersectionTimer.has(idx)) { 118 return; 119 } 120 121 intersectionTimer.set(idx, setTimeout(() => { 122 this.impressedProducts.push(productData); 123 124 if (this.impressedProducts.length > 0) { 125 this.debouncedTrackImpression(); 126 } 127 128 observer.unobserve(entry.target); 129 }, DELAY)); 130 131 } else { 132 if (!intersectionTimer.has(idx)) { 133 return; 134 } 135 136 clearTimeout(intersectionTimer.get(idx)); 137 intersectionTimer.delete(idx); 138 } 139 } catch (_) { 140 // ì¤ë¥ ë°ì ì 무ì 141 } 142 }); 143 }, { 144 threshold: 0.8 145 }); 146 147 const shopItems = this.$list_wrap.find('._shop_item'); 148 149 shopItems.each(function(){ 150 observer.observe($(this)[0]); 151 }); 152 } 153}
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.