Calls
RegisterPage answers false when the page it was given cannot be drawn, which is also what
happens to a page whose fields are of the wrong type: what the map cannot render it refuses rather
than showing an empty screen. The reason is written to the console, so a refused page does not have
to be guessed at. RemovePage answers whether there was a page of that id to remove.
A page belongs to the resource that registered it. Registering your own id again replaces the
first. Only that resource can update the page, set its content, register over it or remove it; the
exports answer false to anyone else and say why in the console. OpenPage opens the menu on the page when it is
closed, so a page can be reached from a command or a key of your own resource. It opens over the
game without the map’s camera; pass true as the second argument to fly the camera up first. The
camera comes up anyway once the player picks the Map tab.
Fields
The page
The document
wide = true makes one take the full width. title is not drawn: the
tab the player opened already names the page. subtitle is a line above the sections.
The page is driven the way the settings screen is. The arrow keys move a cursor through everything
that can be used, in reading order; left and right step a select, switch a toggle and move
between a row’s actions; Enter presses a button, chooses a row or fires the action picked, and puts
the caret in an input. A select steps through its options between two arrows, one action per
step. Text, stats and disabled controls are passed over.
A row of a list is
{ id, label, meta, icon, color, disabled, actions }. icon and color are a
marker sprite and colour, drawn the way the legend draws them. actions is a list of
{ id, label, variant } shown at the end of the row. meta is text or a number. A variant that
is not one of the three is ignored and the control is drawn as its default.
A label too long for its row is cut with an ellipsis, on a tab, a row, a button and a select alike.
A row has room for two short actions on a 1024-pixel-wide screen; with more, their labels are cut
first.
An item the map does not know is skipped, so a page written for a newer map still shows the rest of
its content.
Embedding your own interface
https, and its host must be the NUI origin of a resource on this server:
cfx-nui-<resource> and nothing more, so a registrable domain such as cfx-nui-x.example.com is not
one: or a host listed whole in pageEmbedHosts in Menu. An address carrying a userinfo section
(https://cfx-nui-x@example.com/) loads example.com and is refused, as is one whose host is
percent-encoded or non-ASCII. Anything else is refused.
The frame is sandboxed and is not same-origin with the map, so the embedded page cannot reach the
map’s interface or its callbacks. It talks to its own resource, the way any NUI page does.
Escape goes back from an embedded page as it does from any other, also after the player has clicked
inside it.
What happens
The action table is
{ page, action, row, value }.
The map holds no state of its own for a page: answer an action by sending the page back with
SetPageContent. A toggle or a select shows the value you sent until you send another, and an
input takes the value you send unless the player is typing in it.
A view has the last word on which pages it hosts: a page its
surface.pages does not list is neither drawn as a tab nor opened by OpenPage while that view is
on screen. A page that is open when the view stops allowing it is closed. The page stays registered
and comes back with the next view that allows it.
Errors
RegisterPage answers false and says why in the console when a page has no id, no label, or
content that is neither a document nor an embeddable address. Nothing is registered: there is no
half-registered page and no tab.
An item the map does not understand is dropped from the page rather than refusing the whole of it,
so a page written for a newer map still shows the rest of its content. An item of a kind in the
table above that lacks a field it needs is dropped too, and the console says which kind, once per
page. A section whose items is missing or empty is not drawn.
An embed whose address does not pass the rule above is refused at registration, so it never reaches
the interface. The interface applies the same rule again before it draws the frame, and shows
“Embedded page refused” in place of the page if it ever disagrees.
SetPageContent and RemovePage answer false for a page that is not registered.