Introduction

To make page loading faster we use LAB, which allows us to load all scripts asynchronously and evaluate them in specific order, without making the browser wait for all scripts to be loaded before allowing users to interact with the page. Along with this, we have a simple dependency management in place. More dependencies (CSS, remote javascript and inline javascript) can be easily added into Django templates, along with some context for javascript files that are meant to work inside Django templates.

Dependencies

General Dependencies

General dependencies (e.g. Purr plugin, jqGrid, etc.) are written inside soc/content/js/melange.dependency.js file. It is basically a collection of arrays which list either

  • other dependency arrays (for example s.jqgrid, which includes all javascript files that need to be loaded for lists to work). This means that all dependency arrays can be nested. The unpack() function will take care of linearize the nested arrays.

  • null, which basically says to the downloader to wait for the former script to be evaluated before evaluating the next. For example, you can't load jqGrid if jQuery is not downloaded and evaluated.

  • a string, which contains the full path of a script to be downloaded.

Template Dependencies

All template specific JS and CSS dependencies should be listed into an array inside the dependencies block. The base template provides specific facilities to include CSS files and to give context to Javascript files related to Django templates. You can also include inline scripts that need to be ran after some other script is loaded. So, in each template you can create an array like this:

{% block dependencies %}
[
  dep.melange.menu,
  null,
  css("soc/content/css/search_page.css"),
  tc(
    "soc/content/js/templates/modules/gsoc/program/list/allocation-100413.js",
    {"slots_number": 25}
  ),
  function () {
    do_something();
  } 
]
{% endblock %}

The dep object

In the dep object you can find all the dependencies that are included in the melange.dependency script. You can notice that all the arrays are now found in this dep object instead of the s object, which is internal in the melange.dependency script. This has been done to make it more intuitive to use when writing Django templates. You can also notice that dep.melange.menu then refers to s.melange.menu in the melange.dependency script, which is an array of arrays in itself. This means that you can still nest arrays of dependencies in the Django templates.

null

As for the melange.dependency script, if you put a null as an element of the array, the following scripts will wait to evaluate before the previous ones are evaluated.

css(css_path)

The css(css_path) method is actually a shortcut for melange.dependency.cssFile(css_path). This has been renamed for conveniency. This method will create a new <link> tag in the HTML file, so the browser will download the CSS file and evaluate it in the page. This facility should be used when the absence of the CSS won't compromise the overall rendering of the page, for example when we want to include CSS files that are needed for a widget that is only displayed once something in the page happens or after a Javascript file is evaluated. The reason for this is pretty obvious: dynamic linking a CSS file when the page is already displayed to the user will make the page look suddenly different after some time, disorienting the user. So, basically, global CSS files or CSS styles that are immediately needed in the page should still be linked using a <link> tag in the stylesheet Django block on the top of the page.

tc(script_path, context)

The tc(script_path, context) method is actually a shortcut for melange.dependency.templateWithContext(script_path, context). This has been renamed for conveniency. This method will take care of downloading the script related to the template, evaluate it and then it will inject the context. This was formerly done using the melangeContext attribute of the script tag. So now there is no need to convert the JSON object to a string for the attribute, but you can just put the plain JSON file inside the context parameter of this function calling. All the tc() calls are synchronous. This means that it automatically evaluates itself as [null, tc(), null]. The reason to do this is because there is no way for JS scripts to know about their context in the page (e.g. pass some parameters from the Django template to the JS scope), so we need a small hack to make them so and attach them a context. When a JS template is loaded, it will register itself in a global “template queue” hosted in the main melange.js file, in the melange.templates object. The context is then attached to the last template that has been registered. So we can't allow another template to be attached before the former one has been coupled with a context.

The JS code for each Django template should be put under app/soc/content/js/templates and then following the same path the Django template has. To receive the context in the JS code, then, your code should be inside the following function:

melange.templates.inherit(
  function (_self, context) {
    // Your code here
    // _self contains a reference to this function
    // context contains the context added in your tc() call
  }
);

function()

You can also attach a custom inline function, which is a sort of callback that is called after the previous scripts are loaded and evaluated in the browser. This is discouraged unless really necessary, though: all the logic should be put outside the Django template in the separate JS template file.