JavaScript Modules

Table of Contents

Introduction

Quotation bundle uses JavaScript modules to enhance the user interface in various steps of the quotation process. These include widgets that are autoloaded for every page or widgets that loaded only when needed (such as form elements). The widget loading system is based on Require.js and uses a data attribute to check the name of a widget.

By default, widgets are loaded from the quotation bundle but it is also possible to define your widgets. For this you need to define the package in the require.js config.

Packages and naming

Widgets are require.js modules that return a Javascript constructor. The widget system is designed to be used with a Marionette so the return value is usually a Marionette / Backbone view definition. If the module is found, an instance is then created and given the the element and other options as parameters. The widgets are loaded from different packages where packages refer to require.js packages:

requirejs.config({
    ...
    packages: [
        { name: 'klaro_quotation', location: './bundles/klaroquotation/js', main: 'app' },
        { name: 'somepackage', location: './bundles/package/js' }
    ]
});

The default package is klaro_quotation which means scripts are searched in the quotation bundle javascript package. If the package is omitted, then klaro_quotation is assumed as the package. The actual name of the javascript file is [widget_name].module.js.

For example, to load a widget named confirm, the directory defined in the default package klaro_quotation is searched for the script name confirm.module.js. To load a widget name somepackage/confirm, the directory of the package somepackage is searched for the script name confirm.module.js.

Creating a widget

To put it simply, widgets are require.js modules that return a Backbone view. For example, the confirm module in the previous example could be:

// confirm.module.js
define(['backbone', 'marionette'], function(Backbone, Marionette) {
    'use strict';

    return Backbone.Marionette.ItemView.extend({
        events : {
            'click' : 'handleClick'
        },

        handleClick: function(e) {
            e.preventDefault();

            if(confirm("Are you sure?")) {
                window.location.replace(this.$el.attr('href'));
            }
        }
    });
});

Starting the widget

The ways to load a module are described below.

Loading a widget on a specific element

Javascript modules can be attached to any HTML element by using the data attribute "app" (data-app="...") and they will be automatically loaded. For example the confirm widget can added to a link:

<a href="..." data-app="confirm">Do something dangerous</a>

This will load the script and instantiate the returned definition. The widget will receive as parameter the element any other data attributes attached to it:

<a href="..." data-app="confirm" data-confirm-text="Are you sure?">Do something dangerous</a>

This will make the extra data attribute available in the view options:

define(['backbone', 'marionette'], function(Backbone, Marionette) {
    'use strict';

    return Backbone.Marionette.ItemView.extend({
        confirmText : null,

        initialize: function(options) {
            this.confirmText = options.confirmText || 'Are you sure?';
        },

        // ...
    });
});

Autoloading widgets

To load modules to the page scope, use the following Twig command to do so:

{{ klaro_quotation_load_modules([
    { module : 'bootstrap', 'el' : 'body' },
    { module : 'notification' },
    { module : 'somepackage/toolbarupdate' },
]) }}

The module key tells the name of the widget (possibly preceded by the package). The whole array is then passed to the widget itself, so you can define other parameters such as an element to which the widget will attach itself.

Form widgets

Form widgets are like the other widgets but they are speficically meant to be attached to phase form inputs. They are loaded by the master form widget which looks for a data attribute data-form-input="[widget]". This allows the form to unload and load form widgets as fields are hidden and shown.

The naming of the form widgets follows the convention of phase.[widget_name] (loaded from quotation bundle). To load a custom widget, use data-form-input="somepackage/phase.[widget_name]". This will look for a script named phase.[widget_name].module.js under the somepackage directory and load it. As with other widgets, the form widget receives the element to which the data attribute is attached to as a parameter.