1/** 2 * Tickera 2026 â Inline ROI calculator 3 * Vanilla JS, no library, no build step. 4 * Updates output text on slider drag. 5 */ 6(function () { 7 'use strict'; 8 9 function init() { 10 var root = document.getElementById('tickera-roi-calc'); 11 if (!root) return; 12 13 var EB_PCT_TOTAL = parseFloat(root.dataset.ebPct || '0.066'); // 3.7% + 2.9% = 6.6% 14 var EB_FIXED = parseFloat(root.dataset.ebFixed || '1.79'); // $1.79 per ticket 15 var LICENSE = parseFloat(root.dataset.license || '399'); // Tickera Lifetime $399 16 17 var ticketsEl = root.querySelector('#calc-tickets'); 18 var priceEl = root.querySelector('#calc-price'); 19 var yearsEl = root.querySelector('#calc-years'); 20 21 var ticketsOut = root.querySelector('[for="calc-tickets"][data-fmt]'); 22 var priceOut = root.querySelector('[for="calc-price"][data-fmt]'); 23 var yearsOut = root.querySelector('[for="calc-years"][data-fmt]'); 24 25 var ebOut = root.querySelector('[data-output="eventbrite-total"]'); 26 var tkOut = root.querySelector('[data-output="tickera-total"]'); 27 var saveOut = root.querySelector('[data-output="savings"]'); 28 var saveCtx = root.querySelector('[data-output="savings-context"]'); 29 var saveBox = root.querySelector('.calc-savings'); 30 var saveLabel = root.querySelector('.calc-savings-label'); 31 32 function fmtNum(n) { 33 return Math.round(n).toLocaleString('en-US'); 34 } 35 function fmtUsd(n, opts) { 36 opts = opts || {}; 37 var sign = opts.sign || ''; 38 var amt = Math.abs(Math.round(n)); 39 return sign + '$' + amt.toLocaleString('en-US'); 40 } 41 42 function update() { 43 var tickets = parseInt(ticketsEl.value, 10); 44 var price = parseInt(priceEl.value, 10); 45 var years = parseInt(yearsEl.value, 10); 46 47 // Live label updates 48 ticketsOut.textContent = fmtNum(tickets); 49 priceOut.textContent = fmtUsd(price); 50 yearsOut.textContent = years + (years === 1 ? ' year' : ' years'); 51 52 // Eventbrite cost per ticket: percentage of price + fixed service fee 53 var ebPerTicket = (price * EB_PCT_TOTAL) + EB_FIXED; 54 var ebTotal = ebPerTicket * tickets * years; 55 56 // Tickera Lifetime cost: license, once. (We're not charging yearly.) 57 var tkTotal = LICENSE; 58 59 var savings = ebTotal - tkTotal; 60 var yearsWord = years + (years === 1 ? ' year' : ' years'); 61 62 ebOut.textContent = fmtUsd(ebTotal, { sign: 'â' }); 63 tkOut.textContent = fmtUsd(tkTotal); 64 65 if (savings < 0) { 66 // Tickera license costs more than Eventbrite would at this scale â 67 // stay honest: flip sign, label, and tone so the user sees a loss as a loss. 68 saveOut.textContent = fmtUsd(savings, { sign: 'â' }); 69 if (saveLabel) saveLabel.textContent = 'Tickera costs more'; 70 saveCtx.textContent = 'over ' + yearsWord + ' â Eventbrite is cheaper at this scale'; 71 if (saveBox) saveBox.classList.add('calc-savings--loss'); 72 } else { 73 saveOut.textContent = fmtUsd(savings); 74 if (saveLabel) saveLabel.textContent = 'You keep'; 75 saveCtx.textContent = 'over ' + yearsWord + ', vs Eventbrite'; 76 if (saveBox) saveBox.classList.remove('calc-savings--loss'); 77 } 78 79 // Fill the range visually (track gradient based on value) 80 [ticketsEl, priceEl, yearsEl].forEach(function (el) { 81 var min = parseFloat(el.min); 82 var max = parseFloat(el.max); 83 var val = parseFloat(el.value); 84 var pct = ((val - min) / (max - min)) * 100; 85 el.style.setProperty('--calc-fill', pct + '%'); 86 }); 87 } 88 89 [ticketsEl, priceEl, yearsEl].forEach(function (el) { 90 el.addEventListener('input', update, { passive: true }); 91 }); 92 93 update(); 94 } 95 96 if (document.readyState === 'loading') { 97 document.addEventListener('DOMContentLoaded', init); 98 } else { 99 init(); 100 } 101})();
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.