# Popup (alert / confirm / prompt)
Links: [Home](../index.md)
Modal dialogs over a full-screen overlay: `alert()` with any number of buttons, `confirm()` (yes / no), `prompt()` (one text input) and a bare `popup()` you fill with your own DOM. Written by SGApps.IO; depends only on the framework's `extensions/prototype` (the `_()` DOM chain) and `uri-load` (for `elements/popup/style.css`).
## Loading the Module
```js
Application.require("elements/popup").then(function (Popup) {
// Popup is a plain object: { popup, alert, prompt, confirm }
Popup.alert('Saved', 'Your document has been saved.');
});
```
**Dependencies:** `extensions/prototype`, `uri-load`. The module links `elements/popup/style.css` (overlay, layout) when it loads. The dialog's look -- buttons, spacing, the icon font, the fade / bounce animation -- comes from the class names of the SGApps **RegalRoyal** theme (`rr-button`, `rr-block-space`, `rr-widget-box`, `rr-text-danger`, `websymbols`, `animated fadeIn` / `bounceIn`, `regal-royal--dark-theme`); with the theme stylesheet on the page (`https://sgapps.io/addons/RegalRoyal/styles/less/style.less.cache.css`) the dialogs look as in the playground, without it they get the browser's default buttons and no animation. The module works either way.
## The dialog structure
Every dialog is one `
` overlay appended to `document.body` by `show()` and removed by `hide()`:
```html
popup.space -- fixed, full screen, z-index 30199999, white 89 % + texture
-- the backdrop: click handling (see onOutsideClick)
popup.body -- the dialog box (50 % width, 350-800 px), theme classes go here
popup.header
popup.content / popup.container -- your content, max-height 80vh, scrolls
popup.footer -- the buttons
```
## API
### `Popup.popup([node], [showOnLoad])`
Builds a bare dialog and returns the **popup object**.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `node` | `HTMLElement` | -- | Appended into `popup.content` when given |
| `showOnLoad` | `boolean` | `true` | `false` builds the dialog without showing it; `true` or omitted calls `show()` right away |
```js
var content = document.createElement('div');
content.innerHTML = '
Custom content
Any DOM goes here.
';
var popup = Popup.popup(content); // shown immediately
popup.footer.appendChild(closeButton); // build your own buttons
popup.theme('dark');
```
#### The popup object
| Member | Type | Description |
|---|---|---|
| `show()` | method | Appends the overlay to `document.body` (no-op when already attached) |
| `hide()` | method | Removes the overlay from the DOM (the object stays usable, `show()` brings it back) |
| `theme(name)` | method | `'light'` -- `regal-royal` on the body, dark class removed; `'dark'` -- adds `regal-royal--dark-theme`; `'clean'` -- removes both classes. Anything else is ignored |
| `space` | `HTMLTableElement` | The overlay (`.module__widget_popup`) |
| `body` | `HTMLDivElement` | The dialog box (`.regal-royal`) -- getter |
| `header` | `HTMLDivElement` | `.module__widget_popup_controls` -- getter |
| `content`, `container` | `HTMLDivElement` | `.module__widget_popup_content` -- `content` is a getter, `container` the same node as a plain property |
| `footer` | `HTMLDivElement` | `.module__widget_popup_footer` -- getter |
| `onOutsideClick` | `boolean` or `function(popup, isBackdrop)` | Click handling on the backdrop cell, see below. Default `true` for `popup()`, `false` for `alert()` / `confirm()` / `prompt()` |
`header`, `content`, `body` and `footer` also have **setters, which do not work** (a string is silently dropped, a node is inserted as the text `[object HTMLElement]`). Always write through the getters: `popup.content.innerHTML = '...'`, `popup.footer.appendChild(button)`.
#### `onOutsideClick`
The `
` that fills the overlay listens to `click`:
| `popup.onOutsideClick` | Effect of a click |
|---|---|
| `false` | a click on the backdrop itself (outside the dialog box) calls `hide()`; clicks inside the box do nothing |
| `true` | nothing (the dialog can only be closed by its buttons or by `hide()`) |
| `function` | called for **every** click inside the overlay, inside the box included: `fn.call(td, popup, isBackdrop)` with `isBackdrop === true` when the click hit the backdrop -- decide yourself what to do |
`popup()` starts with `true` (backdrop clicks ignored); `alert()` (and therefore `confirm()` / `prompt()`) sets it to the **negation** of its `onOutsideClick` configuration key, so an alert closes on a backdrop click by default.
### `Popup.alert(title, [text], [callback])` / `Popup.alert(config)`
Builds a dialog with an icon, a title, a text and a row of buttons, shows it and returns the popup object (extended with `attachButton()` and `buttons`).
The first two arguments are flexible: a **string** is the title / text, an **Element** is inserted as is, a **function** becomes the callback of a single OK button, and a plain **object** is merged into the configuration -- so `alert('Title', 'Text')`, `alert('Title', 'Text', onOk)`, `alert({ title: ..., buttons: [...] })` and `alert(titleNode, { theme: 'dark' })` are all valid.
| Config key | Type | Default | Description |
|---|---|---|---|
| `title` | string, Element | `""` | Title line. With `html: true` a string is inserted as HTML |
| `text` | string, Element, `false` | `""` | Body text (a string is wrapped in `
`); with `html: true` inserted as HTML |
| `icon` | string, Element | `"N"` | A **websymbols glyph**: `" [colour]"`, e.g. `"N danger"` -- the first token is the glyph, the second becomes the class `rr-text-` (`regular` when omitted). An Element is inserted as is; with `html: true` the string is inserted as HTML. Falsy: no icon |
| `theme` | string | `""` | Passed to `popup.theme()` when set: `'light'`, `'dark'`, `'clean'` |
| `buttons` | Array | `[{ text: 'OK', callback: hide, focused: true }]` | Button configurations, see `attachButton()`. An empty array gives a dialog without buttons |
| `html` | boolean | `false` | Insert `title`, `text` and `icon` strings as HTML instead of text |
| `focus` | boolean | `true` | Focus the button whose configuration has `focused: true` after showing |
| `focusWindow` | boolean | `true` | Call `window.focus()` after showing |
| `animate` | boolean | `true` | Add `animated fadeIn` to the overlay and `animated bounceIn` to the box (theme classes; the icon also gets `rotateInDownLeft`) |
| `visible` | boolean | `true` | Show the dialog now; `false` builds it hidden -- call `popup.show()` later |
| `onOutsideClick` | boolean, function | `false` | Close on a backdrop click? `true` **and omitted**: a click on the backdrop (outside the box) closes the dialog; `false`: backdrop clicks are ignored; a function is stored as is and called with `(popup, isBackdrop)` for every click in the overlay. (A boolean you pass is stored **negated** in `popup.onOutsideClick`, where `false` means "closes" -- see above; the default configuration is that internal `false`, hence "omitted" behaves like `true`) |
The generated content, inside `popup.content`:
```html
N
Delete 3 files?
This cannot be undone.
```
#### `popup.attachButton(buttonConfig)` and `popup.buttons`
`alert()` runs every entry of `config.buttons` through `attachButton()`; you can call it later to add more.
| Button config key | Type | Default | Description |
|---|---|---|---|
| `text` | string, Element | `""` | Label |
| `callback` | `function (event, button)` | `function () { this.hide(); }` | Called with `this` = the popup object. Its return value is returned from the click handler (return `false` to cancel the event's default) |
| `className` | string | `""` | Extra class(es) on the `