Skip to content

Render Lists

Leo edited this page Feb 1, 2024 · 3 revisions

This page explains how to use placeholders to render a list of objects. The first half of the page will address pre existing lists, while the second half will explain lazy list rendering with blocking list suppliers.

Simple Case: An existing list

Often, you simply want to render a list of elements (Strings, bools, ints, ..) in a clean way. To do so with the Translations Framework, use the following code (example with a boolean list)

Message SOME_LIST = translations.messageBuilder("some.list")
        .withDefault("Header\n<my_list:'\n'> {index}.) {el}</my_list>\nFooter").build();
sendMessage(player, SOME_LIST.insertList("my_list", List.of(true, false, true, false)));

Which renders as

Header
 1.) true
 2.) false
 3.) true
 4.) false
Footer

So in explanation: the NanoMessage segment between open and close tag define how one single element gets rendered.

{el} is the actual value, {index} the position of the element in the list.

Complex objects (not string, number or boolean) render via object resolving, see the section about placeholders.

Quick example - el is of type Player and {el:name} is the player name.

Message SOME_LIST = translations.messageBuilder("some.list")
        .withDefault("Header\n<my_list:'\n'> {index}.) {el:name}</my_list>\nFooter").build();
sendMessage(player, SOME_LIST.insertList("my_list", Bukkit.getOnlinePlayers()));

How to Set the Separator

The separator is the component that is being inserted between every two list elements. It can easily be defined in the list tag. <elements> will render with , as separator, but <elements:'\n<gray>- </gray>'> will start a new line for each new entry and insert the suffix - in gray.

Important
Keep in mind that the separator is not a prefix or suffix for elements, so \n- as separator to get a list will not insert a - before the very first list element. To do so, you would add it to the actual element format, like so:

demo.list.header="<elements:'\n'>"
demo.list.element="<gray>- </gray><element>"

Paginate a List

Lists that are made with the insertList method are always paginated. This means, that a specified page and page-size are being rendered. If you don't pass these values as parameter, it will make the first page as big as the whole list.

Important
Pagination is an important feature to limit the size of the component. If you render a list with thousands of elements in one message, you might create components that are even too large to send as packet and the player will be kicked instead of receiving any message.

Here is the example from above with a pagination

Message ELEMENT_LIST = translations.messageBuilder("demo.list.header")
        .withDefault("--- Header ---\n<my_list>{el ? '<red>true' : '<false>false' }</my_list>\n--- <page>/<pages> ---").build();

sendMessage(player, ELEMENT_LIST.insertList("my_list", List.of(true, false, false, true), ListSegment.paged(0, 2)));

The code above will produce

--- Header ---
<green>true</green>, <green>true</green>
--- 2/2 ---

Placeholders for Existing Lists

As you can see, we used the placeholders <page> and <pages> in the previous example. There is a set of valid placeholders for the not lazy list rendering:

Key Description
has-pages A choice tag that allows you to render a different text if only one page exists.
page A number tag that shows the current page index counting from 1.
pages The total page count for the given list.
next-page The tag + 1, but not bigger than .
prev-page The tag - 1, but not smaller than 1.
range the page size.
offset ( - 1) *

These placeholders can be used to make clickable footers that render the next page of your list. Pass the <next-page> or <prev-page> tag to the command and use <click> tags to execute the command.

Command:

/mylist <page>
# I know it looks messy but this is total control for your plugins administrators.
list="...\n<click:run_command:/mylist <prev-page>>←</click> <page>/<pages> <click:...>→</click>"