Help documentation is deployed as a set of files zipped up in a module jar. With the introduction of module parts in Niagara 4, help content should be contained in a part with a runtime profile of doc. (See Modules for a description of modules and runtime profiles.) Help content can be any MIME typed file. The primary content types are:
There are three steps in help content creation:
The module developer creates help content files and structure files. Some forms this content may take are:
Help -> Guide on Target will take the user to the document corresponding to the type of the component they are currently viewing. These documents should be saved into your module using the path convention yourModule/doc/moduleName-CustomTypeName.html.Help -> On View will take the user to the document corresponding to the type of view they are currently on. These documents should be saved into your module using the path convention yourModule/doc/moduleName-ViewTypeName.html.(Optional) The developer supplies a lexicon key to point to the module containing help. Guide help (Guide on Target) will look for the HTML file defined above in the doc directory of its module if the help.guide.base is not defined in its lexicon. You can supply this key to point to another module. As an example, most core modules point to docUser: help.guide.base=module://docUser/doc.
Build the module. The module part containing the help content is built using the same tools as other module parts. See the build documentation for more information on this. During this step, the help content is indexed for the full text search purposes.
A doc module part’s build script should have the com.tridium.niagara-doc plugin applied in its plugins block:
plugins {
// Other plugins
// ...
id("com.tridium.niagara-doc")
You must also add a dependency on the Niagara modules that generate search indexes:
dependencies {
// Other dependencies
// ...
// 'indexJars' are the Niagara modules required to build the search index for
// a doc module
indexJars(":nre")
indexJars(":baja")
indexJars(":html-wb")
indexJars(":help-wb")
Among other things, applying the com.tridium.niagara-doc plugin will register a Copy task called docCopy, which will stage all documentation to be processed and included in the module. By default, no documentation is included; you will need to configure that task to include any documentation you may have, as shown:
tasks.named<Copy>("docCopy") {
from("src") {
include("doc/**/*.*")
}
}
This will cause several things to happen when the module is built:
docCopy task and referenced in the table of contents will be enhanced with a link to the standard help style sheet. This style sheet is not user configurable.index.html.
In order for the HTML enhancement processing to insert the style sheet and navigation links in the correct positions, the <head>, <body> and </body> elements in the document HTML should start on new lines. It is also required that HTML documentation files in the module are encoded with the UTF-8 character set.
Documentation modules are subject to the same code signing requirements as other modules. See the Build section for details.
The copyright text applied to the HTML can be specified in the project’s build script as an extra property named copyright on the project. For example, the build script could include the following extra property:
ext.copyright = 'Copyright © 2000-2015 Tridium Inc. All rights reserved.'
This will apply the copyright text to a single module part. For multi-project builds, the copyright text can also be specified in the vendor.gradle file, again as an extra property. This will ensure that the same copyright text is applied to all doc module parts under the root Niagara project.
When optionally generating Bajadoc API documentation, there will be one or more projects containing the Java code to be documented - these projects will have runtime profiles such as ‘rt’ or ‘wb’. There will also be a project with a ‘doc’ runtime profile. This will be the project configured to contain user documentation relating to the other projects, and also to generate the Bajadocs from the source code in the other projects:
\<some folder name> - Top level directory
- build.gradle.kts
- settings.gradle.kts
`|- <project name-rt>\ - Folder containing project name-rt`
`| |- <project name-rt>.gradle.kts - rt Project Gradle script file`
`|- <project name-wb>\ - Folder containing project name-wb`
`| |- <project 2 name-wb>.gradle.kts - wb Project Gradle script file`
`|- <project name-doc>\ - Folder containing project name-doc`
`| |- <project name-doc>.gradle.kts - doc Project Gradle script file`
For the ‘rt’, ‘ux’, ‘wb’, or ‘se’ module parts, you must ensure the com.tridium.bajadoc plugin is applied:
plugins {
// other plugins
// ...
id("com.tridium.bajadoc")
This registers the bajadoc task, which must then be configured to generate Bajadoc for specific packages. This can be done with several methods on the bajadoc task:
includePackage This can be used to pass the name of a single Java package to be documented. There are two further configuration properties required here (see below for an example):
name = The name of the Java package.bajaOnly = A boolean value, which, if true, will only generate API documentation for the properties, actions and topics of Niagara types. Methods, functions and regular Java classes will not be documented.include This can be used to include code files via an ANT style include pattern. The pattern should target ‘.java’ files relative to the project’s /src directory. Example: include("com/mycompany/mydriver/messages/*.java")exclude This can be used to exclude files via an ANT style exclude pattern. The pattern should target ‘.java’ files relative to the project’s /src directory. This might be used to exclude certain classes that need to be in a documented package, but are not considered part of the public API and therefore can be ignored. Example: exclude("com/mycompany/mydriver/**/*Util.java")
The bajadoc declaration must contain at least one usage of includePackage or includePattern in order to have a set of source files to generate the documentation from.
Note that include specifies a single package name, while include and exclude specify file paths, which could potentially match more than one Java package.
// Bajadoc task must be added to the imports at the top of the file to be referenced.
import com.tridium.gradle.plugins.bajadoc.task.*
tasks.named<Bajadoc>("bajadoc") {
// Per-package
includePackage("com.mycompany.mydriver.messages")
// Alternatively
include("com/mycompany/mydriver/messages/*.java")
// Note that 'bajaOnly' is only available for includePackage and not include/exclude
includePackage("com.mycompany.mydriver.core", bajaOnly = true)
// Note that '**' in an ANT style pattern matches any number of subfolders
exclude("com/mycompany/mydriver/**/*Util.java")
}
For the ‘doc’ module part, in addition to applying the com.tridium.niagara-doc plugin, you must also apply the com.tridium.bajadoc-module plugin to enable Bajadoc aggregation from other projects:
plugins {
// other plugins
// ...
id("com.tridium.niagara-doc")
id("com.tridium.bajadoc-module")
The application of the com.tridium.bajadoc-module plugin will create a new configuration named bajadocs. You can depend on other projects in your build to pull in their API documentation. Note that all configuration of what to include or exclude from the generated Bajadoc is done in the build script for the module part. The doc module simply aggregates any content generated by each module part. Note that you can aggregate Bajadoc from any number of module parts into one doc module.
dependencies {
// Other dependencies
// ...
bajadocs(project(":<project name-rt>"))
bajadocs(project(":<project name 2-wb>"))
}
You may wish to provide some processing of documentation prior to it being included in your doc module. For example, you may wish to write documentation in a form that is easier to write and convert it to HTML when your module is built. While the specifics of writing Gradle tasks to perform the processing are out of scope for this document, the basic idea would be:
docCopy task copies the results of that Gradle task.As a slightly contrived example, say that you have documentation stored in .foo files, and you have a Java library that can convert .foo files to HTML. First, you will need to add the Java library to your module part’s buildscript classpath:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.foo:foo-to-html:1.0")
}
}
You will then need to create a Gradle task that can perform the conversion. Typically, these kinds of Gradle tasks are SourceTask implementations. Consult the Gradle documentation for further information, or for guidance on how to write more complex tasks. A simple task which calls FooToHtml#convert on all input files is shown below:
abstract class ConvertFooToHtml: SourceTask() {
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
@TaskAction
fun convertFooToHtml() {
val fooToHtml = FooToHtml(option1 = true, option2 = false)
source.visit {
if (!isDirectory) {
// This will ensure the same directory hierarchy is used for the
// output
outputDirectory.dir(path).get().asFile.parentFile.mkdirs()
val outputFileName = relativePath
.replaceLastName("${file.nameWithoutExtension}.html")
.pathString
val outputFile = outputDirectory.file(outputFile).get().asFile
logger.info("Converting {} to {}", path, outputFile)
fooToHtml.convert(file, outputFile)
}
}
}
}
Again, this is a very simplistic example and the Gradle documentation can provide much more detail. You may even find that an existing, publicly available plugin can do the task you need already. The important bit is that the task has a single OutputDirectory that we can then configure our docCopy task to use:
val convertFooToHtml = tasks.register<ConvertFooToHtml>("convertFooToHtml") {
outputDirectory.set(project.layout.buildDirectory.dir("fooconvert"))
from("src") {
include("doc/**/*.foo")
}
}
tasks.named<Copy>("docCopy") {
from("src") {
include("doc/**/*.*")
// Don't include source files for foo
exclude("doc/**/*.foo")
}
// Include the converted output of the 'convertFooToHtml' task
from(convertFooToHtml)
}
Note that we exclude any .foo files from docCopy as it is assumed that the convertFooToHtml task will process them instead. Also note that all doc content must be in a doc subfolder; if your task does not do this, you can force it as follows:
tasks.named<Copy>("docCopy") {
// Include the converted output of the 'convertFooToHtml' task
from(convertFooToHtml) {
// Ensure it's in the right place
into("doc")
}
}
This is the example outlined above in full
/*
* Copyright 2023 Tridium, Inc. All Rights Reserved.
*/
import com.foo.render.FooToHtml
import com.tridium.gradle.plugins.module.util.ModulePart.RuntimeProfile.*
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.foo:foo-to-html:1.0")
}
}
plugins {
id("com.tridium.niagara-module")
id("com.tridium.niagara-signing")
id("com.tridium.bajadoc")
id("com.tridium.niagara-jacoco")
id("com.tridium.niagara-annotation-processors")
id("com.tridium.convention.niagara-home-repositories")
id("com.tridium.niagara-doc")
}
description = "Documentation for stuff"
moduleManifest {
moduleName.set("myDocs")
runtimeProfile.set(doc)
}
// See documentation at module://docDeveloper/doc/build.html#dependencies for the supported
// dependency types
dependencies {
// 'indexJars' are the Niagara modules required to build the search index for
// a doc module
indexJars(":nre")
indexJars(":baja")
indexJars(":html-wb")
indexJars(":help-wb")
}
abstract class ConvertFooToHtml: SourceTask() {
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
@TaskAction
fun convertFooToHtml() {
val fooToHtml = FooToHtml(option1 = true, option2 = false)
source.visit {
if (!isDirectory) {
// This will ensure the same directory hierarchy is used for the
// output
outputDirectory.dir(path).get().asFile.parentFile.mkdirs()
val outputFileName = relativePath
.replaceLastName("${file.nameWithoutExtension}.html")
.pathString
val outputFile = outputDirectory.file(outputFile).get().asFile
logger.info("Converting {} to {}", path, outputFile)
fooToHtml.convert(file, outputFile)
}
}
}
}
val convertFooToHtml = tasks.register<ConvertFooToHtml>("convertFooToHtml") {
outputDirectory.set(project.layout.buildDirectory.dir("fooconvert"))
from("src") {
include("doc/**/*.foo")
}
}
tasks.named<Copy>("docCopy") {
from("src") {
include("doc/**/*.*")
// Don't include source files for foo
exclude("doc/**/*.foo")
}
// Include the converted output of the 'convertFooToHtml' task
from(convertFooToHtml)
}
There are several styles provided by the built-in style sheet that will allow you to mark certain paragraphs as notes, tips, warnings, and so on.
<p class="note"> This is a note. </p>
<p class="tip"> This is a tip. </p>
<p class="warning"> This is a warning. </p>
<p class="important"> This is important! </p>
<p class="caution"> Take caution! </p>
In addition to the Bajadoc feature for documenting Java source code, documentation may also be generated for JavaScript code. This is made easy using the grunt-niagara plugin. You can learn more about this tool at its GitHub page.
grunt-niagara will automatically install and configure the JSDoc tool, which generate HTML-based documentation from comments in the source code. See the JSDoc site for details on the syntax of documentation comments.
The following sections will describe how JSDoc is enabled and configured. But please note that if you have built your web module as described in the Building JavaScript Applications section, almost all of this will be automatically set up for you, so please take a look through that section if you haven’t already. If you already have a web module created and are following along, your code will most likely already look just like the examples.
To incorporate grunt-niagara into your build, the plugin must be enabled in your Gradle file:
import com.tridium.gradle.plugins.grunt.task.GruntBuildTask
plugins {
id("com.tridium.niagara-grunt") // add this to the existing plugins section
}
The actual Grunt work done when building your module is defined in the gruntBuild task. This will allow you to specify which Grunt tasks are run as part of your Gradle build. The task that generates the JSDoc is simply named jsdoc.
tasks.named<GruntBuildTask>("gruntBuild") {
tasks("babel:dist", "copy:dist", "requirejs", "jsdoc") // add "jsdoc"
}
This will run the jsdoc task as it is configured in Gruntfile.js. The jsdoc task is present in the Gruntfile by default, but if you are manually building up your Gruntfile, be sure to include the task as described in the grunt-niagara documentation.
By default, the jsdoc task will generate JSDoc from every JavaScript file in src/rc/ and place it all in build/src/jsdoc for inclusion in your module. After building your module using Gradle, the ORD module://{yourModule}/jsdoc/index.html will be the root page of your JavaScript documentation.
You might like more fine-grained control over how your JSDoc is generated. For instance, you might want to generate documentation for only certain files, decide whether variables marked @private are included or excluded, or add tutorials. You can configure this in the Gruntfile - the jsdoc task is built upon the grunt-jsdoc plugin, and supports all its configuration options. You can find full details on these configuration options at the grunt-jsdoc homepage. A brief custom configuration is shown below to get you started.
jsdoc: {
src: [ 'src/rc/MyModuleA.js', 'src/rc/MyModuleB.js', 'src/rc/myFolder/' ],
options: {
private: true, // include private variables in documentation
tutorials: 'tutorials/' // generate tutorials from this directory
}
}
-doc module, not my -ux module!It’s true - the default behavior of grunt-niagara is to put the documentation into the same module as the code itself. If you would like to keep all your documentation consolidated in your -doc module, you can absolutely install grunt-niagara into your -doc module, and still configure your Gruntfile to generate docs from the code in your -ux module. Just ensure these steps are followed:
package.json that includes grunt-niagara to your -doc module (you can copy this from your -ux module).niagara-grunt plugin and the GruntBuildTask are added to your -doc module’s Gradle file. These can also be copy-pasted over. The only task you need is jsdoc.-doc module’s Gruntfile.js (which can, again, be copied and modified), the only task you need to configure is the jsdoc task. Just add to the src list the relative paths into your -ux module - something like the below:jsdoc: {
src: [ '../myModule-ux/src/rc' ]
}
You can then simply remove the jsdoc task from your -ux module to ensure the JSDoc doesn’t get generated twice.
Niagara modules are defined using RequireJS, which uses the AMD format to define its modules. JSDoc has certain requirements when documenting AMD, which are described on their own JSDoc page. Some brief examples showing the Tridium standard for documenting AMD modules are shown below.
If your module’s name is myModule, and your JavaScript file is at src/rc/MyWidget.js:
/**
* API Status: **Private**
* @module nmodule/myModule/rc/MyWidget
*/
define([
'baja!',
'bajaux/Widget' ], function (
baja,
Widget) {
'use strict';
/**
* A description of my widget.
*
* @class
* @alias module:nmodule/myModule/rc/MyWidget
* @extends module:bajaux/Widget
*/
class MyWidget extends Widget {}
return MyWidget;
});
Note the API Status line on top. This is included because we find that if you fully mark it private with the @private tag, many IDEs will flag an error if you attempt to reference it outside this file, and JSDoc may require you to enable private members to get it to show up in the documentation. If these are not an issue for you, you may certainly add the @private tag if appropriate. If you wish for it to be officially public API, simply omit those lines.
If your module’s name is myModule, and your JavaScript file is at src/rc/myUtilityMethods.js:
define([ 'baja!' ], function (baja) {
'use strict';
/**
* API Status: **Private**
* @exports module:nmodule/myModule/rc/myUtilityMethods
*/
const exports = {};
/**
* @returns {string}
*/
exports.myUtilityFunction = function () {
return 'hello world';
};
return exports;
});
Note the @exports tag. There is no @module tag in this module - the @exports tag takes its place. Individual methods may be documented as usual.
The help side bar has three tabs: Table of Contents, API and Search.
As a general rule, you should provide a TOC with your help content. This should be an XML file, named toc.xml, located at src/doc/toc.xml. This file is required for a module to appear in the help table of contents.
The following is an example TOC file:
<toc version="1.0">
<tocitem text="Index" target="index.html" image="module://myModule/rc/icons/index.png" />
<tocitem text="User Guide" target="userGuide.html" image="module://myModule/rc/icons/user.png" />
<tocitem text="Developer Guide" target="devGuide.html" image="module://myModule/rc/icons/programmer.png" />
<tocitem text="Contact Info">
<tocitem text="Tech Support" target="contact/techSupport.html" />
<tocitem text="Sales" target="contact/sales.html" />
</tocitem>
</toc>
As you can see, it should have <toc> as its root element, containing a list of files that you want to include in the TOC, in the logical order. Your TOC structure can be many levels deep, or simply a flat list of files.
Each file is included via the <tocitem> element, and has several attributes:
text: specifies the text of the node as the user will see it in the TOC tree.target: the relative URL of the content file associated with this TOC item.image: an ORD to a 16x16 icon that will appear on this node in the TOC tree.The target attribute:
src/doc/ directory...You may use tocitem elements with only the text attribute defined as a way of grouping TOC nodes. If you want to define a TOC node associated with some help content, you must provide the target. If you provide the target only, the text will be generated as the name of the target file, without path and extension. The image attribute is always optional.
This is a tree of module parts that have Bajadoc API documentation available. Packages and types within a module part can be viewed by expanding the items in the tree.
This is a search view, used to search for occurrences of text. Enter the search term in the ‘Find:’ box, and click the ‘Search’ button. Matching results will be displayed in a list below the search box.