Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this tutorial, we will following the guideline of developing a plugin to develop our Gantt Chart Userview Menu plugin. Please also refer to the very first tutorial วิธีการพัฒนา Bean Shell Hash Variable for more details steps.

1. What is the problem?

I want to display collected form data in a gantt chart view. I can choose to use Jasper Reports Userview Menu to achieve it but It does not look nice and lack of interactive control. Then, I found this Jquery Gantt Chart library developed by Tait Brown under MIT license which look nicer and work better than viewing a gantt chart using Jasper Report. I want to use it to display my collected form data.

2. What is your idea to solve the problem?

We can develop a Userview Menu Plugin to use the Jquery Gantt Chart library to display the collected form data.

3. What is the input needed for your plugin?

To develop a Gantt Chart Userview Menu plugin, we can consider to provide the following as input.

  1. Data Binder : We can reuse datalist binder to retrieve data
  2. Data Mapping : Map the retrieve data from datalist binder to the data format of the library
  3. Formatting options : Options to format and customise the gantt chart. 

4. What is the output and expected outcome of your plugin?

By referring to the library demo, we can quickly come out a static HTML page like the picture below. As this is a Joget plugin tutorial, we will not go into the detail on coding the static HTML page. You can refer to static.zip. We will expect our userview page can display our collected data as the static HTML page.

5. Is there any resources/API that can be reuse?

If you are not familiar with FreeMaker syntax, you should have a look on their document before proceed.

6. Prepare your development environment

We need to always have our Joget Workflow Source Code ready and builded by following this guideline

...

Open the maven project with your favourite IDE. I will be using NetBeans.  

7. Just code it!

a. Extending the abstract class of a plugin type

Create a "GanttChartMenu" class under "org.joget.tutorial" package. Then, extend the class with org.joget.apps.userview.model.UserviewMenu abstract class. Please refer to Userview Menu Plugin.

b. Implement all the abstract methods

As usual, we have to implement all the abstract methods. We will using AppPluginUtil.getMessage method to support i18n and using constant variable MESSAGE_PATH for message resource bundle directory.

...

Now, for testing purpose, we can skip to c. Manage the dependency libraries of your plugin, d. Make your plugin internationalization (i18n) readye. Register your plugin to Felix Framework and f. Build it and testing then continue the below after testing it. You will get something similar to below in your userview.

...

Code Block
<link href="${request.contextPath}/plugin/org.joget.tutorial.GanttChartMenu/lib/jquery.gantt/css/style.css" rel="stylesheet" type="text/css" />
<script src="${request.contextPath}/plugin/org.joget.tutorial.GanttChartMenu/lib/jquery.gantt/js/jquery.fn.gantt.min.js"></script>
<div class="gantt_chart_menu_body">
    <#if element.properties.title?? ><h3>${element.properties.title!}</h3></#if>
    ${element.properties.customHeader!}
    <div class="gantt"></div>
    <script>
        $(function() {
            "use strict";
            $(".gantt").gantt({
                source: ${data!},
                months: [@@userview.ganttChart.months.label@@],
                dow: [@@userview.ganttChart.dow.label@@],
                itemsPerPage: ${element.properties.itemsPerPage!},
                navigate: "${element.properties.navigate!}",
                scale: "${element.properties.scale!}",
                maxScale: "${element.properties.maxScale!}",
                minScale: "${element.properties.minScale!}",
                waitText: "@@userview.ganttChart.waitText@@",
                onItemClick: function (data) {
                    ${element.properties.onItemClick!}
                },
                onAddClick: function(datetime, rowId) {
                    ${element.properties.onAddClick!}
                },
                onRender: function() {
                    ${element.properties.onRender!}
                },
                useCookie: <#if element.properties.useCookie! == 'true'>true<#else>false</#if>,
                scrollToToday: <#if element.properties.scrollToToday! == 'true'>true<#else>false</#if>
            });
         });
    </script>
    ${element.properties.customFooter!}
</div>

c. Manage the dependency libraries of your plugin

Our plugin is using some libraries, we have to add all of them to our POM file.

Code Block
languagexml
        <!-- Change plugin specific dependencies here -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20080701</version>
        </dependency>
        <dependency>
            <groupId>displaytag</groupId>
            <artifactId>displaytag</artifactId>
            <version>1.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jcl104-over-slf4j</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- End change plugin specific dependencies here -->

d. Make your plugin internationalization (i18n) ready

We are using i18n message key in getLabel and getDescription method. We also used i18n message key in our properties options definition as well. So, we will need to create a message resource bundle properties file for our plugin.

...

Code Block
org.joget.tutorial.GanttChartMenu.pluginLabel=Gantt Chart Menu
org.joget.tutorial.GanttChartMenu.pluginDesc=Display data in a Gantt Chart view
userview.ganttchart.config=Configure Gantt Chart Menu
userview.ganttchart.customId=Custom ID
userview.ganttchart.invalidId=Only alpha-numeric and underscore characters allowed
userview.ganttchart.label=Label
userview.ganttchart.title=Page Title
userview.ganttchart.binder=Data Binder
userview.ganttchart.mapping=Column to Data Mappings
userview.ganttchart.mapping.category=Category (column ID)
userview.ganttchart.mapping.task=Task (column ID)
userview.ganttchart.mapping.activity=Activity (column ID)
userview.ganttchart.mapping.fromDate=Activity From Date (column ID)
userview.ganttchart.mapping.toDate=Activity To Date (column ID)
userview.ganttchart.mapping.dateFormat=Date format for Activity From/To Date
userview.ganttchart.mapping.taskId=Task Id (column ID)
userview.ganttchart.mapping.cssClass=Status (column ID, use as CSS class for styling)
userview.ganttchart.advanced=Advanced
userview.ganttchart.itemsPerPage=Item pre page
userview.ganttchart.navigate=Navigator
userview.ganttchart.navigate.buttons=Buttons
userview.ganttchart.navigate.scroll=Scroll
userview.ganttchart.scale=Default Scale
userview.ganttchart.scale.hours=Hours
userview.ganttchart.scale.days=Days
userview.ganttchart.scale.weeks=Weeks
userview.ganttchart.scale.months=Months
userview.ganttchart.maxScale=Maximum Scale
userview.ganttchart.minScale=Minimum Scale
userview.ganttchart.useCookie=Use cookie for storing chart states
userview.ganttchart.scrollToToday=Auto scroll to today after rendered
userview.ganttchart.onItemClick=On Item Clicked Event (Javascript)
userview.ganttchart.onAddClick=On Empty Space Clicked Event (Javascript)
userview.ganttchart.onRender=On Rendered Event (Javascript)
userview.ganttchart.customHeader=Custom Header (HTML)
userview.ganttchart.customFooter=Custom Footer (HTML)
userview.ganttChart.months.label="January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
userview.ganttChart.dow.label="S", "M", "T", "W", "T", "F", "S"
userview.ganttChart.waitText=Loading...

e. Register your plugin to Felix Framework

We will have to register our plugin class in Activator class (Auto generated in the same class package) to tell Felix Framework that this is a plugin.

Code Block
languagejava
    public void start(BundleContext context) {
        registrationList = new ArrayList<ServiceRegistration>();
        //Register plugin here
        registrationList.add(context.registerService(GanttChartMenu.class.getName(), new GanttChartMenu(), null));
    }

f. Build it and testing 

Let build our plugin. Once the building process is done, we will found a "gantt_chart_menu-5.0.0.jar" file is created under "gantt_chart_menu/target" directory.

...

Populate some data to the form for testing.

The end result.

8. Take a step further, share it or sell it

You can download the source code from gantt_chart_menu.zip.

...