Here is how the above maps to files on the filesystem:
When a page instance is visited, Boomla will locate the
.Request file on its type chain and execute it. The code shall get the children of the page instance and render them - these will be the individual content elements on the page.
Files on the Boomla Filesystem are stored in order. When getting the children of a file, those will be returned in the order they were stored on disk. Thus, you will not need to worry about sorting the files in code.
A content file can be rendered by calling the file's
.Inline method. It's also said that the content is inlined. It works just like the
.Request method: Boomla will look for an
.Inline file on the file's type chain and execute it.
Here is a problem though. What if a page has both contents and sub-pages? We need a way to get them separately.
On traditional filesystems, a directory is one big container. In Boomla, this container is sub-divided into 256 buckets. This allows one to group the children of a file.
You can select all the children of a file or you can select files in a certain bucket.
Each file has its own 256 buckets:
Each bucket may contain any number of files:
0 is the default bucket. Your program files and assets should be placed there. As you will see later, it is typically used for hidden files.
You can use all the other buckets for any app-specific purpose you want:
In our page app, we will store sub-pages in bucket
1 and contents in bucket
Here is an example filesystem tree with 4 pages (black), some of them having contents (green):
Notice how each page may have both sub-pages in bucket
1 and contents in bucket
2. Those buckets may also be empty. (Of course all other buckets exist as well, they are just not shown here for clarity.)
Make sure to move your pages in bucket
Okay, let's implement the above in code! Here is the HTML layout we will use:
And that's how you can return it with the
sjs-4e to do just that. It's simply pre-processing your code to turn the embedded form into plain JS.
Make sure to change the type of the
.Request file to
To demonstrate how it works, let's embed the page file's title. It shall be stored in the page file's
title property, which we can access via
f points to the current page).
The content files are stored in bucket
2. We can get them via
f.query(':2'). This returns a Collection of files. We can then inline (render) these files by calling
Note that we use
<?== to embed HTML code, which does not need to be HTML escaped, while we use
<?= for the title to embed an unescaped string, which does need to be escaped.
While we could link a simple CSS file for use, it's better to use a CSS module instead, which will namespace our CSS class names, etc., to avoid naming conflicts with other apps.
To do that, let's create the file
/apps/page/style.css and set its type to
css-2, which will do the namespacing for us.
Add some CSS code to it, for example:
When served, it will become something like:
In our JS code, we can select the CSS file using
source.select('../style.css'). Note that the
source variable points to the
.Request file. The
style.css file is its sibling, so we need to use
../style.css to select it. If you simply used
style.css, Boomla would look for it under the
.Request file, that is, at
.Request/style.css. That's a consequence of the filesystem differences.
To load the file as a CSS module, use
response.addCssModule(). It will return an object mapping unescaped class names like
wrapper to their escaped equivalents like
NC174BCFA-wrapper. Use it to dynamically inject the class names:
<? ... ?>.
At this point, all your page instances should display the shared page layout with no contents. Let's add a content element to each page to see that it works.
Create a file within each page instance file,
move it in bucket
set its type to
add some page specific
hello world text the file's body.
Visit the pages in your browser to see that it worked. You can create multiple content files if you want, all of them will be displayed.
We'll implement the menu in the next step.