---
title: Admin Loading Data modal
menu_group: Getting started
menu_order: 25
tab: —
tab_order: 25
summary: Shared Loading Data modal used by MediaBlaster core and add-on admin importers for blocking async work.
---

# Admin Loading Data modal

MediaBlaster uses one branded **Loading Data** modal for blocking admin async work (imports, library fetches, destination saves). Core and paid add-ons must share this pattern so screens feel consistent.

## When to use it

Use the shared modal when the user must wait and should not interact with the page:

- Initial catalog / show / episode list fetches
- Destination create/link before browsing
- Import preview / batch start
- Other multi-second REST or AJAX operations that replace the main workspace

Do **not** invent a second spinner overlay, `alert()` for loading, or plugin-local modal CSS that copies Ember/Neon Orange independently.

Inline progress (sync utility strips, job progress bars) remains appropriate for long-running background work that should stay visible while the page is usable.

## Canonical implementation

| Piece | Location |
|-------|----------|
| Markup helper | `MediaBlaster_Admin_UI::render_loading_dialog()` in `includes/class-mediablaster-admin-ui.php` |
| Styles | `.mb-loading-dialog*` in `admin/css/mediablaster-admin-ui.css` |
| JS API | `window.MediaBlasterAdminUI.loading.show(message, options)` / `.hide(options)` in `admin/js/mediablaster-admin-ui.js` |
| Brand tokens | Ember `#F15A24`, Neon Orange `#F97316`, Obsidian `#111827` (Pomelli brand book) |

### PHP (once per screen)

```php
if ( class_exists( 'MediaBlaster_Admin_UI' ) ) {
	MediaBlaster_Admin_UI::render_loading_dialog(
		array(
			'id' => 'mb-loading-dialog', // default; override only if multiple roots
		)
	);
}
```

Register the screen on `mediablaster_admin_ui_target_pages` (and hook needles) so shared CSS/JS load. Enqueue your page script with dependency `mediablaster-admin-ui`.

### JavaScript

```js
var loading = window.MediaBlasterAdminUI && window.MediaBlasterAdminUI.loading;
if ( loading ) {
	loading.show( 'Loading episodes…' ); // title stays "Loading Data"
	// Optional determinate progress (e.g. server-polled mapping):
	loading.setProgress( { current: 12, total: 50, message: 'Mapping episode 12 of 50…' } );
	// …async work…
	loading.hide();
}
```

- `show()` is idempotent: if the dialog is already open, it updates the message only. Pass `{ keepProgress: true }` to avoid resetting the progress bar when refreshing the status line.
- `setProgress({ current, total, message })` shows a determinate bar when `total > 0` and updates the status message. It only updates an **already open** dialog (never reopens after `hide()`), so late poll responses cannot stick the modal open.
- `hide()` always closes the dialog and clears progress.
- Escape is blocked while the modal is open (cancel event prevented).
- Prefer plain-language status messages under the fixed title **Loading Data** (e.g. “Mapping episode 12 of 50…”).

Optional `options.id` targets a non-default dialog id. Optional `options.title` overrides the heading (rare — keep **Loading Data** unless the product copy must differ).

**Import from Spreaker** passes a `progress_key` on destination / episode list / preview requests and polls `GET …/import/progress/{key}` so the modal can show “Mapping episode X of Y…” while PHP classifies the page.

## Current consumers

- **Import from Vimeo** (`r_vimeo_import`) — library list fetches via `setBrowseLoading()`
- **Import from Spreaker** (`mediablaster_spreaker_import`) — shows, destination, episodes, preview, batch start

New importer UIs (core or add-on) should call the same helper and API. Do not ship a duplicate `.mb-*-loading-dialog` stylesheet.

## Accessibility

- Dialog uses `aria-labelledby` on the title and `aria-busy="true"`.
- Pair with `aria-live` announcements and `aria-busy` on the results region when lists refresh.
- Honor `prefers-reduced-motion` (spinner animations disabled in shared CSS).

## Related docs

- [Import from Vimeo](vimeo-mass-import.md)
- Brand book: `.cursor/branding/mediablaster_brand_book_by_pomelli.pdf` (Ember Red, Neon Orange, Obsidian Black, Denim Blue, Pure White)
