Chapter 43. Module Code Examples

43.1. Declare a Module

Module declaration requires integrating the Highlight.js library. This example is part of the examples found in amd-js.war.
Highlight.js is a jQuery plugin. jQuery plugins are the best examples as they are native portal modules. They follow the self-invoking pattern that accepts the jquery dependency as $.

(function($) {
  ...
}(jQuery)

Note

For an overview of the Highlight.js source code, see https://github.com/isagalaev/highlight.js/blob/master/src/highlight.js.
The highlight module is integrated using the XML declaration:

<module>
  <name>highlight</name>
  <script>
    <path>/highlight/highlight.js</path>
  </script>
  <depends>
    <module>jquery</module>
    <as>jQuery</as>
  </depends>
</module>
  • The module highlightuses the /highlight/highlight.js source code bundled in the war file.
  • The depends tag creates a dependency on the jquery module. The dependency is aliased as $ using the as tag to match the Highlight.js self-executing function argument $ .

Note

The jquery module provides jQuery 1.7.1 . The jquery plug-ins are not a part of the portal and do not need to be declared.

43.2. Declare an AMD Module

Asynchronous module declaration is explained in the RequireJS documentation available at http://requirejs.org/docs/api.html#define.
The pattern for AMD modules is as follows:

define("module", ["dependency1",...,"dependencyN"], function(dep1,...,depN) {
});
The portal allows independent usage of modules such as AMD, where some parts are overridden by the XML declaration:
  • The "module" name is ignored and replaced by the declared module name.
  • The module dependencies ranging from "dependency1" to "dependencyN" are declared with the same name in XML (use the as tag to override the dependency name).
After declaring the dependencies from dependency1 to dependencyN in XML, the module definition is declared as follows:

<module>
  <name>MyModule</name>
  ...
  <depends>
    <module>dependency1</module>
  </depends>
  ...
  <depends>
    <module>dependencyN</module>
  </depends>
</module>

43.3. Use jQuery Module

The portal provides the jQuery library as a jquery module. The module configuration is found in eXoResources.war file.
  • To reuse the jQuery version you need to declare a dependency over it.
    
    <portlet>
      <name>RequireJSPortlet</name>
      <module>
        <depends>
          <module>jquery</module>
        </depends>
    </portlet>
    
  • The default jquery module alias is $ so while using it, it should be named $ in the self-executing function:
    
    (function($) {
      ...
    })($);
    
  • The XML <as> tag is required if your library uses a different name such as jQuery:
    
    <portlet>
      <name>RequireJSPortlet</name>
      <module>
        <depends>
          <module>jquery</module>
          <as>jQuery</as>
        </depends>
    </portlet>
    
  • The self-executing function for jQuery is as follows:
    
    (function($) {
      ...
    }(jQuery);
    

43.4. Use a Custom jQuery Version

The portal allows integration of other version of jQuery. Products built to run on the Red Hat JBoss Portal may depend on third-party JavaScript frameworks, which in turn depend on other versions of jQuery libraries. For these reasons, deploying other jQuery libraries is sometimes unavoidable. Multiple jQuery instances within a web page conflict over global variables. But the module system allows to use such a library.
For example, a jQueryPortlet uses jQuery version 1.6.4 to configure two modules.

<module>
  <name>jquery-1.6.4</name>
  <script>
    <adapter>
(function() {
  <include>/javascript/jquery-1.6.4.js</include>
  return jQuery.noConflict(true);
})();
    </adapter>
  </script>
</module>
<portlet>
  <name>jQueryPortlet</name>
  ...
  <depends>
    <module>jquery-1.6.4</module>
  </depends>
</portlet>

43.5. jQuery Plug-ins

To configure a jQuery plugin and use it in jQueryPluginPortlet portlet.
For example, the plugin code is a minimal plugin:

Example 43.1. "jQuery plugin"


(function($) {
 $.fn.doesPluginWork = function() {
    alert('YES, it works!');
 };
})(jQuery);
  • The plugin is then declared as a module:
    
    <module>
      <name>jquery-plugin</name>
      <as>jqPlugin</as>
      <script>
        <path>/jqueryPlugin/jquery-plugin.js</path>
      </script>
      <depends>
        <module>jquery</module>
        <as>jQuery</as>
      </depends>
    </module>
    
  • This plugin in ready for use in your portlet:
    
    <portlet>
      <name>jQueryPluginPortlet</name>
      <module>
        <script>
          <path>/jqueryPlugin/jqueryPluginPortlet.js</path>
        </script>
        <depends>
          <module>jquery</module>
          <as>$</as>
        </depends>
        <depends>
          <module>jquery-plugin</module>
        </depends>
      </module>
    </portlet>
    
Your portlet module should depend on the jquery and the jquery-plugin modules even if it does not use the plugin itself because:
  • Declaring the dependency on jquery allows you to use the jQuery object.
  • Declaring the dependency on jquery-plugin ensures that the plugin is loaded in the jquery dependency before it is injected in the portlet module.

43.6. Override Native AMD Module Dependency

In case of a mismatch between a module declared in the native module and the module system of the portal, the as tag is used to rename the dependencies.
For example, a foo.js file defines an AMD module named foo with two dependencies "dep1", "dep2":

define("foo", ["dep1", "dep2"], function(a1, a2) {
  // The module
});
The dependencies are declared as module1 and module2 in the portal, with mismatch in names. To override this, use the as tag and rename the dependencies:

<module>
  <name>foo</name>
  <script>
    <path>/path/to/foo.js</path>
  </script>
  <depends>
    <module>module1</module>
    <as>dep1</as>
  </depends>
 <depends>
   <module>module2</module>
   <as>dep2</as>
 </depends>
</module>

43.7. CommonJS modules

CommonJS defines its own module format. See the CommonJS wiki for detailed information, which is available at http://wiki.commonjs.org/wiki/Modules/1.1. CommonJS module is not supported natively by the Red Hat JBoss Portal, therefore the adapter format is used to adapt CommonJS modules to work in the portal.
Two simple CommonJS modules are as follows:

Example 43.2. math.js


exports.add = function() {
  var sum = 0, i = 0, args = arguments, l = args.length;
  while (i < l) {
    sum += args[i++];
  }
  return sum;
};

Example 43.3. increment.js


var add = require('math').add;
exports.inc = function(val) {
  return add(val, 1);
};
CommonJS modules uses the require function which conflicts with the same function in RequireJS. To resolve the conflict in AMD enabled environment, these modules are wrapped and injected to predefined modules such as require , exports, and module provided by RequireJS.
The portal wraps the code using the <adapter> format as per the configuration:

<module>
  <name>math</name>
  <script>
    <adapter>
      define(["require", "exports"], function(require, exports) {
      <include>/commonjs/math.js</include>
      });
    </adapter>
  </script>
  <depends>
    <module>require</module>
  </depends>
  <depends>
    <module>exports</module>
  </depends>
</module>
<module>
  <name>increment</name>
  <script>
    <adapter>
      define(["require", "exports", "math"], function(require, exports) {
      <include>/commonjs/increment.js</include>
      });
    </adapter>
  </script>
  <depends>
    <module>require</module>
  </depends>
  <depends>
    <module>exports</module>
  </depends>
  <depends>
    <module>math</module>
  </depends>
</module>
For more information related to modules, see the RequireJS.org documentation available at http://requirejs.org/docs/commonjs.html.

43.8. Mustache.js module

Mustache.js is a popular JavaScript template engine. Mustache can be executed in different environments such as a global object, as a CommonJS module, or as a native AMD module.
If "module" and "exports" dependencies are available, Mustache registers it as a CommonJS module and it is adapted for the portal as per the adapter format as follows:

<module>
  <name>mustache</name>
  <script>
    <adapter>
define(["require", "exports", "module"], function(require, exports, module) {
  <include>/requirejs/js/plugins/mustache.js</include>
});
    </adapter>
  </script>
  <depends>
    <module>require</module>
  </depends>
  <depends>
    <module>exports</module>
  </depends>
  <depends>
    <module>module</module>
  </depends>
</module>
Theadapter tag is used to declare require , exports, and module dependencies of the CommonJS module. Any module can have Mustache instance injected by declaring it in its dependencies list as follows:

<module>
  <name>foo</name>
  ...
  <depends>
    <module>mustache</module>
  </depends>
</module>

(function(mustache){
  //code that use Mustache
  mustache.render(template);
})(mustache);

43.9. Resource loading with Text.js

RequireJS supports loader plugin which allows a module to work as a plugin and use the AMD system for loading web resources efficiently.
Mustache.js is a javascript template engine. This engine need a template file to parse and generate html. In case of many templates or the template size is large, embedding a template in the page is not a good practice for front-end performance reason. In this case, use Text.js to load the separate template files and inject them as dependencies.
Text.js is a native AMD module, which depends on the module predefined dependency provided by the AMD loader. Due to the native AMD support in the portal, it is easy to declare and use Text.js:

<module>
  <name>text</name>
  <script>
    <path>/requirejs/js/plugins/text.js</path>
  </script>
  <depends>
    <module>module</module>
  </depends>
</module>
Use mustache and text modules to load templates and render them in your own module:

<portlet>
  <name>foo</name>
  <module>
    ...
    <depends>
      <module>mustache</module>
    </depends>
    <depends>
      <module>text</module>
      <as>tmpl</as>
      <resource>/path/to/template.html</resource>
    </depends>
  </module>
</portlet>
The text module is in the dependency list with a <resource> tag. Text.js loads that resource template and inject it with the name tmpl. The javascript of the portlet is as follows:

function(mustache, tmpl) {
  var html = mustache.render(tmpl);
  //append rendered html to DOM
})(mustache, tmpl);