Load elFinder with requirejs from Mako template

PySite‘s UI needs several JavaScript libraries which I would like to load asynchronously. Requirejs is a nice tool to achieve this.

Some libraries are used by all pages, like jQuery, and others are used only by certain pages, like elFinder is needed only on the page of the FileManager.

Thanks to requirejs’s author’s foresight, requirejs can not only be initialised by a method call, but also by defining a variable require before the actual requirejs script is loaded. This gives us a very elegant way to initialise requirejs with general settings in Mako’s master template, and define only addional settings in child templates.

The master template defines two blocks: require_config where the configuration is set up, and scripts which loads the actual requirejs script.

<script>
<%block name="require_config">
        var require = {
                // ...
                // general options here
                // ...
        };
</%block>
</script>
<%block name="scripts">
        <script src="${request.static_url('pysite:static/app/libs/requirejs/require.js')}"></script>
</%block>

The child template then overrides the config block and just adds options that are specific for this page.

<%block name="require_config">
        // Call parent to init general options
        ${parent.require_config()}
        // Set specific options for this page, e.g.
        // require.paths['elfinder'] = 'libs/elfinder/js';
</%block>

elFinder is not prepared to be loaded by a module loader, but requirejs can handle such old-style modules with grace. With its shim option we can specify that elFinder depends on jQuery UI, and that a global instance elFinder must be exported, because the localized messages need it to initialize.

<%block name="require_config">
        ${parent.require_config()}
        require.paths['elfinder'] = 'libs/elfinder/js';
        require.shim['elfinder/elfinder.min'] = {
                  deps: ['ui/jquery-ui']
                , exports: 'elFinder' // The i18n files need this
        };
        // All i18n files depend on the elFinder instance from the main script
        require.shim['elfinder/i18n/elfinder.de'] = ['elfinder/elfinder.min'];
        require.shim['elfinder/i18n/elfinder.en'] = ['elfinder/elfinder.min'];
</%block>

Now we can load and initialize elFinder. The domReady plugin of requirejs ensures the DOM node we attach elFinder to is present. Then we need jQuery and load the elFinder modules.

require(['requirejs/domReady!', 'jquery', 'elfinder/elfinder.min', 'elfinder/i18n/elfinder.de', 'elfinder/i18n/elfinder.en'],
function(doc,                   $)
{
        var elf = $('#elfinder').elfinder({
                lang: 'de',
                url : '${request.resource_url(request.context, '@@xhr_filemgr')}'
        }).elfinder('instance');
});

You can review the complete code here:

Master template: https://github.com/dmdm/PySite/blob/master/pysite/templates/_layouts/default.mako

Child template for file manager: https://github.com/dmdm/PySite/blob/master/pysite/filemgr/templates/filemgr.mako