Documentation

Customization

The HTML template syntax explained

HTML templates are simple HTML documents or HTML snippets containing additional information about adding or replacing content.

An important component in the HTML templates are variables. These fragments are used to express and output unique content. How to use these variables and other syntax templates is explained in this chapter of our documentation.

Note: The instructions for use in HTML templates are written in curly brackets.

Variables

Back to top

Variables are placeholders, that get filled with specific content by the app, when a page is loaded.

To add the contents of a variable to an HTML template, wrap the name of the variable in curly brackets.

Example:

{new-variable}

The current language is {sys:locale}

<a class="logout" href="{logout-url}">logout</a>
            

A variable can contain text, figures, associative or numeric arrays and even more complex data like nested arrays.

The available variables for an HTML template are defined by the application, based on what is required or helpful. Please copy the names of the variables from the existing templates.

Automatic variables

Back to top

Automatic variables contain contents from specific data sources. Their names consists of a prefix (e.g. text), followed by a colon, followed by a data source specific name (e.g. about-manja).

{text:*} – Contents of the named text in the user chosen language.

Note: for practical reasons, the content of {text:*}variables is already HTML-encoded. To undo the coding use  ! as a prefix.

{session:*} – Contents of the names session parameter.

{request:*} – Contents of the HTTP-request-parameter (GET and POST).

Examples:

{text:my-account} - gets replaced by "Mein Account"  in German, by "My Account" in English.

{request:id} - Content of the request parameter ID.
            

Predefined variables

Back to top

The following variables are available in every template:

  • sys:skin – Name of the current skin (e.g. d or default)
  • sys:skin-path – Path to the current skin
  • sys:skin-files-path – Path to the files (especially images) of the skin
  • sys:version – Manja version
  • sys:revision – Manja revision
  • sys:branch – GIT branch, from which the version was created (mostly “master”)
  • sys:builddate – Date when the version was created
  • sys:cutag0 – Cache usage tag (matches Manja revision or current timestamp)
  • sys:cutag – Cache usage tag for usage in URL search parameter (e.g. ?2318345)
  • sys:session-is-valid – true, if a valid server session exists (in other words: the user is logged in successfully)
  • sys:session-id
  • sys:session-cookie-name
  • sys:session-data – Associative array of user session data
  • sys:is-guest-session – true, if session is a guest session, which means there is an active session, but instead of a real user a system generated guest account is logged in (s. config.ini [guest-mode])
  • sys:csrf-token – CSRF-token
  • sys:multi-locale – true, if multi language is activated in configuration
  • sys:locales – Array of all configurable countries, keys are locale-codes (eg. “en_EN”), contents each configured name (e.g. “english”)
  • sys:locale-keys – Array of the keys of all available locales (e.g. de_DE, en_GB), see sys:locales
  • sys:locale – user chosen language-/country-setting (e.g. “en_EN”)
  • sys:language – user chosen language (e.g. “en”)
  • sys:module-spec – current module with section (e.g. “administration.metadata”)
  • sys:module-module – current module without section (e.g. “administration”)
  • sys:module-section – current module-section (e.g. “metadata”)
  • sys:module-action – current module-action (e.g. “page”)
  • sys:module-url – URL to the current module
  • sys:upload-limit – upload limit of the server in bytes
  • sys:web-root – URL to web root directory of the Manja installation (possibly an absolute URL, e.g. https://example.manjadigital.de/my-manja)
  • sys:web-root-path – Path to web root directory of the Manja installation (path of the URL, e.g. /my-manja)
  • sys:custom-root – Name of the custom directory (e.g. “custom” or “custom-dev”)
  • sys:cookie-path – Path for setting cookies
  • sys:uwn – URL wrapper name, mostly “manja”
  • sys:timezone – automatically detected or user chosen time zone
  • template:wrapped-content – contains the complete output of the template (*)
  • sys:features – Associative array of the extra features provided by the Manja server (e.g. ssl, versioning, advanced_compare)
  • sys:ui-extensions – Associative array of active UI add-ons (e.g. ui_expiry, ui_tos, ui_projects)
  • sys:registration-url – URL to register form, if activated in configuration (see config.ini [registration])
  • sys:enabled-privacy-notice – true, if privacy notice is activated in configuration (see config.ini [app] enable_privacy_notice)

(*) To create a complete HTML page a chain of templates is processed. For example the templates “login.html” and “page.html”. At first “login.html” gets processed and its full output is handed over to “page.html” in the variable {template:wrapped-content}. This minimises repetion, the page layout has only to be defined once in “page.html”.

If a user account is successfully logged into the server (and so a valid session exists):

  • user:user_id
  • user:username
  • user:roles – Array of user roles
  • user:oblivious – true, if user session data is not stored (see also sys:is-guest-session)

In the templates “page.html” and “print.html” additionally the following variables are available:

  • sys:page-css-urls – Array of URLs to all required CSS files
  • sys:page-scripts – Array of URLs to all required javascript files
  • sys:page-scripts-texts – Associative array of all text translations used in JavaScript files sys:page-scripts

If web UI debugging is activated (s. config.ini [app] enable_web_ui_debugging), additionally the following variables are available:

  • sys:enabled-web-ui-debugging-features – Array of activated debugging features (e.g. no-minify, avoid-caching-js-and-css)
  • sys:web-ui-debugging-features – Array of all available debugging features (e.g. no-minify, avoid-caching-js-and-css, clear-all-caches-on-server, throw-now)

Output conversion

Back to top

Contents of variables can get converted or encoded for the output in each particular context. For example special characters like < and > should get converted for the output as HTML to their HTML entities. Even special characters in URL parameters require specific encoding.

By using a conversion code ahead of the variable name a conversion is requested. Even multiple conversion codes can be used after each other, they get processed from left to right.

Conversion codes and their functions:

  • & – HTML/XML special characters

(& to &amp;< to &lt;> to &gt;" to &quot;)

  • + – like &, but converts additionally plain text line breaks (\n) to HTML line breaks (<br/>\n)
  • ! – Inversion HTML/XML special characters (&amp; to &, aso.)
  • \ – JavaScript special characters (\ to \\" to \"' to \', line break to \n)
  • % – Encoding for URL parameter (RFC 1738)
  • - – Encoding for URL parameter (RFC 3986)
  • # – Conversion to integer (turns to 0, if content can not be converted to figure)
  • . – Floating point number in localised version (e.g. 1.234 in de_DE: “1,234”, in en_US: “1.234”)
  • ? – Debugging output of the content
  • ~ – Debugging output of the content (direct output, in contrast to ?)
  • : – JSON-encoding
  • ; – Conversion to JavaScript bool (returns true or false)

Examples:

{some-var}
No conversion
  
{&some-var}
Contents get HTML encoded

<a class="foo" href="foo.php?var={%&var}">foo</a>
Content gets firstly URL encoded, then HTML encoded

{?complex-data}
Outputs contents structured with details (like data types)

<script>
var hello = "{!\text:hello}";
var complex_data = {:complex-data};
</script>
            

Access to array elements

Back to top

By using square brackets single array elements can be accessed. This works in associative and indexed arrays.

The key can be a string, an integer or a variable.

Examples:

{sys:locales[de_DE]}

{some-list[0]}

{some-list[{some-number}]}

{some-array[{some-key}][0]} 
Since Manja 4.1 also nesting is possible.
            

Comments

Back to top

Comment blocks start with {/* and end with */}.

The contents of comment blocks are ignored and never outputted.

Example:

{/*
  This is a comment.
*/}
            

Non interpreted sections

Back to top

Non interpreted sections start with {{ and end with }}.

Within these sections curly brackets are not interpreted as template directives. This is for instance helpful to include JavaScript code, that includes curly brackets itself.

Example:

<script type="text/javascript">
//{{
  function foo() {
    alert("Hello world!");
  }
//}}
</script>

<div class="x">
{{
  if( foo ) {
    code();
  } else {
    json = {
      "key1": { one: "foo", "two": bar },
      "key2": [ 1, 2, 3 ]
    };
  }
}}
</div>

            

Conditional statements (if, else)

Back to top

Conditional statements start with {if, followed by a condition, followed by a block, that is only processed, when the condition is true, followed by a final curly bracket }.

Optional an else-block can be added, which is only processed, when the condition is not true.

Note: Between else and the curly brackets no blank spaces or line breaks are allowed.
Wrong: } else {Correct: }else{.

Examples:

{if {sys:session-is-valid}
  Hello {&user:username}!
}

{if {sys:session-is-valid}
  Hello {&user:username}!
}else{
  Please login first.
}
            

Expressions

Back to top

To compare and evaluate the values of variables simple expressions are available. They return Booleans (true, false) and are intended mainly for the usage in {if-blocks.

Expressions start with {$(, followed by an expression, followed by a closing )}.

An expression consists of operands and operators. An operand can be text, a figure, a variable or another expression. By using simple brackets expressions can be nested arbitrarily.

The available operators are:

  • == equal
  • != unequal
  • <= less or equal
  • >= greater or equal
  • < less
  • > greater
  • && Boolean AND
  • || Boolean OR
  • ! Boolean negation

Examples:

{if {$({sys:locale}==de_DE)}
  the locale de_DE is in use
}

{if {$({selected-user}=={user:user_id})}
  the selected user is the current user
}

{loop {sys:locales}
  <a href="{sys:module-url}?locale={loop:key}" class="flag{if{$({loop:key}=={sys:locale})} active}">
    <img src="{sys:skin-files-path}/flag_{loop:key}.png"
         width="20" height="12" alt="{loop:value}" title="{loop:value}" />
  </a>
}

{if {$( !{some-var} )}
  Value of the variable "some-var" is empty, 0 or false.
}

{if {$( {A} && !{B} )}
  A is true, B is false.
}

{if {$( {user:roles[manager]} && {user:roles[administrator]} )}
  User ist both manager and administrator.
}

{if {$( {user:roles[user]} && ( {user:roles[manager]} || {user:roles[administrator]} ) )}
  User is regular user as well as manager or administrator (or both: manager and administrator).
}
            

Loops (loop)

Back to top

By using the loop construct all elements of an array can be run through. Loops start with {loop, followed by the array variable, followed by a block, that repeats for each array element, followed by a closing curly bracket }.

Example:

<ul>
  {loop {sys:locales}
    <li>key={loop:key}, value={loop:value}</li>
  }
</ul>
            

Within the loop additionally the following variables are available:

  • loop:key – Key of the current array element (numeric for indexed arrays, text for associative arrays)
  • loop:value – Value of the current array element (can contain arbitrary data and types)
  • loop:odd – Value 1 in odd loop runs, otherwise 0
  • loop:even – Value 1 in even loop runs, otherwise 0
  • loop:first – Value 1 in first loop run, otherwise 0
  • loop:last – Value 1 in last loop run, otherwise 0

If the value of the current array element is an associative array itself, its contents are available within the loop block by using simple variables.

Example:

<table>
 <tr>
  <th>User ID</th>
  <th>Username</th>
  <th>First Name</th>
  <th>Last Name</th>
 </tr>
 {loop {userlist}
  <tr>
   <td>{&loop:key}</td>
   <td>{&username} (oder auch: {&loop:value[username]})</td>
   <td>{&first-name}</td>
   <td>{&last-name}</td>
  </tr>
 }
</table>
            

Aliases

Back to top

Aliases start with {alias, followed by the specific alias-name, followed by the term including the actual alias data, followed by a closing curly bracket }.

Within the alias block all data defined for the alias name will be available.

Example:

{/*
  Notional, "persons" contains following data:
  {
    "person-x": {
      "first-name": "First",
      "last-name: "Last",
      "phone": "12345"
    },
    "person-y": ...
  }
*/}

{alias x {persons[person-x]}
  Name: {&x[first-name]} {&x[last-name]},
  Phone: {&x[phone]}
}
            

Special case: anonymous aliases

If no alias name is given before the expression and the expression returns an associative array as data, its keys are available as separate variables within the alias block.

Example:

{alias {persons[person-x]}
  Name: {&first-name} {&last-name},
  Phone: {&phone}
}
            

Literals

Back to top

Literals start with {literal:, followed by arbitrary text as value, followed by }.

A literal expression will directly evaluate to its value. The literal expression can be used where an expression is required but a value should be used directly.

E.g. for using a simple value instead of an expression in an alias.

The empty literal {literal:} is valid and evaluates to an empty string.

Example:

{/*
  You want to call a template "my-thumbnail.html" with a parameter "size":
*/}

{alias size {literal:120}
    {include:my-thumbnail}
}

{alias size {literal:240}
    {include:my-thumbnail}
}
            

PHP code blocks

Back to top

Wherever the mechanisms of the provided template syntax will not be sufficient, the requests can be written in classic PHP code. To make your code as compatible to upgrades as possible, this should always be the last method of choice.

Syntax: {<? starts a PHP code block and ?>} ends it.

Alternatively the PHP code block starts with {<?=, which implies an echo already.

Within these blocks the previously defined (and for the specific HTML template intended) variables will be available through the PHP array $d.

Examples:

{/*
  Each output will be the variable some-id as 8-digit number with leading zeros.
*/}

{<? echo sprintf('%08d',$d['some-id']); ?>}

{<?=sprintf('%08d',$d['some-id'])?>}
            

Integrate further templates (include and fast-include)

Back to top

By using the include directive other templates can be integrated. The directive starts with {include:, followed by the name of the template (without .html), followed by a closing curly bracket }.

The directives of the integrated template will be executed, the final HTML-fragment outputted. Within the integrated template the same variables like in the current template are available.

Additionally there is the so called “fast-include” directive, which can be used, when a template is integrated multiple times (e.g. for each line in a data table). “Fast-include”-directives ignore (unlike the normal include) all add-on-specific hooks, which can improve the execution time significantly.

The add-on-specific hooks react exclusively on the templates from the default distribution (like e.g. “page-menu.html”, “page-header.html”, u.Ä.). Own templates can be integrated almost always with fast-include.

Examples:

{include:some-fragment}

{fast-include:some-fragment}

{loop {userlist}
  {fast-include:user-fragment}
}
            

Integration of JavaScript files

Back to top

In a template the integration of JavaScript-files may be requested. The files are added to HTML by use of <script> tags.

1. Integrate single file: {use-js-file:path-to-filename}

path-to-filename is the path to the file, relative to the Manja installation in “web/public”.

2. Integrate optimized set: {use-js-set:set-name}

set-name: Name of already predefined set.

Amongst others, the following sets are predefined in Manja:

  • mjs.base – contains the minimum of required external libraries,
  • mjs.page – additional external libraries and Manja basic libraries, e.g. js/mj.widget.js, js/mj.media-result-view-widget.js,
  • mjs.media – everything required for the media section,
  • mjs.mmgmt – everything required for the manager/editor functions within the media section,
  • mjs.madmin – everything required for adminstrator functions within the media section,
  • mjs.admin – everything requred for the administrator section,
  • mjs.acctmgmt – common code for account management in the areas “Administration” and “My Account”,
  • ckeditor – CKEditor (3rdparty/ckeditor/ckeditor.js),
  • code-editor – js/mj.code-editor-widget.js and dependencies (multiple from 3rdparty/CodeMirror/)

3. Create and integrate optimized set: {use-js-set:set-name[:dep1,dep2,...]:file1[,file2,..]}

  • set-name: Name of the new set,
  • dep..:  path or name of a file to integrate,
  • file..: path or name of a file to integrate optimized.

Important for entries in dep.. and file..:

A) Path:

  • either full path to file (relative to the path “web/public” in the Manja installation),
  • or without path at all – the path “web/public/js/” is presumed.

B) Suffix:

  • either with suffix: the stated file is integrated,
  • or without suffix: if exists the file name.min.js instead of name.js is integrated.

Files in dep.. are always integrated directly and separately.

Files in file.. get optimized: the files of a set will be merged into a single file.

For files in file.. the prefix + can be added to enable further preprocessing: Placeholders for localized text (as in HTML templates) will be processed and replaced in all marked files.

Examples:

{use-js-file:custom/files/my-script.js}

{use-js-set:code-editor}

{use-js-set: mjs.my-custom-set:
  custom/files/3rdparty/external-lib.js,
  custom/files/3rdparty/another-external-lib.js
  :
  custom/files/my-lib,
  custom/files/my-other-lib.js
}

{use-js-set: mjs.my-custom-set:
  custom/files/my-lib,
  custom/files/my-other-lib.js
}
            

Integration of CSS/Less files {use-styles:name}

Back to top

In a template the integration of CSS/Less-files may be requested. The files are added to HTML by use of <style> tags.

name is the name of the CSS/Less-file.

If the name is listed with suffix .css or full path (relative to the path “web/public” in the Manja installation) the file is integrated directly.

If neither the suffix nor the path are specified, the following files are checked – matching the name and the respective skin:

1. in skin: public/skin/<skin-name>/f/<name>.less
2. in skiin: public/skin/<skin-name>/f/<name>.<locale>.less
3. in add-ons: ext/<addon-name>/skin/d/f/<name>.less
4. in add-ons: ext/<addon-name>/skin/d/f/<name>.<language>.less
5. in add-onss: ext/<addon-name>/skin/d/f/<name>.<locale>.less
6. in custom-directory: public/custom/<name>.less
7. in custom-directory: public/custom/<name>.<language>.less
8. in custom-directory: public/custom/<name>.<locale>.less

The identified .less-files are compiled into .css-files, minified and merged into a few optimised CSS files, which are finally added to HTML by use of <style>-tags.

Examples:

{use-styles:my-styles}
If they exist custom/my-styles.less, custom/my-styles.de_DE.less etc. 
are compiled to .css and integrated.

{use-styles:custom/my-styles.css}
only custom/my-styles.css is used.
            

JavaScript/HTML/Template-Mix Best Practices

Back to top

Comprehensive JavaScript code should be outsourced to your own files and incorporated by {use-js-set:*} or {use-js-file:path-to-filename}.

For the best possible representation of the mix of HTML, JavaScript and Manja template syntax in editors and IDEs, we recommend the following:

1. Enclose inline JavaScript code in templates as “uninterpreted area” by {{ and }} and convert it into valid JavaScript syntax using a one-line JavaScript comment:

<script>
//{{
  alert("Hello World");
//}}
</script>
            

2. Provide template data for JavaScript code in a special script block <script type="text/x-mj-tmpl-javascript">.

Blocks with type text/x-mj-tmpl-javascript are output as simple JavaScript blocks in the generated HTML.

Advantage: Editors and IDEs ignore the content (they do not try to interpret it as JavaScript).

<script type="text/x-mj-tmpl-javascript">
var some_id = {#some-id};
var some_text = "{\some-text}";
var some_object = {:some-object};
</script>

<script>
//{{
  console.log({some_id,some_text,some_object});
//}}
</script>