Home

JavaScript Module Engine

The JS Engine is a framework used by Gambio GX3 e-commerce platform for handling JavaScript operations easily and consistently. It features useful libraries, extensions and widgets which can be reused and will boost up the UI development.

Main concept of the engine is that JavaScript code is divided into small modules that are bound directly in the HTML markup with the use of "data-" attributes. The core principles are that every module should be as simple as possible to use and it should always serve a single purpose within the application context. That said, modules are divided into four collections depending their purpose:

  • Widgets
  • Extensions
  • Controllers
  • Compatibility

These collections are used only for organising the modules depending their general type and they do not have any other functional difference.

Since JS Engine v1.2 namespace support was added so that modules can used from every section of the application (admin, frontend, module development). You will just have to define you own namespace as shown in the examples section below and the engine will load the modules from your own paths. Of course, you can also use one of the pre-made namespaces that contain useful modules.

The engine is already loaded and used in every page of the shop system so you can start using it immediately. The following example show how you can bind a widget to a specific HTML element:

<table data-gx-widget="datatable"> 
  <thead>
    <tr>
      <th>Column 1</th>
      <th>Column 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>Cell 1</td>
        <td>Cell 2</td>
    </tr>
  </tbody>
</table>

When the page is loaded the engine will load the "datatable" widget from the "gx" namespace which will convert the table into a jQuery DataTable instance without writing a single line of JS code! Of course real world situations are more complex than this example. The following sections will showcase the capabilities of JS Engine and how it can be used in order to organise and reuse existing code in a more efficient manner.


Defining Namespaces

Namespaces are an easy way of telling the engine where your modules are located in the project file structure. As with module binding the namespace definitions need to be included in the rendered HTML markup. The engine will then parse them and register them so that it can further find the required modules for the page.

<body data-my_custom_name-namespace="admin/javascript/my_custom_folder">...</body>
<!-- OR -->
<div data-my_custom_name-namespace="admin/javascript/my_custom_folder">...</div>
<!-- OR -->
<span data-my_custom_name-namespace="admin/javascript/my_custom_folder">...</span>

The "data-{my_custom-name}-namespace="{relative-path}" attribute will be parsed and a new namespace will be created with the {my_custom-name} string value as reference name and the {relative-path} as the relative-to-root location of the module files.

This attribute can be added in any place of the HTML markup that is rendered in the browser but it must
be done before the document object is ready, otherwise the namespace will not be registered.

Notice: Namespace names must be unique in the application, that means that there shouldn't be any other namespace with the same name in the same page. The engine will throw an error if it detects this situation.

Hint: It is always better to use a small string as the namespace name because it will be used in multiple places.


Collections

As already mentioned the engine modules are divided into different collections depending their general purpose. Each one of these collections are included automatically in a new namespace even if no modules where found in the page.

Widgets

Widgets define JavaScript UI controls that can be easily resused in order to provide advanced functionality that will enhance the user experience. The engine wraps the functionality of major JavaScript projects and plugins such as the jQuery UI library, the DataTables plugin and many more.

Example:

<!-- The following element will become a datetimepicker. -->
<input type="text" data-gx-widget="datetimepicker" />


Extensions

Extensions are engine modules that extend existing widgets with extra functionality that is repeated multiple times within the application. For example the addition of the data-gx-extension="link" will enable the link functionality into any element.

Example:

<label data-gx-extension="link" data-link-url="http://gambio.de">Navigate To Official Website</label>


Controllers

Implementing new pages often require specific functionality and methods in order to achieve the final result and that is where custom controllers come in to the scene. You can define your own controller module which should only contain page-specific code.

Example:

<!-- Engine will automatically include the my_controller_name.js file -->
<div class="container" data-gx-controller="my_controller_name">...</div>


Compatibility

Compatibility modules were introduced during the Admin "Facelift" project and they are mixed-purpose modules that are used only for the implementation of the compatibility mode. The reason of their separation is that they are only necessary for the transformation of the old pages and not within the new theme context.

Example:

<!-- Engine will automatically include the compatibility_module.js file -->
<div class="container" data-gx-compatibility="compatibility_module">...</div>


Modules

Now that you know how to include a module in a page let's get into creating one. Modules need to be easy to maintain so if you realise that a module is becoming too complex to handle it is time to split it into multiple modules or move part of its functionality into custom libraries (see the "Libraries" section below).

Module Definition Example: Place this file in the "admin/javascript/mynamespace/controllers/controller_name.js" location. You will also need to provide a minified version in the same directory with the ".min.js" extension.

mynamespace.controller.module('controller_name', [], function(data) { 
  'use strict'; 

  var $this = $(this),
    module = {}; 

  module.init = function(done) {
    alert($this.text()); // Get the text content of the bound element. 
    done(); // Complete the module execution.
  };

  return module;
});

This example shows the simplest possible module definition. You will only need to replace the "mynamespace" with your own namespace name and the module is ready to serve a specific page. In order to use this module you will need the following markup.

<div data-mynamespace-namespace="admin/javascript/mynamespace"> 
    <span data-mynamespace-controller="controller_name">Hello World!<span>
</div>

Once the page is loaded the "module.init" function will be executed and it will alert the content of the span element (Hello World!).


Libraries

The engine libraries provide some other useful function utilities that can save you from spending a lot of time writing and testing your code. Current libraries include UI modal dialog handling, advanced DataTable initialization and many more. By convention the library objects should be defined in the jse.libs object and must be placed in a "libs" directory of the namespace folder.

Example:

jse.libs.mylib = jse.libs.mylib || {}; 

(function(exports) {

    'use strict'; 

     var _privateMethod = function() {
        // ...
     };

     exports.publicMethod = function() {
        // ... 
     };

})(jse.libs.mylib);

Core libraries that reside in the JSEngine/build/libs directory require only the filename without the extension in order to be loaded. Otherwise you will have to provide a full URL to the file. With this mechanism modules can also load external scripts that have nothing to do with the JS Engine.

mynamespace.extensions.module(

'my_module',

[
    'datatable', // core library (only the name is required)
    jse.core.config.get('shopUrl') + '/admin/javascript/mynamespace/libs/my_lib' // url without the extension
], 

function(data) {

    var $this = $(this),
        module = {}; 

    module.init = function(done) {
        jse.libs.datatable.create($('#a-random-table'), {}); 
        jse.libs.publicMethod();
        done();
    }; 

    return module; 

});


Examples

Below are some examples that demonstrate different scenarios of the engine. More examples will be added soon.

Get Parameters From HTML

HTML

<button data-mynamespace-widget="mywidget" data-mywidget-text="Hello World!"></button>

Module

mynamespace.widgets.module('mywidget', [], function(data) {

    var $this = $(this),
        module = {}; 

    module.init = function(done) {
        $this.on('click', function() {
            alert(data.text); // data.text value comes from the HTML markup
        });
        done(); 
    };

    return module;
});


Engine Loading (Optional)

The engine is already loaded within the shop but if you need to include it in an external page you have to specify an initial configuration object and also include the required files.

Example:

<!-- External Engine Dependencies -->
<script src="http://shop.de/admin/includes/ckeditor/ckeditor.js"></script>

<!-- gx-admin.css includes boilerplate and widget styling for admin. -->
<link href="http://shop.de/admin/html/assets/styles/vendor.min.css" rel="stylesheet" />
<link href="http://shop.de/admin/html/assets/styles/gx-admin.min.css" rel="stylesheet" />

<!-- Include Engine Vendor Files -->
<link href="http://shop.de/JSEngine/build/vendor.min.css" rel="stylesheet" />
<script src="http://shop.de/JSEngine/build/vendor.min.js"></script>

<!-- EngineConfiguration Object -->
<script type="text/javascript">
    window.JSEngineConfiguration = {
        // REQUIRED VALUES
        environment  : 'production', // or 'development'
        shopUrl         : 'http://shop.de',

        // OPTIONAL VALUES
        engineUrl     : 'http://shop.de/JSEngine',
        translations : {},
        languageCode : 'de',
        pageToken     : '69f38ab02489ac2d8645fb3f5d1fa957'
    };
</script>

<!-- Include the engine, other modules will be loaded dynamically via RequireJS. -->
<script src="http://shop.de/JSEngine/build/jse.min.js"></script>


About This Document

This documentation contains reference and examples for further information about available extensions and widgets and the core engine libraries. It is highly preferable that you use the engine features in your implementations because they are tested and will keep your pages up to date with the latest features. Before using any of the engine modules make sure that you read their documentation for further information and usage examples.

Notice: Every section of the engine except from the the core libraries need to use underscore separators for the module names because the engine supports the inclusion of custom variables passed through the HTML to the modules in the following format data-my_controller_name-title="Some Title", and the my_controller_name cannot be neither CamelCase "MyControllerName" nor dash-separated "my-controller-name". So try to keep the names as short as possible.

The module reference is relatively new and might not be complete. It will be improved in time providing new information and examples. Check out the browser's console for deprecation warnings so that you know when a specific module or method is going to be removed. If something is not clear for you from this
document try to look directly in the code of the modules.

It will be helpful to look in existing namespaces and modules in order to get an idea of how the files are structured. Currently a complete namespace exists in the admin directory in "admin/javascript/engine" path. There you will find every kind of possible module.


About The Engine

Copyright: Gambio GmbH © 2016

License: GPLv2

Current Version: v1.3

Website: www.gambio.de