For today something that is not easy to describe in a single post: createList.
createList is a very, very useful function that does... create a list! YAY!
As you very well know, lists are present almost everywhere: even the messages in a topic are a list, the (list of) messages in a board, etc., but create a list is a lot of repetitive tasks:- grab the elements (possibly sorted in some way),
- "process" them,
- order them in columns,
- create pages (if needed),
- send them to a template.
And apart from few specific things the "basic" code is always the same.
And here it comes createList to help in a way: with that function the "only" thing you have to do to create a list of something is define an array of information, and no, I don't mean the data you have to display, but "how" you want to retrieve and display them.
Let's take a quick look at all (at least those documented) the options available in createList:
https://github.com/elkarte/Elkarte/wiki/Createlist
In a very short summary, in the array that you will pass to createList you define:- an unique identifier of the list,
- the columns you want to display (this requires a bit more),
- and a function (name or object and method) that will be called to retrieve the data,
and the list is ready.
Let's not continue without an example in front of us:
https://github.com/elkarte/Elkarte/blob/v1.0.0-beta.1/sources/admin/ManageAttachments.controller.php#L1392
This example is the declaration of the array of informations that will be later on passed to createrList. It is also moderately simple, there are the basics plus just a couple of extras here and there, so it is suitable for use in a tutorial like that one.
So, let's split it up into pieces to better analyse it, first chunk:
$listOptions = array(
'id' => 'attach_paths',
'base_href' => $scripturl . '?action=admin;area=manageattachments;sa=attachpaths;' . $context['session_var'] . '=' . $context['session_id'],
'title' => $txt['attach_paths'],
'get_items' => array(
'function' => 'list_getAttachDirs',
),
Ohhh many interesting things.
First of all the unique id of the list is 'attach_paths', why this is important? Easy: because you can use createList multiple times in a page, and in order to distinguish the results you need something to identify them. But this is not the only reason, the id is also important because every time createList is called, the id is used to "generate" a hook:
function createList($listOptions)
{
call_integration_hook('integrate_' . $listOptions['id'], array($listOptions));
it's the first line of createList . In our example then when createList is called, the hook integrate_attach_paths will be called. This is particularly important for addons, for two reasons: first because they can hook out of the box any list in ElkArte that uses createList, and second because any time they will use createList an hook will be called and other addons will be able to use it. At the moment, due to the bug and some limits the hook doesn't have "full and flexible powers" on the list, but this is something for the next time.
Second element of the array above is 'base_href', this is necessary in two cases:- when the list is spread across multiple pages
- when the list can be sorted
in this case the declaration seems useless..., but let's not be too picky. 
The base_href parameter is simply the common, base, part of the url that will be used to create the links in the headers for sorting columns or to pass from one page to the other.
Next one if 'title', well, easy enough: an header (h3 in the common template) that will be displayed above the list.
Finally the most important 'get_items' this array, in this simple form, contains only the name of the function that will be called to retrieve the elements of the list, in that case list_getAttachDirs.
Okay, next chunk:
'columns' => array(
'current_dir' => array(
'header' => array(
'value' => $txt['attach_current'],
'class' => 'centertext',
),
'data' => array(
'function' => create_function('$rowData', '
return \'<input type="radio" name="current_dir" value="\' . $rowData[\'id\'] . \'" \' . ($rowData[\'current\'] ? \' checked="checked"\' : \'\') . (!empty($rowData[\'disable_current\']) ? \' disabled="disabled"\' : \'\') . \' class="input_radio" />\';
'),
'style' => 'width: 10%;',
'class' => 'centertext',
),
),
'path' => array(
'header' => array(
'value' => $txt['attach_path'],
),
'data' => array(
'function' => create_function('$rowData', '
return \'<input type="hidden" name="dirs[\' . $rowData[\'id\'] . \']" value="\' . $rowData[\'path\'] . \'" /><input type="text" size="40" name="dirs[\' . $rowData[\'id\'] . \']" value="\' . $rowData[\'path\'] . \'"\' . (!empty($rowData[\'disable_base_dir\']) ? \' disabled="disabled"\' : \'\') . \' class="input_text"/>\';
'),
'style' => 'width: 40%;',
),
),
'current_size' => array(
'header' => array(
'value' => $txt['attach_current_size'],
),
'data' => array(
'db' => 'current_size',
'style' => 'width: 15%;',
),
),
'num_files' => array(
'header' => array(
'value' => $txt['attach_num_files'],
),
'data' => array(
'db' => 'num_files',
'style' => 'width: 15%;',
),
),
'status' => array(
'header' => array(
'value' => $txt['attach_dir_status'],
'class' => 'centertext',
),
'data' => array(
'db' => 'status',
'style' => 'width: 25%;',
'class' => 'centertext',
),
),
),
BAM!
Columns.
In this central part we are defining what columns we want to be able to see in our list, the way to define a column can have several variants, the the two mandatory parts are the header and "how to show the data" that can be one of several elements.
First off let's remember that this part is "working" with the array of values returned by the 'get_items' function, this may become more clear as we go.
'header' usually contains a 'value' that is a simple text string used as header of a column, in some of the above columns there is also a 'class', this si a css class that will be attached to the header of the column to style it.
Now the most important part: 'data', this is an associative array that defines the content and style of each and every cell of our list/table. There are several way pick the "value" we want to display, in the example above only two of them are used, so let's just stick with those (all the others are explained in the documentation):- 'db', is the easiest way to grab something to displayin createList, it just pick the corresponding index from the array returned by the 'get_items' function
- 'function' this instead is the most flexible way to deal with data, it is a function that is executed for each entry in the corresponding column. The function receives as argument the full row of data each time. The function shall return a string that is what will be used to populate the cell.
I think that for this time there is already enough informations floating around, so let's just skim through the last bits:
'form' => array(
'href' => $scripturl . '?action=admin;area=manageattachments;sa=attachpaths;' . $context['session_var'] . '=' . $context['session_id'],
),
'additional_rows' => array(
array(
'position' => 'below_table_data',
'value' => '
<input type="hidden" name="' . $context['session_var'] . '" value="' . $context['session_id'] . '" />
<input type="submit" name="save" value="' . $txt['save'] . '" class="right_submit" />
<input type="submit" name="new_path" value="' . $txt['attach_add_path'] . '" class="right_submit" />',
),
empty($errors['dir']) ? array(
'position' => 'top_of_list',
'value' => $txt['attach_dir_desc'],
'style' => 'padding: 5px 10px;',
'class' => 'windowbg2 smalltext'
) : array(
'position' => 'top_of_list',
'value' => $txt['attach_dir_save_problem'] . '<br />' . implode('<br />', $errors['dir']),
'style' => 'padding-left: 35px;',
'class' => 'warningbox',
),
),
);
'form' this can be used to "surround" the list with a form (so that you can let people input things and then submit them as a normal html form).
'additional_rows' is an array of elements that can be positioned in several different places before and after the list itself, they are frequently used to add buttons or legends or other elements necessary to the list.
Once the list is created, where does the data go?
There are two possible ways to render a list:- using a sub_template that directly handles the array generated by the list
- using the default template_show_list template
In this second case, there are again two possibilities:- use template_show_list as a sub_template
- call it from another sub_template
Let's forget for the moment about 1, and let's focus on 2. In order to use template_show_list as a sub_template, we have to do another "trick" before:
$context['default_list'] = 'attach_paths';
we have to define which one is the "default list" to show.
Then we can define the sub_template as usual:
$context['sub_template'] = 'show_list';
and it's done.
The alternative 2b is used for example when you want to have multiple lists in the same page, in that case you can define your own sub_template like:
$context['sub_template'] = 'my_own_list';
Then you will create the template like:
function template_my_own_list()
{
template_show_list('attach_paths');
}
you will pass the id of the list you want to display as argument of template_show_list and the generic template will render your list for you!
This is much more than I wanted to write...
Oh well, next one will be short.