# blockenberg/2.0.7/blocks/footnotes/index.js

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

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/footnotes/index.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/footnotes/index.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/footnotes/index.js#L10-L20`.

```javascript
( function () {
    var el = wp.element.createElement;
    var Fragment = wp.element.Fragment;
    var useState = wp.element.useState;
    var registerBlockType = wp.blocks.registerBlockType;
    var useBlockProps = wp.blockEditor.useBlockProps;
    var InspectorControls = wp.blockEditor.InspectorControls;
    var PanelColorSettings = wp.blockEditor.PanelColorSettings;
    var PanelBody = wp.components.PanelBody;
    var TextControl = wp.components.TextControl;
    var TextareaControl = wp.components.TextareaControl;
    var ToggleControl = wp.components.ToggleControl;
    var RangeControl = wp.components.RangeControl;
    var SelectControl = wp.components.SelectControl;
    var Button = wp.components.Button;
    var __ = wp.i18n.__;

    var _fnTC, _fnTV;
    function _tc() { return _fnTC || (_fnTC = window.bkbgTypographyControl); }
    function _tv() { return _fnTV || (_fnTV = window.bkbgTypoCssVars); }

    // ── helpers ────────────────────────────────────────────────────────────────
    function updateNote(notes, idx, val) {
        return notes.map(function (n, i) {
            if (i !== idx) return n;
            return Object.assign({}, n, { text: val });
        });
    }

    var MARKER_LABELS = { number: '1, 2, 3…', letter: 'a, b, c…', roman: 'i, ii, iii…', symbol: '*, †, ‡…' };
    var SYMBOLS = ['*', '†', '‡', '§', '‖', '¶', '#', '**', '††', '‡‡'];

    function getMarker(style, i) {
        if (style === 'letter') return String.fromCharCode(97 + i);
        if (style === 'roman') {
            var nums = [1,4,5,9,10,40,50,90,100,400,500,900,1000];
            var syms = ['i','iv','v','ix','x','xl','l','xc','c','cd','d','cm','m'];
            var n = i + 1, out = '';
            for (var k = nums.length - 1; k >= 0; k--) {
                while (n >= nums[k]) { out += syms[k]; n -= nums[k]; }
            }
            return out;
        }
        if (style === 'symbol') return SYMBOLS[i % SYMBOLS.length];
        return String(i + 1);
    }

    // ── FootnotesPreview ────────────────────────────────────────────────────────
    function FootnotesPreview(props) {
        var a = props.attributes;

        var markerStyle = {
            background: a.markerBg,
            color: a.markerColor,
            borderRadius: '3px',
            fontSize: '11px',
            fontWeight: '700',
            padding: '1px 5px',
            cursor: 'default',
            display: 'inline-block',
            minWidth: '20px',
            textAlign: 'center',
            flexShrink: '0'
        };

        return el('div', {
            className: 'bkbg-fn-block',
            style: { background: a.bgColor, borderRadius: a.borderRadius + 'px' }
        },
            a.dividerEnabled && el('div', { className: 'bkbg-fn-divider', style: { borderTopColor: a.dividerColor } }),
            a.showTitle && el('div', {
                className: 'bkbg-fn-title',
                style: { color: a.titleColor }
            }, a.title),
            el('ol', { className: 'bkbg-fn-list bkbg-fn-list-' + a.listStyle },
                a.notes.map(function (note, i) {
                    return el('li', {
                        key: i,
                        className: 'bkbg-fn-item',
                        style: { color: a.textColor, borderColor: a.borderColor }
                    },
                        el('span', { className: 'bkbg-fn-marker', style: markerStyle },
                            getMarker(a.markerStyle, i)
                        ),
                        el('span', { className: 'bkbg-fn-text' }, note.text)
                    );
                })
            )
        );
    }

    // ── NoteEditor ──────────────────────────────────────────────────────────────
    function NoteEditor(props) {
        var notes = props.notes;
        var setAttributes = props.setAttributes;
        var markerStyle = props.markerStyle;
        var markerColor = props.markerColor;

        var openState = useState(notes.map(function () { return false; }));
        var open = openState[0];
        var setOpen = openState[1];

        function toggle(i) {
            setOpen(open.map(function (v, j) { return j === i ? !v : v; }));
        }

        function remove(i) {
            var newNotes = notes.filter(function (_, j) { return j !== i; })
                .map(function (n, j) { return Object.assign({}, n, { id: j + 1 }); });
            setAttributes({ notes: newNotes });
            setOpen(open.filter(function (_, j) { return j !== i; }));
        }

        function add() {
            var newId = notes.length + 1;
            setAttributes({ notes: notes.concat([{ id: newId, text: 'New footnote text.' }]) });
            setOpen(open.concat([true]));
        }

        return el('div', null,
            notes.map(function (note, i) {
                return el('div', { key: i, className: 'bkbg-fn-nota-editor' },
                    el('div', {
                        className: 'bkbg-fn-nota-header',
                        onClick: function () { toggle(i); },
                        style: { borderLeftColor: markerColor }
                    },
                        el('span', null, getMarker(markerStyle, i) + ' — ' + note.text.slice(0, 40) + (note.text.length > 40 ? '…' : '')),
                        el('span', null, open[i] ? '▲' : '▼')
                    ),
                    open[i] && el('div', { className: 'bkbg-fn-nota-fields' },
                        el(TextareaControl, {
                            label: __('Footnote text'),
                            value: note.text,
                            rows: 3,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ notes: updateNote(notes, i, v) }); }
                        }),
                        el(Button, {
                            variant: 'link',
                            isDestructive: true,
                            onClick: function () { remove(i); }
                        }, __('Remove'))
                    )
                );
            }),
            el(Button, {
                variant: 'secondary',
                onClick: add,
                style: { marginTop: '8px' }
            }, __('+ Add Footnote'))
        );
    }

    // ── register ────────────────────────────────────────────────────────────────
    registerBlockType('blockenberg/footnotes', {
        edit: function (props) {
            var a = props.attributes;
            var setAttributes = props.setAttributes;

            return el(Fragment, null,
                el(InspectorControls, null,
                    el(PanelBody, { title: __('Footnotes'), initialOpen: true },
                        el(NoteEditor, {
                            notes: a.notes,
                            setAttributes: setAttributes,
                            markerStyle: a.markerStyle,
                            markerColor: a.markerColor
                        })
                    ),
                    el(PanelBody, { title: __('Settings'), initialOpen: false },
                        el(TextControl, {
                            label: __('Section title'),
                            value: a.title,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ title: v }); }
                        }),
                        el(ToggleControl, {
                            label: __('Show title'),
                            checked: a.showTitle,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ showTitle: v }); }
                        }),
                        el(ToggleControl, {
                            label: __('Show divider line'),
                            checked: a.dividerEnabled,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ dividerEnabled: v }); }
                        }),
                        el(ToggleControl, {
                            label: __('Show tooltip on hover'),
                            checked: a.showTooltip,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ showTooltip: v }); }
                        }),
                        el(SelectControl, {
                            label: __('Marker style'),
                            value: a.markerStyle,
                            __nextHasNoMarginBottom: true,
                            options: Object.keys(MARKER_LABELS).map(function (k) {
                                return { value: k, label: MARKER_LABELS[k] };
                            }),
                            onChange: function (v) { setAttributes({ markerStyle: v }); }
                        }),
                        el(SelectControl, {
                            label: __('List style'),
                            value: a.listStyle,
                            __nextHasNoMarginBottom: true,
                            options: [
                                { value: 'default', label: 'Default (clean rows)' },
                                { value: 'card', label: 'Card (bordered)' },
                                { value: 'compact', label: 'Compact' }
                            ],
                            onChange: function (v) { setAttributes({ listStyle: v }); }
                        }),
                        el(RangeControl, {
                            label: __('Border radius (px)'),
                            value: a.borderRadius,
                            min: 0, max: 24,
                            __nextHasNoMarginBottom: true,
                            onChange: function (v) { setAttributes({ borderRadius: v }); }
                        })
                    ),
                    el(PanelBody, { title: __('Typography'), initialOpen: false },
                        _tc()({ label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { setAttributes({ typoTitle: v }); } }),
                        _tc()({ label: __('Note Text', 'blockenberg'), value: a.typoNote, onChange: function (v) { setAttributes({ typoNote: v }); } })
                    ),
                    el(PanelColorSettings, {
                        title: __('Colors'),
                        initialOpen: false,
                        colorSettings: [
                            { label: __('Background'), value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '#f8fafc' }); } },
                            { label: __('Border'), value: a.borderColor, onChange: function (v) { setAttributes({ borderColor: v || '#e2e8f0' }); } },
                            { label: __('Title'), value: a.titleColor, onChange: function (v) { setAttributes({ titleColor: v || '#0f172a' }); } },
                            { label: __('Text'), value: a.textColor, onChange: function (v) { setAttributes({ textColor: v || '#475569' }); } },
                            { label: __('Marker text'), value: a.markerColor, onChange: function (v) { setAttributes({ markerColor: v || '#3b82f6' }); } },
                            { label: __('Marker background'), value: a.markerBg, onChange: function (v) { setAttributes({ markerBg: v || '#eff6ff' }); } },
                            { label: __('Divider'), value: a.dividerColor, onChange: function (v) { setAttributes({ dividerColor: v || '#e2e8f0' }); } },
                            { label: __('Tooltip background'), value: a.tooltipBg, onChange: function (v) { setAttributes({ tooltipBg: v || '#1e293b' }); } },
                            { label: __('Tooltip text'), value: a.tooltipColor, onChange: function (v) { setAttributes({ tooltipColor: v || '#f1f5f9' }); } }
                        ]
                    })
                ),
                el('div', useBlockProps({ style: Object.assign({}, _tv()(a.typoTitle, '--bkbg-fn-tt-'), _tv()(a.typoNote, '--bkbg-fn-nt-')) }),
                    el(FootnotesPreview, { attributes: a })
                )
            );
        },

        save: function (props) {
            return el('div', useBlockProps.save(),
                el('div', {
                    className: 'bkbg-fn-app',
                    'data-opts': JSON.stringify(props.attributes)
                })
            );
        }
    });
}() );

```
