# blockenberg/2.0.7/blocks/expense-tracker/frontend.js

Blockenberg — 600+ Advanced Gutenberg Blocks &amp; AI Agent for WordPress Block Editor, version 2.0.7. 388 lines.

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/expense-tracker/frontend.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/expense-tracker/frontend.js
- Modified: 2026-03-06T12:32:40+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/expense-tracker/frontend.js#L10-L20`.

```javascript
(function () {
    'use strict';

    function typoCssVarsForEl(typo, prefix, el) {
        if (!typo || typeof typo !== 'object') return;
        var map = {
            family: 'font-family', weight: 'font-weight', transform: 'text-transform',
            style: 'font-style', decoration: 'text-decoration',
            sizeDesktop: 'font-size-d', sizeTablet: 'font-size-t', sizeMobile: 'font-size-m', sizeUnit: 'font-size-unit',
            lineHeightDesktop: 'line-height-d', lineHeightTablet: 'line-height-t', lineHeightMobile: 'line-height-m', lineHeightUnit: 'line-height-unit',
            letterSpacingDesktop: 'letter-spacing-d', letterSpacingTablet: 'letter-spacing-t', letterSpacingMobile: 'letter-spacing-m', letterSpacingUnit: 'letter-spacing-unit',
            wordSpacingDesktop: 'word-spacing-d', wordSpacingTablet: 'word-spacing-t', wordSpacingMobile: 'word-spacing-m', wordSpacingUnit: 'word-spacing-unit'
        };
        Object.keys(map).forEach(function (k) {
            if (typo[k] !== undefined && typo[k] !== '') {
                var v = typo[k];
                if (typeof v === 'number') {
                    var css = map[k];
                    var unit = '';
                    if (css.indexOf('font-size') === 0 && css !== 'font-size-unit') unit = typo.sizeUnit || 'px';
                    else if (css.indexOf('line-height') === 0 && css !== 'line-height-unit') unit = typo.lineHeightUnit || '';
                    else if (css.indexOf('letter-spacing') === 0 && css !== 'letter-spacing-unit') unit = typo.letterSpacingUnit || 'px';
                    else if (css.indexOf('word-spacing') === 0 && css !== 'word-spacing-unit') unit = typo.wordSpacingUnit || 'px';
                    v = v + unit;
                }
                el.style.setProperty(prefix + map[k], v);
            }
        });
    }

    var CAT_COLORS = {
        Housing:       '#6366f1',
        Food:          '#f59e0b',
        Transport:     '#10b981',
        Entertainment: '#ec4899',
        Health:        '#ef4444',
        Shopping:      '#3b82f6',
        Utilities:     '#14b8a6',
        Other:         '#8b5cf6'
    };
    var CATEGORIES = ['Housing','Food','Transport','Entertainment','Health','Shopping','Utilities','Other'];

    var STORAGE_KEY = 'bkbg_expense_tracker';

    function loadData(uid) {
        try {
            var raw = localStorage.getItem(STORAGE_KEY + '_' + uid);
            return raw ? JSON.parse(raw) : { expenses: [], budget: 1000 };
        } catch (e) { return { expenses: [], budget: 1000 }; }
    }

    function saveData(uid, data) {
        try { localStorage.setItem(STORAGE_KEY + '_' + uid, JSON.stringify(data)); } catch (e) {}
    }

    function formatDate(d) {
        var dt = new Date(d);
        return dt.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
    }

    function initBlock(root) {
        var opts;
        try { opts = JSON.parse(root.getAttribute('data-opts')); } catch (e) { return; }
        var a = opts;
        var uid = root.getAttribute('data-uid') || ('expt' + Math.random().toString(36).slice(2));
        root.setAttribute('data-uid', uid);

        var stored = loadData(uid);
        var expenses = stored.expenses || [];
        var budget = stored.budget || a.defaultBudget;
        var filterCat = 'all';
        var nextId = (expenses.length ? Math.max.apply(null, expenses.map(function (e) { return e.id; })) + 1 : 1);

        root.innerHTML = '';

        var wrap = document.createElement('div');
        wrap.className = 'bkbg-expt-wrap';
        wrap.style.cssText = 'background:' + a.sectionBg + ';max-width:' + a.contentMaxWidth + 'px;margin:0 auto;';
        root.appendChild(wrap);

        typoCssVarsForEl(a.typoTitle, '--bkbg-expt-ttl-', wrap);
        typoCssVarsForEl(a.typoSubtitle, '--bkbg-expt-sub-', wrap);

        if (a.showTitle) {
            var h = document.createElement('div');
            h.className = 'bkbg-expt-title';
            h.style.cssText = 'color:' + a.titleColor + ';';
            h.textContent = a.title;
            wrap.appendChild(h);
        }
        if (a.showSubtitle) {
            var sub = document.createElement('div');
            sub.className = 'bkbg-expt-subtitle';
            sub.style.color = a.subtitleColor;
            sub.textContent = a.subtitle;
            wrap.appendChild(sub);
        }

        /* Summary */
        var summaryEl = document.createElement('div');
        summaryEl.className = 'bkbg-expt-summary';
        wrap.appendChild(summaryEl);

        /* Form */
        var form = document.createElement('div');
        form.className = 'bkbg-expt-form';
        form.style.cssText = 'background:' + a.cardBg + ';border-color:' + a.borderColor + ';';
        wrap.appendChild(form);

        function makeFormGroup(labelText) {
            var g = document.createElement('div');
            g.className = 'bkbg-expt-form-group';
            var lbl = document.createElement('label');
            lbl.className = 'bkbg-expt-label';
            lbl.style.color = a.labelColor;
            lbl.textContent = labelText;
            g.appendChild(lbl);
            return g;
        }

        var gName = makeFormGroup('Description');
        var iName = document.createElement('input');
        iName.className = 'bkbg-expt-input';
        iName.placeholder = 'e.g. Coffee';
        gName.appendChild(iName);
        form.appendChild(gName);

        var gAmt = makeFormGroup('Amount');
        var iAmt = document.createElement('input');
        iAmt.className = 'bkbg-expt-input';
        iAmt.type = 'number';
        iAmt.placeholder = '0.00';
        iAmt.min = '0';
        iAmt.step = '0.01';
        gAmt.appendChild(iAmt);
        form.appendChild(gAmt);

        var gCat = makeFormGroup('Category');
        var iCat = document.createElement('select');
        iCat.className = 'bkbg-expt-select';
        CATEGORIES.forEach(function (c) {
            var o = document.createElement('option');
            o.value = c;
            o.textContent = c;
            iCat.appendChild(o);
        });
        gCat.appendChild(iCat);
        form.appendChild(gCat);

        var gDate = makeFormGroup('Date');
        var iDate = document.createElement('input');
        iDate.className = 'bkbg-expt-input';
        iDate.type = 'date';
        iDate.value = new Date().toISOString().slice(0, 10);
        gDate.appendChild(iDate);
        form.appendChild(gDate);

        var addBtn = document.createElement('button');
        addBtn.className = 'bkbg-expt-add-btn';
        addBtn.style.background = a.accentColor;
        addBtn.textContent = '+ Add';
        form.appendChild(addBtn);

        /* Chart */
        var chartEl = null;
        if (a.showChart) {
            chartEl = document.createElement('div');
            chartEl.className = 'bkbg-expt-chart';
            chartEl.style.cssText = 'background:' + a.cardBg + ';border-color:' + a.borderColor + ';';
            wrap.appendChild(chartEl);
        }

        /* List */
        var listEl = document.createElement('div');
        listEl.className = 'bkbg-expt-list';
        listEl.style.cssText = 'background:' + a.cardBg + ';border-color:' + a.borderColor + ';';
        wrap.appendChild(listEl);

        var listHeader = document.createElement('div');
        listHeader.className = 'bkbg-expt-list-header';
        listHeader.style.cssText = 'color:' + a.labelColor + ';border-color:' + a.borderColor + ';';
        listHeader.appendChild(document.createTextNode('Expenses'));
        var filterSel = document.createElement('select');
        filterSel.className = 'bkbg-expt-filter';
        var allOpt = document.createElement('option');
        allOpt.value = 'all';
        allOpt.textContent = 'All Categories';
        filterSel.appendChild(allOpt);
        CATEGORIES.forEach(function (c) {
            var o = document.createElement('option');
            o.value = c;
            o.textContent = c;
            filterSel.appendChild(o);
        });
        listHeader.appendChild(filterSel);
        listEl.appendChild(listHeader);

        var listBody = document.createElement('div');
        listEl.appendChild(listBody);

        function persist() { saveData(uid, { expenses: expenses, budget: budget }); }

        function render() {
            var total = expenses.reduce(function (s, e) { return s + e.amount; }, 0);

            /* Summary */
            summaryEl.innerHTML = '';
            function makeCard(val, lbl, color) {
                var c = document.createElement('div');
                c.className = 'bkbg-expt-card';
                c.style.cssText = 'background:' + a.cardBg + ';border-color:' + a.borderColor + ';';
                var v = document.createElement('div');
                v.className = 'bkbg-expt-card-val';
                v.style.color = color;
                v.textContent = a.currency + val;
                var l = document.createElement('div');
                l.className = 'bkbg-expt-card-lbl';
                l.style.color = a.subtitleColor;
                l.textContent = lbl;
                c.appendChild(v);
                c.appendChild(l);
                return c;
            }

            summaryEl.appendChild(makeCard(total.toFixed(2), 'Total Spent', a.accentColor));

            if (a.showBudget) {
                var rem = budget - total;
                var remColor = rem < 0 ? a.dangerColor : a.labelColor;
                var budCard = makeCard(Math.abs(rem).toFixed(2), rem < 0 ? 'Over Budget' : 'Remaining', remColor);
                var barWrap = document.createElement('div');
                barWrap.className = 'bkbg-expt-budget-bar-wrap';
                var barFill = document.createElement('div');
                barFill.className = 'bkbg-expt-budget-bar';
                var pct = Math.min((total / budget) * 100, 100);
                barFill.style.cssText = 'width:' + pct + '%;background:' + (rem < 0 ? a.dangerColor : a.accentColor) + ';';
                barWrap.appendChild(barFill);
                budCard.appendChild(barWrap);
                summaryEl.appendChild(budCard);
            }

            summaryEl.appendChild(makeCard(expenses.length.toString(), 'Transactions', a.labelColor));

            /* Chart */
            if (chartEl) {
                chartEl.innerHTML = '';
                var ct = document.createElement('div');
                ct.className = 'bkbg-expt-chart-title';
                ct.style.color = a.labelColor;
                ct.textContent = 'Spending by Category';
                chartEl.appendChild(ct);

                var catTotals = {};
                expenses.forEach(function (e) {
                    catTotals[e.category] = (catTotals[e.category] || 0) + e.amount;
                });
                var maxCat = Math.max.apply(null, Object.values(catTotals).concat([0]));

                Object.keys(catTotals).sort(function (x, y) { return catTotals[y] - catTotals[x]; }).forEach(function (cat) {
                    var pct = maxCat > 0 ? Math.round((catTotals[cat] / maxCat) * 100) : 0;
                    var row = document.createElement('div');
                    row.className = 'bkbg-expt-bar-row';
                    var lbls = document.createElement('div');
                    lbls.className = 'bkbg-expt-bar-labels';
                    var catLbl = document.createElement('span');
                    catLbl.style.color = a.labelColor;
                    catLbl.textContent = cat;
                    var amtLbl = document.createElement('span');
                    amtLbl.style.color = a.subtitleColor;
                    amtLbl.textContent = a.currency + catTotals[cat].toFixed(2);
                    lbls.appendChild(catLbl);
                    lbls.appendChild(amtLbl);
                    var track = document.createElement('div');
                    track.className = 'bkbg-expt-bar-track';
                    var fill = document.createElement('div');
                    fill.className = 'bkbg-expt-bar-fill';
                    fill.style.cssText = 'width:' + pct + '%;background:' + (CAT_COLORS[cat] || a.accentColor) + ';';
                    track.appendChild(fill);
                    row.appendChild(lbls);
                    row.appendChild(track);
                    chartEl.appendChild(row);
                });

                if (!Object.keys(catTotals).length) {
                    var empty = document.createElement('div');
                    empty.style.cssText = 'text-align:center;padding:16px;font-size:13px;color:' + a.subtitleColor + ';';
                    empty.textContent = 'No expenses yet';
                    chartEl.appendChild(empty);
                }
            }

            /* List */
            listBody.innerHTML = '';
            var filtered = filterCat === 'all' ? expenses : expenses.filter(function (e) { return e.category === filterCat; });
            var sorted = filtered.slice().sort(function (x, y) { return new Date(y.date) - new Date(x.date); });

            if (!sorted.length) {
                var empt = document.createElement('div');
                empt.className = 'bkbg-expt-empty';
                empt.style.color = a.subtitleColor;
                empt.textContent = filterCat === 'all' ? 'No expenses yet. Add your first one above!' : 'No expenses in this category.';
                listBody.appendChild(empt);
                return;
            }

            sorted.forEach(function (exp) {
                var item = document.createElement('div');
                item.className = 'bkbg-expt-item';
                item.style.borderColor = a.borderColor;
                var left = document.createElement('div');
                left.className = 'bkbg-expt-item-left';
                var dot = document.createElement('div');
                dot.className = 'bkbg-expt-dot';
                dot.style.background = CAT_COLORS[exp.category] || a.accentColor;
                var info = document.createElement('div');
                var name = document.createElement('div');
                name.className = 'bkbg-expt-item-name';
                name.style.color = a.labelColor;
                name.textContent = exp.name;
                var meta = document.createElement('div');
                meta.className = 'bkbg-expt-item-meta';
                meta.style.color = a.subtitleColor;
                meta.textContent = exp.category + ' · ' + formatDate(exp.date);
                info.appendChild(name);
                info.appendChild(meta);
                left.appendChild(dot);
                left.appendChild(info);
                var right = document.createElement('div');
                right.className = 'bkbg-expt-item-right';
                var amt = document.createElement('div');
                amt.className = 'bkbg-expt-item-amount';
                amt.style.color = a.labelColor;
                amt.textContent = a.currency + exp.amount.toFixed(2);
                var del = document.createElement('button');
                del.className = 'bkbg-expt-del-btn';
                del.textContent = '×';
                del.setAttribute('aria-label', 'Delete');
                del.addEventListener('click', function () {
                    expenses = expenses.filter(function (e) { return e.id !== exp.id; });
                    persist();
                    render();
                });
                right.appendChild(amt);
                right.appendChild(del);
                item.appendChild(left);
                item.appendChild(right);
                listBody.appendChild(item);
            });
        }

        addBtn.addEventListener('click', function () {
            var name = iName.value.trim();
            var amt = parseFloat(iAmt.value);
            if (!name || isNaN(amt) || amt <= 0) { return; }
            expenses.push({ id: nextId++, name: name, amount: amt, category: iCat.value, date: iDate.value || new Date().toISOString().slice(0, 10) });
            persist();
            render();
            iName.value = '';
            iAmt.value = '';
            iName.focus();
        });

        iName.addEventListener('keydown', function (e) {
            if (e.key === 'Enter') { iAmt.focus(); }
        });
        iAmt.addEventListener('keydown', function (e) {
            if (e.key === 'Enter') { addBtn.click(); }
        });

        filterSel.addEventListener('change', function () {
            filterCat = filterSel.value;
            render();
        });

        render();
    }

    function init() {
        document.querySelectorAll('.bkbg-expt-app').forEach(initBlock);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

```
