Define theme modules
We define theme modules in XML or JSON.
These samples cover syntax for the plugin.xml extension point and JSON module definitions.
- Define the module.
An ID is required and version is an optional decimal value.
<module id="testModule1" version="1.0" > "modules": [ // ... { "id":"testModule1", "version":"1.0", // ... }, // ... ]
- Optionally, define capabilities in the module with a required ID string and value in dot notation, for example, 1.2.3.4.
This information is added to the theme client capabilities map carried in the request attribute...
com.ibm.portal.theme.client.capabilities
Portlets can query from the server-side to determine which client-side capabilities are present, including....
- JavaScript libraries
- CSS style catalogs
Client-side JavaScript code can query the global JSON object...
com_ibm_theme_capabilities
...for all available capabilities within the scope of the currently rendered page.
<capability id="capabilityA" value="1.0.0"/> <capability id="capabilityB" value="1.5"/> "capabilities":[ { "id":"capabilityA", "value":"1.0.0" }, { "id":"capabilityB", "value":"1.5" } ],
CF03: In addition to the explicit capabilities defined here, an implicitly defined capability per module was also introduced. This implicitly defined capability has the name and version of the module. If the same name is defined explicitly, the explicit one is used.
- Define any number of prereqs inside the module, with a required ID string and optional type string or minVersion in dot notation.
If type optional is used, no errors are output if the prereq cannot be found on the system. Optional.
<prereq id="testModuleA"/> <prereq id="testModuleB" minVersion="1.2.3.4"/> <prereq id="testModuleC" type="optional"/> "prereqs":[ { "id":"testModuleA" }, { "id":"testModuleB", "minVersion":"1.2.3.4" }, { "id":"testModuleC", "type":"optional" } ],
- Add a title or titles for the module in different languages.
Optional.
<title lang="en" value="en Module"/> <title lang="de" value="de Module"/> <title lang="es" value="es Module"/> "titles": [ { "lang":"en", "value":"en Module" }, { "lang":"de", "value":"de Module" }, { "lang":"es", "value":"es Module" } ],
- Add a description or descriptions. in different languages.
Optional.
<description lang="en" value="one two three"/> <description lang="de" value="ein zwei drei"/> <description lang="es" value="uno dos tres"/> "descriptions": [ { "lang":"en", "value":"one two three" }, { "lang":"de", "value":"ein zwei drei" }, { "lang":"es", "value":"uno dos tres" } ],
- Add contributions each with at least one child subcontribution to the module.
Contribution types...
Type Description head Linked into the head section of the theme at the co:head dynamic content spot. config Added to the end of the body section in the theme at the co:config dynamic content spot. menu Called by the theme menu framework. dyn-cs Output added to the theme at the specified dynamic content spot.
Subcontribution types...
Type Description css CSS can be added to head contributions only. js JavaScript files can be linked to head or config contributions. json JSON output is used by menu contributions only. markup HTML can be served by head, config, or dyn-cs dynamic spots. config_static Static JavaScript object. Global and publicly cacheable. Available in head or config contributions. config_dynamic Dynamic JavaScript object. Changes based on the page or user. Available in head or config contributions.
We can implement the following use cases in a module...
- Add a CSS file.
If we add more than one CSS file of the same type, use a separate subcontribution for each one.
Optional.
<contribution type="head"> <sub-contribution type="css"> <uri value="res:/HelloWorld/css/helloWorld.css" /> </sub-contribution> </contribution> "contributions": [{ "type":"head", "sub-contributions": [{ "type":"css", "uris": [{ "value":"/css/helloWorld.css" }] }] }],
- Define an alternative CSS file for bidirectional styles.
Optional. These styles are only served up when using a rtl language.
<contribution type="head"> <sub-contribution type="css"> <uri value="res:/HelloWorld/css/helloWorld.css" /> <uri type="rtl" value="res:/HelloWorld/css/helloWorld_rtl.css" /> </sub-contribution> </contribution> "contributions": [ {"type":"head", "sub-contributions": [ {"type":"css", "uris": [ { "value":"/css/helloWorld.css" }, { "value":"/css/helloWorld_rtl.css", "type":"rtl" } ] } } ], ]
- Define a resource for a specific device class.
Optional. Within the same subcontribution, add URIs with the appropriate device class string or equation identifier.
<contribution type="head"> <sub-contribution type="css"> <uri value="res:/HelloWorld/css/helloWorld.css" /> <uri deviceClass="tablet+iOS" value="res:/HelloWorld/css/helloWorld_iPad.css" /> </sub-contribution> </contribution> "contributions": [{ "type":"head", "sub-contributions": [{ "type":"css", "uris": [{ "value":"/css/helloWorld.css" }, { "value":"/css/helloWorld_iPad.css", "deviceClass":"tablet+iOS" }] }] }],
- Add a piece of markup to the head section, ensuring the HTML validates within the head, such as a meta tag.
Optional. Subcontributions of type markup can also be added to config or dyn-cs contributions.
<contribution type="head"> <sub-contribution type="markup"> <uri value="res:/HelloWorld/markup/helloWorldHead.html" /> </sub-contribution> </contribution> "contributions": [{ "type":"head", "sub-contributions": [{ "type":"markup", "uris": [{ "value":"/markup/helloWorldHead.html" }] }] }],
- Add a JavaScript file to the head section of the theme because it must be available for portlets to use, for example, a js library such as Dojo or jQuery).
Optional. If we add more than one JavaScript file of the same type, use a separate subcontribution for each one.
<contribution type="head"> <sub-contribution type="js"> <uri value="res:/HelloWorld/js/helloWorldHead.js" /> </sub-contribution> </contribution> "contributions": [{ "type":"head", "sub-contributions": [{ "type":"js", "uris": [{ "value":"/js/helloWorldHead.js" }] }] }]
- Define a JavaScript file in the config area.
It performs better than adding it to the head, but the js is not available until after the portlets have loaded.
Optional. If we add more than one JavaScript file of the same type, use a separate subcontribution for each one.
<contribution type="config"> <sub-contribution type="js"> <uri value="res:/HelloWorld/js/helloWorldBody_root.js" /> </sub-contribution> </contribution> "contributions": [{ "type":"config", "sub-contributions": [{ "type":"js", "uris": [{ "value":"/js/helloWorldBody_root.js" }] }] }]
- Define an alternative JavaScript file for other locales. Within the same subcontribution, add a second URI with the appropriate locale attribute.
Optional.
<contribution type="config"> <sub-contribution type="js"> <uri value="res:/HelloWorld/js/helloWorldBody_root.js" /> <uri lang="en" value="res:/HelloWorld/js/helloWorldBody_en.js" /> <uri lang="de" value="res:/HelloWorld/js/helloWorldBody_de.js" /> <uri lang="es" value="res:/HelloWorld/js/helloWorldBody_es.js" /> </sub-contribution> </contribution> "contributions": [{ "type":"config", "sub-contributions": [{ "type":"js", "uris": [{ "value":"/js/helloWorldBody_root.js" }, { "value":"/js/helloWorldBody_en.js", "lang":"en" }, { "value":"/js/helloWorldBody_de.js", "lang":"de" }, { "value":"/js/helloWorldBody_es.js", "lang":"es" }] }] }],
- Define an alternative JavaScript file for debugging purposes.
To debug the client-side code of a theme, supply a second entry for a debug subcontribution type debug to provide a more readable version of the JavaScript file.
<contribution type="config"> <sub-contribution type="js"> <uri value="res:/HelloWorld/js/helloWorldBody_root.js" /> <uri type="debug" value="res:/HelloWorld/js/helloWorldBody_debug.js" /> <uri type="debug,rtl" value="res:/HelloWorld/js/helloWorldBody_debug_rtl.js" /> </sub-contribution> </contribution> "contributions": [{ "type":"config", "sub-contributions": [{ "type":"js", "uris": [{ "value":"/js/helloWorldBody_root.js" }, { "value":"/js/helloWorldBody_debug.js", "type":"debug" }, { "value":"/js/helloWorldBody_debug_rtl.js", "type":"debug,rtl" }] }] }],
- Add a dynamic JavaScript config object.
Optional.
<contribution type="config"> <sub-contribution type="config_dynamic"> <uri value="res:/HelloWorld/jsp/helloWorldBodyConfig.jsp" /> </sub-contribution> </contribution> "contributions": [{ "type":"config", "sub-contributions": [{ "type":"config_dynamic", "uris": [{ "value":"/config/helloWorldBodyConfig.js" }] }] }]
- Add a static JavaScript config. object. Optional.
<contribution type="config"> <sub-contribution type="config_static"> <uri value="res:/HelloWorld/jsp/helloWorldBodyStatic.jsp" /> </sub-contribution> </contribution> "contributions": [{ "type":"config", "sub-contributions": [{ "type":"config_static", "uris": [{ "value":"/config/helloWorldBodyStatic.js" }] }] }]
- Define a menu contribution. Create a contribution of type menu with a subcontribution of type json.
Optional. The subcontribution references a JSON file that defines the individual menu entries. See Menu framework.
<contribution type="menu"> <sub-contribution type="json"> <uri value="res:/HelloWorld/js/helloWorld.json" /> </sub-contribution> </contribution> "contributions": [{ "type":"menu", "sub-contribution": [{ "type":"json", "uris": [{ "value":"/js/helloWorld.json" }] }] }]
- Define a dynamic spot. When the module is turned on, the output of this subcontribution replaces the default contents of the dynamic spot identified by the ref-id attribute.
Optional.
<contribution type="dyn-cs"> <sub-contribution type="markup" ref-id="some_dynamic_spot_id"> <uri value="res:/HelloWorld/jsp/helloWorldDynamicSpot.jsp" /> </sub-contribution> </contribution> "contributions": [{ "type":"dyn-cs", "sub-contribution": [{ "type":"markup", "ref-id":"some_dynamic_spot_id", "uris": [{ "value":"/html/helloWorldDynamicSpot.html" }] }] }]
- Give the module an activation handler.
Optional. Use either the extensionID, used in these examples, or class attribute to indicate the ModuleActiveChecker implementation; both are supported. By default, all modules defined are active. An inactive module is treated the same as a module that is not defined. Therefore, inactive modules are not started during portal run time. Set a key for activation or deactivation of the module with an entry in a resource environment provider in the application server. RESOURCE_ENV_PROVIDER_NAME with the name of the resource environment provider, and KEY_IN_RESOURCE_ENV_PROVIDER with the key within the resource environment provider. Valid key values are true if the module is active, or false if the module is inactive. For example, if to specify the my.module.is.active key for module activation in the resource environment provider ConfigService, the entry is:
<repentry rep="ConfigService" key="my.module.is.active"/> <moduleActivation extensionID="com.ibm.portal.resourceaggregator.util.ResourceEnvironmentProviderModuleActivationHandler"> <parameter name="rep" value="RESOURCE_ENV_PROVIDER_NAME" /> <parameter name="key" value="KEY_IN_RESOURCE_ENV_PROVIDER"/> </moduleActivation> "moduleActivation": { "extensionID":"com.ibm.portal.resourceaggregator.util.ResourceEnvironmentProviderModuleActivationHandler","parameters": [{ "name":"rep", "value":"RESOURCE_ENV_PROVIDER_NAME" }, { "name":"key", "value":"KEY_IN_RESOURCE_ENV_PROVIDER" }] },
- Give the module a runtime activation handler with a condition.
Optional. This allows a module to be turned on or off on a per page basis, which is based on the state of the current page. Currently, the runtime activation handler supports checking device class, which can be a string or an equation. See Device class equations.
<runtimeActivation> <condition deviceClass="tablet"/> </runtimeActivation>{code} "runtimeActivation": [{ "condition": { "deviceClass":"tablet" } }]
Parent Writing modulesRelated concepts:
Server-side framework