# HTML component custom API

### Overview

Every **HTML code** component on a page exposes a JavaScript API via `window.FpsHtml_API`. This lets you programmatically control any HTML component from custom scripts — update content, show/hide, re-run embedded scripts, or call backend endpoints — all without a page reload.

### Setup: Component ID

For the API to work, the component must have a **Component ID** set in its settings (`comp_ID` field). Without it the component won't register itself in `window.FpsHtml_API`.

Set a short, unique string like `hero-block` or `promo-banner`.

### Accessing the API

The API is registered after the component mounts. Use the helper below to wait for it:

```javascript
function waitForHtmlAPI(compId, callback, timeout) {
  timeout = timeout || 5000;
  var start = Date.now();
  var check = function() {
    if (window.FpsHtml_API && window.FpsHtml_API[compId]) {
      callback(window.FpsHtml_API[compId]);
    } else if (Date.now() - start < timeout) {
      setTimeout(check, 100);
    } else {
      console.error('FpsHtml_API: component "' + compId + '" not found after ' + timeout + 'ms');
    }
  };
  check();
}
```

Then use it:

```javascript
waitForHtmlAPI('my-block', function(api) {
  api.setHtml('<p>Hello from API!</p>');
});
```

### API Reference

#### `getHtml()`

Returns the current HTML string of the component.

```javascript
var html = api.getHtml();
console.log(html); // '<p>Hello from API!</p>'
```

***

#### `setHtml(newHtml)`

Replaces the component's HTML content.

```javascript
api.setHtml('<h2>Updated content</h2><p>Fresh text here.</p>');
```

***

#### `rerender()`

Forces the component to re-execute all embedded `<script>` tags. Useful when you need scripts inside the HTML to run again without changing the content.

```javascript
api.rerender();
```

***

#### `show()`

Shows the component if it was hidden via `api.hide()`.

```javascript
api.show();
```

***

#### `hide()`

Hides the component programmatically. Does not affect the `isHidden` setting — just toggles visibility at runtime.

```javascript
api.hide();
```

***

#### `getData()`

Returns the full data object the component was initialized with (including `html`, `comp_ID`, `isHidden`, etc.).

```javascript
var data = api.getData();
console.log(data.comp_ID); // 'my-block'
```

***

#### `getElement()`

Returns the root DOM element wrapping the component. Useful for direct DOM manipulation.

```javascript
var el = api.getElement();
el.style.opacity = '0.5';
```

***

#### `callEndpoint(endpoint, method, body, params, callback)`

Makes an authenticated request to a backend endpoint. Works the same as `window.callEndpoint()` but scoped to this component's context.

**Parameters:**

| Parameter  | Type             | Description                                              |
| ---------- | ---------------- | -------------------------------------------------------- |
| `endpoint` | string           | API endpoint name (e.g. `'getItems'`)                    |
| `method`   | string           | HTTP method: `'GET'`, `'POST'`                           |
| `body`     | object\|FormData | Request body (ignored for GET)                           |
| `params`   | object           | URL query parameters                                     |
| `callback` | function         | `(status, data) => {}` — `status` is `'ok'` or `'error'` |

```javascript
api.callEndpoint('getStats', 'GET', null, { period: '30d' }, function(status, data) {
  if (status === 'ok') {
    api.setHtml('<p>Total: ' + data[0].total + '</p>');
  }
});
```

### Examples

#### Load data and render HTML on page load

```javascript
waitForHtmlAPI('stats-widget', function(api) {
  api.callEndpoint('getDashboardStats', 'GET', null, {}, function(status, data) {
    if (status === 'ok') {
      var item = data[0] || {};
      api.setHtml(
        '<div class="stats">' +
          '<span>Users: ' + item.users + '</span>' +
          '<span>Orders: ' + item.orders + '</span>' +
        '</div>'
      );
    } else {
      api.hide();
    }
  });
});
```

***

#### Control visibility from another HTML component

```javascript
// This script lives inside a different HTML component on the same page
document.getElementById('toggle-btn').addEventListener('click', function() {
  var api = window.FpsHtml_API && window.FpsHtml_API['promo-banner'];
  if (api) {
    api.hide();
  }
});
```

***

#### Update content on a button click

```javascript
waitForHtmlAPI('result-block', function(api) {
  document.getElementById('load-btn').addEventListener('click', function() {
    api.setHtml('<p>Loading...</p>');

    api.callEndpoint('fetchResult', 'POST', { id: '123' }, {}, function(status, data) {
      if (status === 'ok') {
        api.setHtml('<p>' + data[0].text + '</p>');
      } else {
        api.setHtml('<p>Error loading data.</p>');
      }
    });
  });
});
```

***

#### Re-run scripts after socket update

If you have scripts inside the HTML component that should re-execute when data refreshes via WebSocket, call `rerender()` after updating content:

```javascript
waitForHtmlAPI('chart-block', function(api) {
  api.callEndpoint('getChartData', 'GET', null, {}, function(status, data) {
    if (status === 'ok') {
      api.setHtml('<canvas id="myChart"></canvas><script>/* init chart with ' + JSON.stringify(data) + ' */<\/script>');
      api.rerender();
    }
  });
});
```

### Notes

* The API is registered after component mount. Always use `waitForHtmlAPI` (or a similar polling approach) rather than accessing `window.FpsHtml_API` directly.
* `hide()` / `show()` is runtime-only. The `isHidden` setting in the component config is a separate mechanism and takes precedence at initial render.
* If the component is removed from the page, its entry in `window.FpsHtml_API` is automatically deleted.
* All requests via `api.callEndpoint()` are authenticated the same way as `window.callEndpoint()`. See `CUSTOM_BROWSER_API.md` for details.
