# blockenberg/2.0.7/blocks/world-clock/index.js

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

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

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

    /* ── Typography helpers (lazy) ───────────────────────────────── */
    var _tc, _tvf;
    Object.defineProperty(window, '__bkwc_tc',  { get: function () { return _tc  || (_tc  = window.bkbgTypographyControl); } });
    Object.defineProperty(window, '__bkwc_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
    function getTypoControl(label, typoObj, setAttributes, attrName) {
        var fn = window.__bkwc_tc;
        return fn ? fn({ label: label, value: typoObj || {}, onChange: function (v) { var o = {}; o[attrName] = v; setAttributes(o); } }) : null;
    }
    function getTypoCssVars(a) {
        var fn = window.__bkwc_tvf;
        var s = {};
        if (fn) {
            Object.assign(s, fn(a.titleTypo || {}, '--bkwc-tt-'));
            Object.assign(s, fn(a.labelTypo || {}, '--bkwc-lb-'));
            Object.assign(s, fn(a.timeTypo || {}, '--bkwc-tm-'));
        }
        return s;
    }

    /* ── Common TZ list used for autocomplete hint ───── */
    var COMMON_TZ = [
        'America/New_York','America/Chicago','America/Denver','America/Los_Angeles',
        'America/Sao_Paulo','America/Mexico_City','America/Toronto',
        'Europe/London','Europe/Paris','Europe/Berlin','Europe/Moscow','Europe/Istanbul',
        'Asia/Dubai','Asia/Kolkata','Asia/Shanghai','Asia/Tokyo','Asia/Singapore','Asia/Seoul',
        'Africa/Cairo','Africa/Johannesburg','Australia/Sydney','Pacific/Auckland'
    ];

    /* ── helpers ──────────────────────────────────────── */
    function getTimeParts(tz, fmt, showSec) {
        try {
            var now = new Date();
            var opts12  = { timeZone: tz, hour: 'numeric', minute: '2-digit', second: showSec ? '2-digit' : undefined, hour12: fmt === '12h' };
            var optsDate = { timeZone: tz, month: 'short', day: 'numeric', weekday: 'short' };
            return {
                time: new Intl.DateTimeFormat('en-US', opts12).format(now),
                date: new Intl.DateTimeFormat('en-US', optsDate).format(now)
            };
        } catch (e) {
            return { time: '--:--', date: '' };
        }
    }

    function getAnglesParts(tz) {
        try {
            var now = new Date();
            var parts = new Intl.DateTimeFormat('en-US', {
                timeZone: tz, hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false
            }).format(now).split(':').map(Number);
            var h = parts[0] % 12, m = parts[1], s = parts[2];
            return {
                hourAngle: (h * 30) + (m * 0.5),
                minAngle:  m * 6 + s * 0.1,
                secAngle:  s * 6
            };
        } catch (e) {
            return { hourAngle: 0, minAngle: 0, secAngle: 0 };
        }
    }

    /* ── Analog clock face SVG ──────────────────────── */
    function AnalogClock(props) {
        var a = props, size = a.size || 120, r = size / 2;
        var ang = getAnglesParts(a.tz);
        // tick marks
        var ticks = [];
        for (var i = 0; i < 12; i++) {
            var rad = (i * 30 - 90) * Math.PI / 180;
            var rIn = r * 0.82, rOut = r * 0.92;
            ticks.push(el('line', {
                key: i,
                x1: r + rIn * Math.cos(rad), y1: r + rIn * Math.sin(rad),
                x2: r + rOut * Math.cos(rad), y2: r + rOut * Math.sin(rad),
                stroke: a.accentColor, strokeWidth: 1.5
            }));
        }
        function hand(angle, length, color, width) {
            var rad = (angle - 90) * Math.PI / 180;
            return el('line', {
                x1: r, y1: r,
                x2: r + length * Math.cos(rad),
                y2: r + length * Math.sin(rad),
                stroke: color, strokeWidth: width, strokeLinecap: 'round'
            });
        }
        return el('svg', { width: size, height: size, viewBox: '0 0 ' + size + ' ' + size },
            el('circle', { cx: r, cy: r, r: r - 2, fill: a.clockFace, stroke: a.accentColor, strokeWidth: 2 }),
            ticks,
            hand(ang.hourAngle, r * 0.5, a.handHour, 3),
            hand(ang.minAngle,  r * 0.7, a.handMin,  2),
            a.showSeconds !== false ? hand(ang.secAngle, r * 0.75, a.handSec, 1) : null,
            el('circle', { cx: r, cy: r, r: 3, fill: a.handSec })
        );
    }

    /* ── Single clock card ──────────────────────────── */
    function ClockCard(props) {
        var a = props.attrs, zone = props.zone;
        var parts = getTimeParts(zone.tz, a.timeFormat, a.showSeconds);
        var cardStyle = {
            background: a.cardBg,
            border: '1px solid ' + a.borderColor,
            borderRadius: a.cardRadius + 'px',
            padding: a.cardPadding + 'px',
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            gap: 8
        };
        return el('div', { className: 'bkbg-wc-card', style: cardStyle },
            a.clockStyle === 'analog' ? el(AnalogClock, {
                tz: zone.tz, size: a.analogSize,
                clockFace: a.clockFace, accentColor: a.accentColor,
                handHour: a.handHour, handMin: a.handMin, handSec: a.handSec,
                showSeconds: a.showSeconds
            }) : null,
            el('div', { className: 'bkbg-wc-label', style: { color: a.labelColor, textAlign: 'center' } }, zone.label),
            a.clockStyle === 'digital' ? el('div', { className: 'bkbg-wc-time', style: { color: a.timeColor } }, parts.time) : null,
            a.showDate ? el('div', { className: 'bkbg-wc-date', style: { color: a.dateColor } }, parts.date) : null
        );
    }

    /* ── Editor preview ───────────────────────────────── */
    function WorldClockPreview(props) {
        var a = props.attrs;
        var gridStyle = {
            display: 'grid',
            gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)',
            gap: a.gap + 'px',
            maxWidth: a.maxWidth + 'px',
            margin: '0 auto'
        };
        return el('div', { className: 'bkbg-wc-preview', style: { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', background: a.sectionBg || undefined } },
            (a.showTitle || a.showSubtitle) ? el('div', { style: { textAlign: 'center', marginBottom: 32, maxWidth: a.maxWidth + 'px', margin: '0 auto 32px' } },
                a.showTitle ? el('h3', { className: 'bkbg-wc-title', style: { color: a.titleColor, margin: '0 0 8px' } }, a.title) : null,
                a.showSubtitle ? el('p', { className: 'bkbg-wc-subtitle', style: { color: a.subtitleColor, margin: 0 } }, a.subtitle) : null
            ) : null,
            el('div', { style: gridStyle },
                a.zones.map(function (zone, i) {
                    return el(ClockCard, { key: i, zone: zone, attrs: a });
                })
            )
        );
    }

    /* ── Edit component ───────────────────────────────── */
    function WorldClockEdit(props) {
        var a = props.attributes;
        var set = props.setAttributes;
        var blockProps = useBlockProps((function () {
            var s = getTypoCssVars(a);
            return { className: 'bkbg-wc-editor', style: s };
        })());

        function s(key) { return function (v) { var o = {}; o[key] = v; set(o); }; }
        function n(key) { return function (v) { var o = {}; o[key] = Number(v) || 0; set(o); }; }
        function t(key) { return function (v) { var o = {}; o[key] = v; set(o); }; }

        function updateZone(i, field, val) {
            var z = a.zones.slice();
            z[i] = Object.assign({}, z[i]);
            z[i][field] = val;
            set({ zones: z });
        }

        function addZone() {
            set({ zones: a.zones.concat([{ label: 'City', tz: 'UTC' }]) });
        }

        function removeZone(i) {
            if (a.zones.length <= 1) return;
            var z = a.zones.filter(function (_, idx) { return idx !== i; });
            set({ zones: z });
        }

        return el(Fragment, null,
            el(InspectorControls, null,

                /* Title */
                el(PanelBody, { title: __('Header', 'blockenberg'), initialOpen: true },
                    el(ToggleControl, { label: __('Show Title', 'blockenberg'), checked: a.showTitle, onChange: t('showTitle'), __nextHasNoMarginBottom: true }),
                    a.showTitle ? el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: s('title') }) : null,
                    el(ToggleControl, { label: __('Show Subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: t('showSubtitle'), __nextHasNoMarginBottom: true }),
                    a.showSubtitle ? el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: s('subtitle') }) : null
                ),

                /* Zones */
                el(PanelBody, { title: __('Timezone Zones', 'blockenberg'), initialOpen: true },
                    a.zones.map(function (zone, i) {
                        return el('div', { key: i, style: { marginBottom: 16, background: '#f9f9f9', borderRadius: 8, padding: '8px 12px' } },
                            el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 } },
                                el('strong', null, 'Zone ' + (i + 1)),
                                el(Button, { isDestructive: true, isSmall: true, onClick: function () { removeZone(i); } }, '✕')
                            ),
                            el(TextControl, { label: __('Label', 'blockenberg'), value: zone.label, onChange: function (v) { updateZone(i, 'label', v); } }),
                            el(TextControl, { label: __('IANA Timezone', 'blockenberg'), value: zone.tz, onChange: function (v) { updateZone(i, 'tz', v); }, help: 'e.g. America/New_York, Europe/London' })
                        );
                    }),
                    el(Button, { isPrimary: true, onClick: addZone, style: { marginTop: 8 } }, __('+ Add Zone', 'blockenberg'))
                ),

                /* Clock Settings */
                el(PanelBody, { title: __('Clock Settings', 'blockenberg'), initialOpen: false },
                    el(SelectControl, { label: __('Clock Style', 'blockenberg'), value: a.clockStyle, options: [{ label: 'Digital', value: 'digital' }, { label: 'Analog', value: 'analog' }], onChange: s('clockStyle') }),
                    el(SelectControl, { label: __('Time Format', 'blockenberg'), value: a.timeFormat, options: [{ label: '12-hour (AM/PM)', value: '12h' }, { label: '24-hour', value: '24h' }], onChange: s('timeFormat') }),
                    el(ToggleControl, { label: __('Show Date', 'blockenberg'), checked: a.showDate, onChange: t('showDate'), __nextHasNoMarginBottom: true }),
                    el(ToggleControl, { label: __('Show Seconds', 'blockenberg'), checked: a.showSeconds, onChange: t('showSeconds'), __nextHasNoMarginBottom: true })
                ),

                /* Colors */
                
                el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
                    getTypoControl( 'Title', a.titleTypo, set, 'titleTypo' ),
                    getTypoControl( 'Label', a.labelTypo, set, 'labelTypo' ),
                    getTypoControl( 'Time', a.timeTypo, set, 'timeTypo' )
                ),
el(PanelColorSettings, {
                    title: __('Colors', 'blockenberg'),
                    initialOpen: false,
                    colorSettings: [
                        { value: a.accentColor,   onChange: s('accentColor'),   label: __('Accent', 'blockenberg') },
                        { value: a.cardBg,         onChange: s('cardBg'),         label: __('Card Background', 'blockenberg') },
                        { value: a.borderColor,    onChange: s('borderColor'),    label: __('Card Border', 'blockenberg') },
                        { value: a.timeColor,      onChange: s('timeColor'),      label: __('Time Color', 'blockenberg') },
                        { value: a.labelColor,     onChange: s('labelColor'),     label: __('City Label', 'blockenberg') },
                        { value: a.dateColor,      onChange: s('dateColor'),      label: __('Date Color', 'blockenberg') },
                        { value: a.clockFace,      onChange: s('clockFace'),      label: __('Clock Face', 'blockenberg') },
                        { value: a.handHour,       onChange: s('handHour'),       label: __('Hour Hand', 'blockenberg') },
                        { value: a.handMin,        onChange: s('handMin'),        label: __('Minute Hand', 'blockenberg') },
                        { value: a.handSec,        onChange: s('handSec'),        label: __('Second Hand', 'blockenberg') },
                        { value: a.titleColor,     onChange: s('titleColor'),     label: __('Title Color', 'blockenberg') },
                        { value: a.subtitleColor,  onChange: s('subtitleColor'),  label: __('Subtitle Color', 'blockenberg') },
                        { value: a.sectionBg,      onChange: s('sectionBg'),      label: __('Section Background', 'blockenberg') }
                    ]
                }),

                /* Layout & Sizing */
                el(PanelBody, { title: __('Layout & Sizing', 'blockenberg'), initialOpen: false },
                    el(RangeControl, { label: __('Columns', 'blockenberg'), value: a.columns, onChange: n('columns'), min: 1, max: 6 }),
                    el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, onChange: n('gap'), min: 4, max: 48 }),
                    el(RangeControl, { label: __('Card Radius (px)', 'blockenberg'), value: a.cardRadius, onChange: n('cardRadius'), min: 0, max: 32 }),
                    el(RangeControl, { label: __('Card Padding (px)', 'blockenberg'), value: a.cardPadding, onChange: n('cardPadding'), min: 8, max: 64 }),
                    el(RangeControl, { label: __('Time Size (px)', 'blockenberg'), value: a.timeSize, onChange: n('timeSize'), min: 16, max: 64 }),
                    a.clockStyle === 'analog' ? el(RangeControl, { label: __('Analog Clock Size (px)', 'blockenberg'), value: a.analogSize, onChange: n('analogSize'), min: 60, max: 240 }) : null,
                    el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, onChange: n('maxWidth'), min: 400, max: 1400, step: 20 }),
                    el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, onChange: n('paddingTop'), min: 0, max: 160 }),
                    el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, onChange: n('paddingBottom'), min: 0, max: 160 })
                )
            ),

            el('div', blockProps,
                el(WorldClockPreview, { attrs: a })
            )
        );
    }

    registerBlockType('blockenberg/world-clock', {
        edit: WorldClockEdit,
        save: function (props) {
            var a = props.attributes;
            return el('div', wp.blockEditor.useBlockProps.save({
                className: 'bkbg-wc-app',
                style: getTypoCssVars(a),
                'data-opts': JSON.stringify(a)
            }));
        }
    });
}() );

```
