Index

mmo-app

1 symbol · generated 30 Sep 2026

element

mmo-app

mmo-app.jhs:1

The application shell. One element, three templates, chosen by the host's class: <mmo-app class="admin">, class="landing" or class="blog".

<mmo-app template></mmo-app>
Extends
CustomShadowElement
The `load(config)` contract, the menu, breadcrumb, tab, notification, modal and panel api and the `MMO.app` entry point are the ones projects already use; the shell around them is built on the `.scs` design system, and on three templates instead of one fixed layout. One change, in 3.1.0: a message (`notify`, `alert`, `confirm`, `ask`, `error`, `showModal`, `showNotification`, `showPanel`) is text unless it is a node, where it used to be html -- markup a caller wrote goes through `MMO.core.dom.html()`.

Index

templatethe template to use (admin, landing, blog).
template accessorThe active template.
constructor()
init()
initPanelResize()Let the side panel be dragged wider or narrower by its left edge.
resizePanelByKey(event)Resize the panel from the keyboard: left and right by 16px, 4px with shift, Home back to its default width.
setPanelWidth(width)
resetPanelWidth()Put the panel back to the width the stylesheet gives it.
updateRegions()Reflect which optional regions the page filled, as host classes: a hero, a page header or a rail that no slot fills is removed from the layout instead of holding empty space.
load(config)Load the application configuration, the object the theme writes into MMO.config.
addBreadcrumb(label, url, index)Add a breadcrumb, closest to the root first.
clearTabs()Remove every page tab.
getTabs()Every page tab currently in the strip.
addTab(label, url, icon, order)Add a page tab.
scrollTabs(direction)Scroll the tab strip.
updateTabsOverflow()Show the tab scrollers only when the strip actually overflows.
getMenu(url)Find a rail entry by the url it points at.
setActiveMenu(url)Mark a menu entry, and every accordion above it, as active.
revealMenu(node)Scroll a rail entry into view, in the rail's own scroller.
addMenu(group, label, url, icon, order)Add a menu entry, creating the accordion hierarchy its url implies.
bindAccordionToggle(accordion)Keep an accordion's open state across pages, and keep its title a link.
toggleMenu()Collapse or expand the rail.
shortcut(event)Global shortcuts: alt+/ opens the palette, escape closes what is open.
initCommands()The commands the shell always has: what its own buttons do, when the template has those buttons.
addCommand(label, run, icon, keywords)Add a command to the palette, listed under « Commandes ».
addSearchSource(source)Add a remote source to the palette: its results are listed under their own heading, after the pages and the commands.
openPalette(query)Open the command palette, on the whole menu or already searching.
closePalette()Close the command palette.
filterPalette(query)Filter the palette on what has been typed, one group per category: the text of the page itself first (searchPage), then the pages of the menu, the commands, and each remote source (addSea…
searchPage(query, limit)Find a text in the page: accents and case do not count.
indexPage()Read the text of the page once, when the palette opens, so a search is a lookup rather than a walk through the whole document at every key.
pageMatch(entry, at, length)One match in the page, as a palette item: the words around it, the match marked.
revealPageMatch(node, at, length)Scroll to a match in the page, and select it: the selection is the browser's own highlight, and nothing is written into the page.
fold(text) staticFold a text for searching: lower case, accents dropped -- one character for one character, so an offset in the folded text is the same offset in the original.
searchRemote(source, query)Ask a remote source, and read its answer as palette items.
appendPaletteGroup(parent, title, items)Add a group of results to the palette.
updatePaletteEmpty(query)Keep one result selected, and say so when there is none left -- once no source is still searching.
paletteKey(event)Move through the results, across the groups, and follow the selected one.
showPanel(title, body)Open a panel in the side drawer.
closePanel(value)Close the panel on top of the stack, resolving its promise.
closeAllPanels(value)Close every panel.
showNotification(css, content)Show a notification.
notify(content, title, button, butIcon)Show a notification with a title and a dismiss button.
showModal(css, content)Show a modal dialog.
answer(node, value)Wire a dialog's buttons to its result: any <button value="..."> closes the dialog with that value, and the promise resolves with it -- false when the dialog is dismissed (escape, a click outsid…
ask(title, content)Ask for a value: one input, and the answer.
confirm(title, content)Ask a yes/no question.
alert(title, content)Say something, with one button to dismiss it.
error(title, content)The same, in the error tone.
toggleUserCard()Toggle the account card.
toggleConsole()Toggle the developer drawer.
showConsoleTab(name)Show one pane of the developer drawer, and open the drawer if it was closed.
loadServerInfo(reload)Fill the server pane with what the server is made of: php, its extensions and every package the framework included, as AdminController::routeServerInfo answers them.
toggleTOC()Toggle the table of contents.
updateConsoleTags(console)Update the warning and error counters of the status bar.
gotoTop(event)Scroll back to the top of whichever container actually scrolls.
blockScreen(active)Block the screen while something runs.
setThemeMode(scheme)Apply a colour scheme.
toggleDarkMode()Switch between the dark and light schemes.
(default)the page itself
logothe mark at the top of the rail
menurail entries written by hand, next to the ones MMO.config.menus adds
side-footthe foot of the rail, on the row the scheme switch ends
user-infothe account line next to the account button, at the end of the top bar
user-card-bodywhat the account card shows when it is opened
brandthe brand in the top bar, for the landing and blog templates
navlinks in the top bar
actionsbuttons on the right of the top bar
headeranything else on the top bar, after the actions
herothe band above the page, for a landing
page-titlethe page header's title
page-actionsthe page header's buttons
navigationa strip between the header and the content (filters, a sub-navigation)
asidethe rail on the right of the content, for an article
footerthe footer, for the landing and blog templates
panel-titlethe tabs of the side panel, one per open panel
panelthe body of the side panel
statusthe status bar, left of the log button
logsthe lines the server log tab of the developer drawer shows
notificationsthe notifications stacked in the corner
screen-blockerwhat covers the page while it is blocked (blockScreen)
.adminthe application shell: rail, breadcrumb, page tabs, side panel, status bar
.landingthe marketing shell: sticky translucent header, hero, sections, large footer
.blogthe editorial shell: header, content column, sticky rail, footer
.menu-collapsedthe rail is reduced to icons
.menu-openthe rail is open, on a small screen
.panel-openthe side panel is open
.console-openthe developer drawer (server log, server information) is open
.toc-openthe table of contents is open
.palette-openthe command palette is open, over the page
.has-herothe page filled the hero region, so the shell makes room for it
.has-user-cardthe page filled the account card, so it gets a body above the logout link

Attributes1

template

mmo-app.jhs

the template to use (admin, landing, blog). Defaults to the host's class.

template

Properties1

template

accessormmo-app.jhs:1240

The active template.

get template() set template(value)
Type
string

Methods57

initPanelResize()

mmo-app.jhs:1161

Let the side panel be dragged wider or narrower by its left edge.

initPanelResize()`MMO.inputs.Drag` in `size-x` mode resizes by the left edge, which is the one the panel has: it grows towards the content. The panel's own `max-width` caps it, and 240px is the point below which its header no longer fits.
returnsvoid

resizePanelByKey(event)

mmo-app.jhs:1187

Resize the panel from the keyboard: left and right by 16px, 4px with shift, Home back to its default width.

resizePanelByKey(event)
eventKeyboardEvent
returnsvoid

setPanelWidth(width)

mmo-app.jhs:1207
setPanelWidth(width)
widthnumber- in pixels
returnsvoid

resetPanelWidth()

mmo-app.jhs:1214

Put the panel back to the width the stylesheet gives it. @return {void}

resetPanelWidth()

updateRegions()

mmo-app.jhs:1224

Reflect which optional regions the page filled, as host classes: a hero, a page header or a rail that no slot fills is removed from the layout instead of holding empty space.

updateRegions()

load(config)

mmo-app.jhs:1262

Load the application configuration, the object the theme writes into MMO.config.

load(config)A link's label is html: it is the application's own config (a page's `index.json`, what a controller adds to the document), like every other region -- a controller naming a link after data escapes it.
configobject- breadcrumbs, navigations, menus and logs

addBreadcrumb(label, url, index)

mmo-app.jhs:1309

Add a breadcrumb, closest to the root first.

addBreadcrumb(label, url, index = 0)
labelstring- html, from the application's config (load)
urlstring
index = 0number- the depth of this crumb
returnsHTMLAnchorElement

getTabs()

mmo-app.jhs:1325

Every page tab currently in the strip.

getTabs()
returnsNodeListthe page tabs

addTab(label, url, icon, order)

mmo-app.jhs:1337

Add a page tab.

addTab(label, url, icon = null, order = 0)
labelstring- html, from the application's config (load)
urlstring
icon = null?string
order = 0number
returnsHTMLAnchorElement

scrollTabs(direction)

mmo-app.jhs:1353

Scroll the tab strip.

scrollTabs(direction)
directionnumber- -1 left, 1 right

updateTabsOverflow()

mmo-app.jhs:1359

Show the tab scrollers only when the strip actually overflows.

updateTabsOverflow()

getMenu(url)

mmo-app.jhs:1374

Find a rail entry by the url it points at.

getMenu(url)
urlstring
returns?HTMLElementthe menu entry for this url

setActiveMenu(url)

mmo-app.jhs:1387

Mark a menu entry, and every accordion above it, as active.

setActiveMenu(url)A marked entry nobody can see is not a mark: the folders it sits under are opened, and the rail is scrolled to it -- inside the rail only, so the page itself does not move.
urlstring

revealMenu(node)

mmo-app.jhs:1416

Scroll a rail entry into view, in the rail's own scroller.

revealMenu(node)
nodeHTMLElement

addMenu(group, label, url, icon, order)

mmo-app.jhs:1437

Add a menu entry, creating the accordion hierarchy its url implies.

addMenu(group, label, url, icon, order = 0)
groupstring- the section of the rail this entry belongs to, html (load)
labelstring- html, from the application's config (load)
urlstring
iconstring
order = 0number

bindAccordionToggle(accordion)

mmo-app.jhs:1520

Keep an accordion's open state across pages, and keep its title a link.

bindAccordionToggle(accordion)
accordionHTMLElement

toggleMenu()

mmo-app.jhs:1536

Collapse or expand the rail. On a small screen it opens as a drawer instead.

toggleMenu()

shortcut(event)

mmo-app.jhs:1557

Global shortcuts: alt+/ opens the palette, escape closes what is open.

shortcut(event)`/` is read from the key *and* from its position: on a qwerty keyboard alt+/ is the `Slash` key, but a mac turns it into `÷`, and an azerty keyboard has `/` on shift.
eventKeyboardEvent

initCommands()

mmo-app.jhs:1574

The commands the shell always has: what its own buttons do, when the template has those buttons.

initCommands()

addCommand(label, run, icon, keywords)

mmo-app.jhs:1591

Add a command to the palette, listed under « Commandes ».

addCommand(label, run, icon = null, keywords = '')
labelstring- text
runFunction- called when the command is picked, once the palette is closed
icon = null?string- an <mmo-icon> name
keywords = ''string- other words the command is found by
returnslabel: string, run: Function, icon: ?string, keywords: string} the command
MMO.app.addCommand('Vider le cache', () => clearCache(), 'trash', 'cache clear')

addSearchSource(source)

mmo-app.jhs:1607

Add a remote source to the palette: its results are listed under their own heading, after the pages and the commands. The server is asked url?q=…&limit=… (plus params) and answers {results: [{url, label | shortName | name, kind, hint | namespace, icon}]}, or the same wrapped in data. The server usually declares its sources in MMO.config.searches (load).

addSearchSource(source)
source
returnsObjectthe source
MMO.app.addSearchSource({name: 'documentation', label: 'Documentation', url: MMO.url('doc/search')})

openPalette(query)

mmo-app.jhs:1618

Open the command palette, on the whole menu or already searching.

openPalette(query = '')
query = ''string- what the palette starts with
MMO.app.openPalette('Route')

filterPalette(query)

mmo-app.jhs:1642

Filter the palette on what has been typed, one group per category: the text of the page itself first (searchPage), then the pages of the menu, the commands, and each remote source (addSearchSource), which only answers once typing pauses.

filterPalette(query)A page is matched on its label *and* its url, so it is found by what it is called or by where it lives.
querystring

searchPage(query, limit)

mmo-app.jhs:1711

Find a text in the page: accents and case do not count. Each match is listed with its context and the heading it sits under; picking it scrolls to it and selects it (revealPageMatch).

searchPage(query, limit = 20)
querystring
limit = 20number
returnsArray<Object>palette items

indexPage()

mmo-app.jhs:1733

Read the text of the page once, when the palette opens, so a search is a lookup rather than a walk through the whole document at every key. The page is what the default slot and the page's own regions hold -- never the menu, the panels or the notifications -- open shadow roots included, and only what is visible.

indexPage()
returnsArray<{node: Text, text: string, heading: string>} each text node, folded (fold), with the heading it sits under

pageMatch(entry, at, length)

mmo-app.jhs:1775

One match in the page, as a palette item: the words around it, the match marked.

pageMatch(entry, at, length)
entry
atnumber- where the match starts in the text node
lengthnumber
returnsObject

revealPageMatch(node, at, length)

mmo-app.jhs:1799

Scroll to a match in the page, and select it: the selection is the browser's own highlight, and nothing is written into the page.

revealPageMatch(node, at, length)
nodeText
atnumber
lengthnumber

fold(text)

staticmmo-app.jhs:1820

Fold a text for searching: lower case, accents dropped -- one character for one character, so an offset in the folded text is the same offset in the original.

static fold(text)
textstring
returnsstring

searchRemote(source, query)

mmo-app.jhs:1832

Ask a remote source, and read its answer as palette items.

searchRemote(source, query)
source
querystring
returnsPromise<Array<Object>>

appendPaletteGroup(parent, title, items)

mmo-app.jhs:1852

Add a group of results to the palette.

appendPaletteGroup(parent, title, items)
parentHTMLElement
titlestring- the category
items

updatePaletteEmpty(query)

mmo-app.jhs:1887

Keep one result selected, and say so when there is none left -- once no source is still searching.

updatePaletteEmpty(query)
querystring

paletteKey(event)

mmo-app.jhs:1904

Move through the results, across the groups, and follow the selected one.

paletteKey(event)
eventKeyboardEvent

showPanel(title, body)

mmo-app.jhs:1944

Open a panel in the side drawer.

showPanel(title, body)The promise it returns is the panel's result: `closePanel(value)` resolves it with `value`, which is how an edit form in a panel reports what the user did (`MMO.elements.Entity`). The title and the body are text unless they are nodes, like every message of the shell (`showModal`).
titlestring- text
body?(Node | string | MMO.core.dom.Html)- a node, or text; markup you wrote goes through MMO.core.dom.html()
returnsPromiseresolved with the value the panel is closed with. promise.node is the panel's body element, for a caller that has to reach into it.
MMO.app.showPanel(entity.title, form)

closePanel(value)

mmo-app.jhs:1965

Close the panel on top of the stack, resolving its promise.

closePanel(value = null)
value = null*- what showPanel's promise resolves with

closeAllPanels(value)

mmo-app.jhs:1978

Close every panel.

closeAllPanels(value = null)
value = null*- what each panel's promise resolves with

showNotification(css, content)

mmo-app.jhs:1994

Show a notification.

showNotification(css, ...content)Like every message of the shell (`showModal`), its content is text unless it is a node: what a caller got from a user or an api shows as it was typed. Markup it wrote itself goes through `MMO.core.dom.html()`.
cssstring- a tone class: success, warning, error, info
...content...*- its children (MMO.core.dom.appendChildren); one with a slot goes to that part of the card, title or footer (mmo-notification)
returnsHTMLElement
MMO.app.showNotification('success', MMO.core.dom.createElement('span', {slot: 'title'}, 'Saved'), file.name)

notify(content, title, button, butIcon)

mmo-app.jhs:2014

Show a notification with a title and a dismiss button.

notify(content, title, button = 'ok', butIcon = 'eye')
content*- the body: text, a node, or MMO.core.dom.html() (showNotification)
titlestring- text
button = 'ok'string- the dismiss label, text
butIcon = 'eye'string- the dismiss icon
returnsHTMLElement
MMO.app.notify(file.name + ' is saved.', 'Saved')

showModal(css, content)

mmo-app.jhs:2038

Show a modal dialog.

showModal(css, ...content)Its content is text unless it is a node: a name, an error's message, anything a caller got from a user or an api shows as it was typed and runs nothing -- the same goes for `ask`, `confirm`, `alert`,
See
error, showNotification, notify and showPanel. Markup the caller wrote itself goes through MMO.core.dom.html().
cssstring
...content...*- its children, MMO.core.dom.appendChildren
returnsHTMLDialogElement
MMO.app.showModal('info', MMO.core.dom.createElement('h2', {}, file.name), MMO.core.dom.html('<p>is <b>saved</b></p>'))

answer(node, value)

mmo-app.jhs:2054

Wire a dialog's buttons to its result: any <button value="..."> closes the dialog with that value, and the promise resolves with it -- false when the dialog is dismissed (escape, a click outside), so a caller can always tell "no" from "not answered".

answer(node, value)
nodeHTMLDialogElement
valuefunction(HTMLDialogElement, string):*- what to resolve with, from the button's value
returnsPromise

ask(title, content)

mmo-app.jhs:2083

Ask for a value: one input, and the answer.

ask(title, ...content)
titlestring- text
...content...*- shown above the input: text unless it is a node (showModal)
returnsPromise<string | false>what was typed, false when cancelled
MMO.app.ask('Rename « ' + folder.name + ' »', 'Its new name:')

confirm(title, content)

mmo-app.jhs:2106

Ask a yes/no question.

confirm(title, ...content)
titlestring- text
...content...*- text unless it is a node (showModal)
returnsPromise<boolean>
MMO.app.confirm('Delete « ' + file.name + ' »?', 'It cannot be recovered.')

alert(title, content)

mmo-app.jhs:2121

Say something, with one button to dismiss it.

alert(title, ...content)
titlestring- text
...content...*- text unless it is a node (showModal)
returnsPromise<boolean>true when it was acknowledged

error(title, content)

mmo-app.jhs:2136

The same, in the error tone.

error(title, ...content)
titlestring | Error- text: an Error reads as Error: its message
...content...*- text unless it is a node (showModal)
returnsPromise<boolean>
MMO.app.error(file.name, error.message)

showConsoleTab(name)

mmo-app.jhs:2162

Show one pane of the developer drawer, and open the drawer if it was closed. The server pane is fetched the first time it is asked for, not on every page load: it is a tool, not a page region.

showConsoleTab(name)
namestring- logs or server

loadServerInfo(reload)

mmo-app.jhs:2177

Fill the server pane with what the server is made of: php, its extensions and every package the framework included, as AdminController::routeServerInfo answers them.

loadServerInfo(reload = false)
reload = falseboolean- fetch again even if the pane was already filled
returnsPromise

updateConsoleTags(console)

mmo-app.jhs:2219

Update the warning and error counters of the status bar.

updateConsoleTags(console)
consoleHTMLElement

gotoTop(event)

mmo-app.jhs:2228

Scroll back to the top of whichever container actually scrolls.

gotoTop(event = null)
event = null?Event

blockScreen(active)

mmo-app.jhs:2238

Block the screen while something runs.

blockScreen(active = true)
active = trueboolean

setThemeMode(scheme)

mmo-app.jhs:2246

Apply a colour scheme.

setThemeMode(scheme = 'default')
scheme = 'default'string- dark, light or default to follow the system

toggleDarkMode()

mmo-app.jhs:2263

Switch between the dark and light schemes.

toggleDarkMode()

Slots22

menu

mmo-app.jhs

rail entries written by hand, next to the ones MMO.config.menus adds

<slot name="menu">

side-foot

mmo-app.jhs

the foot of the rail, on the row the scheme switch ends

<slot name="side-foot">

user-info

mmo-app.jhs

the account line next to the account button, at the end of the top bar

<slot name="user-info">

user-card-body

mmo-app.jhs

what the account card shows when it is opened

<slot name="user-card-body">

brand

mmo-app.jhs

the brand in the top bar, for the landing and blog templates

<slot name="brand">

actions

mmo-app.jhs

buttons on the right of the top bar

<slot name="actions">

header

mmo-app.jhs

anything else on the top bar, after the actions

<slot name="header">

hero

mmo-app.jhs

the band above the page, for a landing

<slot name="hero">

page-title

mmo-app.jhs

the page header's title

<slot name="page-title">

page-actions

mmo-app.jhs

the page header's buttons

<slot name="page-actions">

navigation

mmo-app.jhs

a strip between the header and the content (filters, a sub-navigation)

<slot name="navigation">

aside

mmo-app.jhs

the rail on the right of the content, for an article

<slot name="aside">

panel-title

mmo-app.jhs

the tabs of the side panel, one per open panel

<slot name="panel-title">

panel

mmo-app.jhs

the body of the side panel

<slot name="panel">

status

mmo-app.jhs

the status bar, left of the log button

<slot name="status">

logs

mmo-app.jhs

the lines the server log tab of the developer drawer shows

<slot name="logs">

notifications

mmo-app.jhs

the notifications stacked in the corner

<slot name="notifications">

screen-blocker

mmo-app.jhs

what covers the page while it is blocked (blockScreen)

<slot name="screen-blocker">

CSS hooks11

.admin

mmo-app.jhs

the application shell: rail, breadcrumb, page tabs, side panel, status bar

.admin

.landing

mmo-app.jhs

the marketing shell: sticky translucent header, hero, sections, large footer

.landing

.blog

mmo-app.jhs

the editorial shell: header, content column, sticky rail, footer

.blog

.menu-collapsed

mmo-app.jhs

the rail is reduced to icons

.menu-collapsed

.menu-open

mmo-app.jhs

the rail is open, on a small screen

.menu-open

.panel-open

mmo-app.jhs

the side panel is open

.panel-open

.console-open

mmo-app.jhs

the developer drawer (server log, server information) is open

.console-open

.toc-open

mmo-app.jhs

the table of contents is open

.toc-open

.palette-open

mmo-app.jhs

the command palette is open, over the page

.palette-open

.has-hero

mmo-app.jhs

the page filled the hero region, so the shell makes room for it

.has-hero

.has-user-card

mmo-app.jhs

the page filled the account card, so it gets a body above the logout link

.has-user-card