# Referință pentru Constructorul de widgeturi

> Referința de cod pentru Constructorul de widgeturi KickBot: evenimentele Kick și datele lor, globalValues, userVariables, funcțiile pentru chat și previzualizarea.

Source: https://kickbot.com/ro/docs/widgets/widget-builder-reference

Pagina aceasta arată ce poate folosi codul tău într-un widget din [Constructorul de widgeturi](https://kickbot.com/ro/docs/widgets/widget-builder) KickBot: evenimentele `widgetEvent`, obiectul `globalValues`, obiectul `userVariables` și funcțiile ajutătoare din `window.kickbotWidget`. Fiecare widget este HTML, CSS și JavaScript simplu, care rulează ca sursă browser în OBS. KickBot se conectează la Kick în locul tău și trimite evenimentele în codul tău.

## Cum rulează un widget

Când OBS deschide URL-ul widgetului, KickBot:

1. Încarcă pagina widgetului cu fundal transparent.
2. Adaugă CSS-ul tău într-un element `<style>` și pune HTML-ul tău în pagină.
3. Încarcă datele canalului tău de pe Kick (numărul de urmăritori, numărul de spectatori, starea streamului și mesajele recente din chat) în `globalValues`.
4. Rulează JavaScript-ul tău. Rulează o singură dată, după pasul 3, așa că `globalValues` este gata când pornește codul tău.
5. Trimite evenimentele live în codul tău ca evenimente `widgetEvent` pe `document`.

JavaScript-ul tău poate citi două obiecte fără să importe nimic: `globalValues` și `userVariables`. Funcțiile ajutătoare sunt în `window.kickbotWidget`.

Limite:

| Element | Limită |
| --- | --- |
| Lățime și înălțime | Se setează în **Setări de bază**. Un widget gol nou are 800 × 600. Fereastra Widget nou acceptă cel mult 7680 × 4320. |
| HTML, CSS și JavaScript | Cel mult 2.000.000 de caractere pe fișier |
| Numele widgetului | Cel mult 500 de caractere |
| Fișiere pentru variabilele pentru utilizator | Cel mult 25 MB pe fișier |
| Widgeturi în constructor pe planul gratuit | 10 (fără limită pe Premium) |

## Ascultă evenimentele

Adaugă un singur listener pentru `widgetEvent` pe `document`. Fiecare eveniment are `event.detail`, cu trei câmpuri:

| Câmp | Tip | Valoare |
| --- | --- | --- |
| `event_name` | string | Evenimentul, de exemplu `followEvent` |
| `source` | string | Mereu `kick` |
| `data` | object | Datele evenimentului (vezi mai jos) |

```javascript
document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;

    if (event_name === 'followEvent') {
        showAlert(data.user.username + ' followed!');
    }
    if (event_name === 'subEvent') {
        showAlert(data.username + ' subscribed for ' + data.months + ' months');
    }
});
```

### Lista de evenimente

| Numele evenimentului | Când se declanșează | Buton de test |
| --- | --- | --- |
| `subEvent` | Un spectator se abonează | Sub |
| `subGiftEvent` | Un spectator oferă sub-uri cadou | Sub cadou |
| `kicksEvent` | Un spectator trimite KICKs | KICKs |
| `followEvent` | Un spectator îți dă follow | Follow |
| `unfollowEvent` | Un spectator îți dă unfollow | Unfollow |
| `chatMessageEvent` | Cineva trimite un mesaj în chat | Mesaj |
| `chatMessageDeletedEvent` | Un moderator șterge un mesaj | Mesaj șters |
| `chatMessagePinnedEvent` | Un mesaj este fixat | Mesaj fixat |
| `chatMessageUnpinnedEvent` | Mesajul fixat este scos | Fixare mesaj anulată |
| `chatClearedEvent` | Un moderator golește chatul | Chat golit |
| `followerCountUpdatedEvent` | Kick trimite un număr nou de urmăritori | Număr de urmăritori actualizat |
| `subCountUpdatedEvent` | Numărul de sub-uri de pe Kick s-a schimbat | Număr de sub-uri actualizat |
| `viewerCountUpdatedEvent` | Kick trimite un număr nou de spectatori | Număr de spectatori actualizat |
| `raidEvent` | Alt canal îți dă raid (host) | Raid |
| `streamOnline` | Streamul tău începe | Stream pornit |
| `streamOffline` | Streamul tău se termină | Stream oprit |

Nu există un eveniment pentru donații. Pentru alertele de donații, folosește [widgetul de alerte de donații](https://kickbot.com/ro/docs/tipping/tip-alerts).

### Datele evenimentelor

Acestea sunt datele din `event.detail.data`. Se potrivesc cu evenimentele de test din editor. Evenimentele reale pot avea mai multe câmpuri. Numele, numerele și ID-urile de aici sunt exemple.

`subEvent`

```javascript
{
    months: 1,
    username: 'viewer_one',
    chatroom_id: 3847194
}
```

`subGiftEvent`

```javascript
{
    chatroom_id: 3847194,
    gifted_usernames: ['viewer_one', 'viewer_two', 'viewer_three'],
    gifter_username: 'big_gifter'
}
```

`kicksEvent`

```javascript
{
    message: 'Great stream!',
    sender: { id: 12345678, username: 'viewer_one', username_color: '#93EBE0' },
    gift: {
        gift_id: 'full_send',
        name: 'Full Send',
        amount: 100,
        type: 'BASIC',
        tier: 'BASIC',
        character_limit: 0,
        pinned_time: 0
    },
    channel: 'channel_3984507'
}
```

`followEvent` și `unfollowEvent` (aceeași formă; `followers_count` este numărul nou)

```javascript
{
    id: 'd4e5f6a7-89b0-12c3-d456-78901e2f3a4b',
    channel: { id: 3984507, slug: 'kickbotdev' },
    user: { id: 14873539, slug: 'viewer_one', username: 'viewer_one' },
    followers_count: 36,
    created_at: '2024-05-13T22:19:07+00:00'
}
```

`chatMessageEvent`

```javascript
{
    id: '85c884b3-7377-478c-b6aa-22b7db752b93',
    chatroom_id: 3974112,
    content: 'hello [emote:37226:KEKW]',
    type: 'message',
    created_at: '2024-05-13T22:29:52+00:00',
    sender: {
        id: 4063326,
        username: 'viewer_one',
        slug: 'viewer_one',
        identity: {
            color: '#72ACED',
            badges: [{ type: 'subscriber', text: 'Subscriber', count: 3 }]
        }
    }
}
```

Emote-urile Kick apar în `content` ca `[emote:ID:NAME]`. Folosește `createChatMessageFragment` (vezi [Afișează în siguranță textul din chat](#show-chat-text-safely)) ca să le transformi în imagini.

`chatMessageDeletedEvent`

```javascript
{
    id: '9cd3788a-ecd2-4051-a162-a7ea9be8ce7a',
    message: { id: '89d6be86-63db-4581-922e-14a6c4a9c2e6' }
}
```

Folosește `data.message.id` ca să găsești și să scoți mesajul pe care l-ai afișat.

`chatMessagePinnedEvent` (`data.message` are aceeași formă ca datele unui `chatMessageEvent`)

```javascript
{
    message: {
        id: '5d798a38-ad17-45e4-8169-bda2faa85b79',
        chatroom_id: 3974112,
        content: 'This is a pinned message!',
        type: 'message',
        created_at: '2024-05-13T22:30:41+00:00',
        sender: { id: 4063326, username: 'kickbotdev', slug: 'kickbotdev', identity: { color: '#72ACED', badges: [] } }
    }
}
```

`chatMessageUnpinnedEvent`: `data` este un array gol (`[]`).

`chatClearedEvent`

```javascript
{ id: '47e3596f-0274-46e0-85b1-029fa3bfc5ea' }
```

`followerCountUpdatedEvent` (atenție, aici e camelCase: `followersCount`)

```javascript
{ followersCount: 1532, channel_id: 4599, created_at: 1715639984 }
```

`subCountUpdatedEvent`

```javascript
{ subscriber_count: 184, channel_id: 4599 }
```

`viewerCountUpdatedEvent`

```javascript
{ viewer_count: 320, channel_id: 5937485 }
```

`raidEvent`

```javascript
{
    chatroom_id: 839485,
    optional_message: 'gg stream',
    number_viewers: 150,
    host_username: 'raiding_channel'
}
```

`streamOnline`

```javascript
{
    livestream: {
        id: 3984507,
        channel_id: 3984507,
        session_title: 'Test stream!',
        created_at: '2024-05-13T22:30:41+00:00'
    }
}
```

`streamOffline`

```javascript
{
    livestream: {
        id: 3984507,
        channel: { id: 3984507, is_banned: false }
    }
}
```

## Valori globale

`globalValues` ține starea curentă a canalului tău. KickBot îl completează înainte să ruleze codul tău și îl ține la zi pe măsură ce vin evenimentele. Folosește-l ca să desenezi widgetul de la început, înainte să vină vreun eveniment.

```javascript
globalValues = {
    subCount: 184,
    followerCount: 1532,
    viewerCount: 320,
    lastFollower: { /* the last follow */ },
    lastSub: { /* the last sub, for example { username, months } */ },
    lastGiftedSub: { /* the last gift, for example { gifter_username, gifted_usernames } */ },
    chatMessages: [ /* chatMessageEvent payloads */ ],
    streamerInfo: {
        kick: {
            username: 'KickBotDev',
            slug: 'kickbotdev',
            profile_picture: 'https://files.kick.com/images/user/.../fullsize.webp',
            user_id: '4063326',
            channel_id: '3984507',
            chatroom_id: '3974112',
            bio: 'Channel bio',
            subscriber_badges: [ /* your channel's sub badges from Kick */ ]
        }
    },
    currentStream: {
        is_live: true,
        title: 'Stream title',
        started_at: '2026-10-24 18:00:00'
    }
}
```

| Valoare | Cum se actualizează |
| --- | --- |
| `subCount` | Se încarcă de pe Kick. Crește cu 1 la fiecare `subEvent` și cu 1 la fiecare sub cadou și se setează din nou la `subCountUpdatedEvent`. |
| `followerCount` | Se încarcă de pe Kick. Se setează la `followEvent`, `unfollowEvent` și `followerCountUpdatedEvent`. |
| `viewerCount` | Se încarcă de pe Kick (0 când ești offline). Se setează la `viewerCountUpdatedEvent`. |
| `lastFollower`, `lastSub`, `lastGiftedSub` | Ultimul pe care l-a văzut KickBot pe canalul tău sau `null`. Se actualizează la evenimentul potrivit. |
| `chatMessages` | Mesajele recente de pe Kick când se încarcă widgetul, apoi fiecare mesaj nou. Păstrează cele mai noi 100. `chatClearedEvent` îl golește. Ca să ascunzi mesajele șterse, tratează `chatMessageDeletedEvent` în propriul cod. |
| `streamerInfo.kick` | Profilul tău de Kick. Nu se schimbă cât rulează widgetul. |
| `currentStream` | Se încarcă de pe Kick când se încarcă widgetul. Nu se actualizează la `streamOnline` sau `streamOffline`. Ascultă acele evenimente dacă ai nevoie de starea live. |

## Variabile pentru utilizator

Variabilele pentru utilizator sunt setările pe care le văd streamerii când îți deschid widgetul în Widgeturi salvate. Le adaugi la **Variabile pentru utilizator** în editor. În cod, citești valoarea cu `userVariables.<variable name>.value`.

```javascript
const goal = Number(userVariables.follower_goal.value);
document.body.style.color = userVariables.text_color.value;
```

Câmpurile unei variabile:

| Câmp | Ce este |
| --- | --- |
| Titlu | Eticheta pe care o văd streamerii. |
| Numele variabilei | Numele din codul tău. Doar litere, cifre și `_`. Nu-l mai poți schimba după ce creezi variabila. |
| Tooltip | Un text de ajutor în plus, sub titlu. |
| Tipul variabilei | Vezi tabelul de mai jos. |
| Valoare implicită | Valoarea de dinainte ca streamerul să o schimbe. Poate fi goală. |
| Obligatoriu | Streamerii trebuie să completeze o valoare înainte să poată salva. |

| Tip | Ce vede streamerul | `value` în codul tău |
| --- | --- | --- |
| Text | O casetă de text | Un string |
| Număr | O casetă pentru număr | Un număr sau un string numeric. Folosește `Number()` ca să fii sigur. |
| Culoare | Un selector de culoare | Un string cu o culoare hex, de exemplu `#ffffff` |
| Listă derulantă | Un meniu cu opțiunile tale | Opțiunea aleasă, ca string. Implicit este prima opțiune. |
| Comutator | Un comutator pornit/oprit | `true` sau `false` |
| Imagine/GIF | O casetă pentru URL și un buton de încărcare | Un URL către fișier |
| Video | O casetă pentru URL și un buton de încărcare | Un URL către fișier |
| Audio | O casetă pentru URL și un buton de încărcare | Un URL către fișier |

Fișierele încărcate sunt stocate de KickBot, iar `value` este URL-ul fișierului. Cu meniul de lângă o variabilă o muți mai sus sau mai jos, o editezi sau o ștergi. Ordinea din editor este ordinea pe care o văd streamerii.

## Afișează în siguranță textul din chat

Tratează fiecare câmp de eveniment și fiecare variabilă pentru utilizator ca pe un text venit de la un străin. KickBot curăță textul din chat și din evenimente înainte să ajungă în codul tău, așa că e sigur ca text HTML, dar nu ca URL, CSS sau script. Nu pune câmpurile brute ale evenimentelor în `innerHTML`. Folosește aceste funcții ajutătoare:

| Funcție ajutătoare | Ce face |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | Întoarce un `DocumentFragment` cu noduri de text și imagini pentru emote-urile Kick. Emote-urile au `font_size + 3` pixeli. Implicit, `font_size` este 20. |
| `window.kickbotWidget.createTextNode(value)` | Întoarce un nod de text pentru orice valoare. |
| `window.kickbotWidget.escapeHtmlText(value)` | Face escape la text ca să-l folosești între taguri HTML, când trebuie neapărat să construiești un string HTML. Nu-l folosi pentru URL-uri, CSS sau script. |

```javascript
document.addEventListener('widgetEvent', (event) => {
    if (event.detail.event_name !== 'chatMessageEvent') return;
    const data = event.detail.data;

    const line = document.createElement('div');
    line.id = 'msg-' + data.id;
    const name = document.createElement('strong');
    name.style.color = data.sender.identity.color;
    name.append(window.kickbotWidget.createTextNode(data.sender.username + ': '));
    line.append(name);
    line.append(window.kickbotWidget.createChatMessageFragment(data.content, 20));
    document.getElementById('chat').append(line);
});
```

Pentru alt text, folosește `textContent` sau `createTextNode`.

## Previzualizarea

Previzualizarea din editor funcționează ca OBS, cu câteva diferențe pentru testare:

- Când schimbi codul sau o variabilă pentru utilizator, previzualizarea rulează din nou JavaScript-ul tău. Înainte, KickBot scoate listenerii `widgetEvent` de la rularea anterioară. Timerele din `setInterval` și `setTimeout` nu sunt scoase, așa că apasă pe butonul de reîncărcare dacă se adună.
- Când schimbi lățimea sau înălțimea, previzualizarea se reîncarcă.
- Evenimentele de test ajung doar în previzualizare. Un **Follow** de test adaugă 1 la `globalValues.followerCount`, iar **Unfollow** scade 1. **Număr de spectatori actualizat** trimite un număr de exemplu. **Mesaj șters** scoate un mesaj la întâmplare din chatul din previzualizare.
- Dacă pe canalul tău nu există încă un ultim urmăritor, sub sau sub cadou, previzualizarea folosește date de exemplu pentru `lastFollower`, `lastSub` și `lastGiftedSub`.
- Ca să vezi rezultatul din `console.log` și erorile, apasă pe butonul de pop-out și deschide instrumentele pentru dezvoltatori în acea fereastră.

## Exemplu: obiectiv de urmăritori

Acesta este un obiectiv de urmăritori scurt. Folosește un listener de evenimente, `globalValues` și două variabile pentru utilizator: `follower_goal` (Număr) și `bar_color` (Culoare).

HTML:

```html
<div class="goal">
    <span id="count"></span> / <span id="target"></span>
    <div class="bar"><div class="fill"></div></div>
</div>
```

CSS:

```css
body { margin: 0; font-family: Arial, sans-serif; color: #fff; }
.goal { padding: 12px; background: #100c28; border-radius: 16px; font-size: 32px; font-weight: bold; }
.bar { height: 24px; margin-top: 8px; background: #3d3957; border-radius: 12px; overflow: hidden; }
.fill { height: 100%; width: 0; transition: width 0.3s ease; }
```

JavaScript:

```javascript
const target = Number(userVariables.follower_goal.value) || 100;
document.getElementById('target').textContent = target;
document.querySelector('.fill').style.background = userVariables.bar_color.value;

function update(count) {
    document.getElementById('count').textContent = count;
    document.querySelector('.fill').style.width = Math.min((count / target) * 100, 100) + '%';
}

document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;
    if (event_name === 'followEvent' || event_name === 'unfollowEvent') update(data.followers_count);
    if (event_name === 'followerCountUpdatedEvent') update(data.followersCount);
});

update(globalValues.followerCount);
```

Pentru o versiune completă, cu mai multe setări, pornește un widget nou de la șablonul **Simple Follower Goal**.

## Sfaturi

- Desenează starea de început din `globalValues`, apoi schimb-o la evenimente. Un widget care așteaptă un eveniment pare gol până se întâmplă ceva.
- Widgeturi salvate arată butoane de test doar pentru numele de evenimente care apar în JavaScript-ul tău. Scrie numele complet al evenimentului (de exemplu `'followEvent'`) în cod, ca streamerii să-ți poată testa widgetul.
- Lasă fundalul transparent, dacă fundalul nu face parte din design, ca widgetul să stea peste scenă.
- Poți gestiona widgeturile din constructor și cu API-ul KickBot. Vezi [referința API pentru widgeturi](https://kickbot.com/docs/api/reference/widgets).
