PageSourceSearch

https://microorganisms.com/js/marketplace-artist-listener.js?v=1790698586

js microorganisms.com collected 2026-09-29 16:16:32 UTC 9,530 bytes, 184 lines download raw bytes

1/**
2 * Artist tool live preview via postMessage
3 * Listens for style updates from the admin artist tool iframe parent.
4 */
5(function() {
6    function fmtNum(n) { return Math.round(n).toLocaleString(); }
7
8    function rebuildPriceCard(listingType, ltoData) {
9        var card = document.querySelector('[data-card="price"]');
10        var content = document.getElementById('priceCardContent');
11        if (!card || !content) return;
12
13        var buyNowPrice = card.dataset.buyNowPrice;
14        var estimatedHigh = card.dataset.estimatedHigh;
15        var isSeller = card.dataset.isSeller === '1';
16        var certId = card.dataset.certId;
17        var showAppraisal = card.dataset.showAppraisal !== '0';
18
19        card.dataset.listingType = listingType;
20
21        var appraisalHtml;
22        if (!showAppraisal) {
23            appraisalHtml = '';
24        } else if (certId) {
25            appraisalHtml = '<a href="#" class="cert-link" data-cert-id="' + certId + '">Appraised at $' + estimatedHigh + ' <i class="fas fa-certificate" style="font-size:0.65em;opacity:0.6"></i></a>';
26        } else {
27            appraisalHtml = 'Appraised at $' + estimatedHigh;
28        }
29
30        var html = '';
31        var hasBuyNow = buyNowPrice && (listingType === 'buy_now' || listingType === 'buy_now_or_offer');
32
33        if (hasBuyNow) {
34            html += '<div class="factor-label price-label">Price</div>';
35            html += '<div class="price-tag price-amount">$' + buyNowPrice + '</div>';
36            if (appraisalHtml) html += '<div class="text-xs text-light price-appraisal">' + appraisalHtml + '</div>';
37            if (!isSeller) {
38                html += '<button class="btn btn-primary btn-mb" id="buyNowBtn"><i class="fas fa-shopping-cart"></i> Buy Now</button>';
39                // LTO add-on: shown alongside Buy Now when the listing offers lease-to-own.
40                if (ltoData && ltoData.monthly_payment > 0) {
41                    html += '<div class="lto-addon-option" style="margin-top:14px;padding-top:14px;border-top:1px solid rgba(255,255,255,0.08);">';
42                    html += '<div class="text-sm" style="margin-bottom:6px;">or <strong>lease to own</strong> from <strong>$' + fmtNum(ltoData.monthly_payment) + '/mo</strong> &times; ' + ltoData.num_months + ' months' + (ltoData.down_payment > 0 ? ' &middot; $' + fmtNum(ltoData.down_payment) + ' down' : '') + '</div>';
43                    html += '<button class="btn btn-outline btn-mb" id="ltoStartBtn"><i class="fas fa-file-signature"></i> Lease to Own</button>';
44                    html += '</div>';
45                }
46            }
47        } else if (listingType === 'lease_to_own' && ltoData && ltoData.monthly_payment > 0) {
48            html += '<div class="factor-label price-label">Lease to Own</div>';
49            html += '<div class="price-tag price-amount">$' + fmtNum(ltoData.monthly_payment) + '<span class="lto-per-month">/mo</span></div>';
50            html += '<div class="text-xs text-light price-appraisal">' + ltoData.num_months + ' months &middot; $' + fmtNum(ltoData.total_price) + ' total</div>';
51            if (ltoData.down_payment > 0) {
52                html += '<div class="text-xs text-light lto-down-payment">$' + fmtNum(ltoData.down_payment) + ' due today</div>';
53            }
54            if (appraisalHtml) html += '<div class="text-xs text-muted price-appraisal">' + appraisalHtml + '</div>';
55            if (!isSeller) {
56                html += '<button class="btn btn-primary btn-mb" id="ltoStartBtn"><i class="fas fa-file-signature"></i> Start Lease</button>';
57            }
58        } else if (listingType === 'make_offer') {
59            html += '<div class="factor-label price-label">Make an Offer</div>';
60            if (appraisalHtml) html += '<div class="text-sm text-muted price-appraisal">' + appraisalHtml + '</div>';
61        } else {
62            html += '<div class="factor-label price-label">Price on Inquiry</div>';
63            if (appraisalHtml) html += '<div class="text-sm text-muted price-appraisal">' + appraisalHtml + '</div>';
64        }
65
66        if (!isSeller && (listingType === 'make_offer' || listingType === 'buy_now_or_offer')) {
67            html += '<button class="btn btn-outline btn-mb" id="makeOfferBtn"><i class="fas fa-hand-holding-usd"></i> Make Offer</button>';
68        }
69
70        if (!isSeller && listingType === 'inquiry') {
71            html += '<button class="btn btn-primary btn-mb" id="inquireBtn"><i class="fas fa-envelope"></i> Inquire About Price</button>';
72        }
73
74        content.innerHTML = html;
75
76        var stripeNote = card.querySelector('.price-stripe-note');
77        if (stripeNote) stripeNote.hidden = (listingType === 'inquiry');
78
79        var mobileCta = document.querySelector('.mobile-cta');
80        if (mobileCta && !isSeller) {
81            var ctaText = mobileCta.querySelector('.mobile-cta-text');
82            var ctaBtn = mobileCta.querySelector('.btn-cta');
83            var isLto = listingType === 'lease_to_own' && ltoData && ltoData.monthly_payment > 0;
84            if (ctaText) {
85                if (hasBuyNow) {
86                    ctaText.innerHTML = '<div class="mobile-cta-price">$' + buyNowPrice + '</div>';
87                } else if (isLto) {
88                    ctaText.innerHTML = '<div class="mobile-cta-price">$' + fmtNum(ltoData.monthly_payment) + '/mo</div>';
89                } else if (listingType === 'inquiry') {
90                    ctaText.innerHTML = '<div class="mobile-cta-label">Inquire About Price</div>';
91                } else {
92                    ctaText.innerHTML = '<div class="mobile-cta-label">Make an Offer</div>';
93                }
94            }
95            if (ctaBtn) {
96                if (hasBuyNow) {
97                    ctaBtn.textContent = 'Buy Now';
98                } else if (isLto) {
99                    ctaBtn.textContent = 'Start Lease';
100                } else if (listingType === 'make_offer' || listingType === 'buy_now_or_offer') {
101                    ctaBtn.textContent = 'Make Offer';
102                } else {
103                    ctaBtn.textContent = 'Inquire';
104                }
105            }
106        }
107    }
108
109    window.addEventListener('message', function(e) {
110        if (!e.data) return;
111
112        if (e.data.type === 'artist-listing-type') {
113            rebuildPriceCard(e.data.listingType, e.data.lto || null);
114            return;
115        }
116
117        if (e.data.type !== 'artist-style') return;
118        var root = document.documentElement;
119        var d = e.data;
120
121        /* Apply theme variables */
122        if (d.vars) {
123            Object.keys(d.vars).forEach(function(k) {
124                root.style.setProperty('--' + k, d.vars[k]);
125            });
126        }
127
128        /* Apply border styles to cards */
129        if (d.border) {
130            var cards = document.querySelectorAll('.card, .card-flush');
131            cards.forEach(function(card) {
132                if (d.border.style === 'none') {
133                    card.style.border = 'none';
134                } else {
135                    card.style.border = d.border.width + ' ' + d.border.style + ' ' + (d.border.color || 'var(--border)');
136                }
137                if (d.border.radius) card.style.borderRadius = d.border.radius;
138                if (d.border.shadow !== undefined) card.style.boxShadow = d.border.shadow;
139            });
140        }
141
142        /* Apply background image as the deepest page layer.
143           The page bg color sits on top with opacity controlled by the slider,
144           letting the image show through. */
145        var bgLayer = document.getElementById('artist-bg-layer');
146        if (!bgLayer) {
147            bgLayer = document.createElement('div');
148            bgLayer.id = 'artist-bg-layer';
149            bgLayer.style.cssText = 'position:fixed;inset:0;z-index:-2;background-size:cover;background-position:center;pointer-events:none;';
150            document.body.prepend(bgLayer);
151        }
152        var bgOverlay = document.getElementById('artist-bg-overlay');
153        if (!bgOverlay) {
154            bgOverlay = document.createElement('div');
155            bgOverlay.id = 'artist-bg-overlay';
156            bgOverlay.style.cssText = 'position:fixed;inset:0;z-index:-1;pointer-events:none;';
157            document.body.insertBefore(bgOverlay, bgLayer.nextSibling);
158        }
159
160        if (d.bgImage) {
161            var opacity = d.bgOpacity !== undefined ? d.bgOpacity : 0.15;
162            bgLayer.style.backgroundImage = 'url(' + d.bgImage + ')';
163            var bgColor = getComputedStyle(root).getPropertyValue('--bg').trim() || '#ffffff';
164            bgOverlay.style.backgroundColor = bgColor;
165            bgOverlay.style.opacity = 1 - opacity;
166            document.body.style.setProperty('background-color', 'transparent', 'important');
167        } else {
168            bgLayer.style.backgroundImage = '';
169            bgOverlay.style.backgroundColor = '';
170            bgOverlay.style.opacity = '';
171            // Override the page-injected `body { background: transparent !important }` rule
172            // (emitted by listing.php when the listing was loaded with a bgImage). Without
173            // !important here the body stays transparent and the browser default shows
174            // through, which often reads as dark/black in light theme. Pull from --bg so
175            // it matches the current theme.
176            document.body.style.setProperty('background-color', 'var(--bg)', 'important');
177        }
178
179        /* Force theme mode */
180        if (d.theme) {
181            root.setAttribute('data-theme', d.theme);
182        }
183    });
184})();

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.