Joget DX Preview Release Available for Download

Check out Joget DX, the next generation successor to Joget Workflow for faster, simpler digital transformation.

Page tree
Skip to end of metadata
Go to start of metadata

在本教程中,我们将遵循开发插件的  指导方针  来开发我们的甘特图用户视图菜单插件。 有关更多详细信息步骤,请参阅第一个教程  如何开发一个Bean Shell哈希变量插件

1.什么问题?

我想在甘特图视图中显示收集的表单数据。我可以选择使用  贾斯珀报告用户视图菜单来实现它,但它看起来不错,缺乏交互控制。然后,我发现这个  由Tait Brown  根据MIT许可开发的Jquery Gantt Chart库  ,看起来比使用Jasper Report的甘特图更好看,效果更好。我想用它来显示我收集的表单数据。  

2.你有什么想法来解决这个问题?

我们可以开发一个  Userview菜单插件  来使用  Jquery甘特图库来显示收集的表单数据。

3.你的插件需要什么输入?

要开发一个甘特图Userview菜单插件,我们可以考虑提供以下作为输入。

  1. 数据绑定器:我们可以重用数据绑定器来检索数据
  2. 数据映射:将检索数据从数据列表绑定到映射库的数据格式
  3. 格式化选项:用于格式化和自定义甘特图的选项。 

4.你的插件的输出和预期结果是什么?

通过参考库演示,我们可以快速地出来一个静态的HTML页面,如下图所示。由于这是一个Joget插件教程,所以我们不会详细介绍静态HTML页面的编码。你可以参考  static.zip。我们预计我们的用户视图页面可以将我们收集的数据显示为静态的HTML页面。

5.有没有可重用的资源/ API?

如果您不熟悉  FreeMaker  语法,则在继续之前,您应该查看其文档。

6.准备你的开发环境

我们需要始终准备好Joget Workflow Source Code,并按照这个指导方针建立起来  。 

本教程的以下内容是使用Macbook Pro和Joget源代码5.0.0版编写的。 其他平台命令请参考  如何开发插件

让我们说我们的文件夹目录如下。 

- Home
  - joget
    - plugins
    - jw-community
      -5.0.0

“plugins”目录是我们要创建和存储我们所有插件的文件夹,“jw-community”目录是Joget Workflow源代码存储的地方。

运行以下命令在“plugins”目录下创建一个maven项目。

cd joget/plugins/
~/joget/jw-community/5.0.0/wflow-plugin-archetype/create-plugin.sh org.joget.tutorial gantt_chart_menu 5.0.0

然后,shell脚本将要求我们为您的插件输入一个版本,并在生成maven项目之前要求我们确认。

Define value for property 'version':  1.0-SNAPSHOT: : 5.0.0
[INFO] Using property: package = org.joget.tutorial
Confirm properties configuration:
groupId: org.joget.tutorial
artifactId: gantt_chart_menu
version: 5.0.0
package: org.joget.tutorial
Y: : y

我们应该在终端上显示“BUILD SUCCESS”消息,并在“plugins”文件夹中创建一个“gantt_chart_menu”文件夹。

用你最喜欢的IDE打开maven项目。我将使用  NetBeans。  

7. Just code it!

a. 扩展插件类型的抽象类

在“org.joget.tutorial”包下创建一个“GanttChartMenu”类。然后,使用org.joget.apps.userview.model.UserviewMenu  抽象类来扩展  该类。请参阅用户  视图菜单插件

b. 实现所有的抽象方法

像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录。

Implementation of all basic abstract methods
package org.joget.tutorial;
 
import org.joget.apps.app.service.AppPluginUtil;
import org.joget.apps.userview.model.UserviewMenu;
 
public class GanttChartMenu extends UserviewMenu {
    
    private final static String MESSAGE_PATH = "messages/GanttChartMenu";
 
    public String getName() {
        return "Gantt Chart Menu";
    }
    public String getVersion() {
        return "5.0.0";
    }
    
    public String getClassName() {
        return getClass().getName();
    }
    
    public String getLabel() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.GanttChartMenu.pluginLabel", getClassName(), MESSAGE_PATH);
    }
    
    public String getDescription() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.GanttChartMenu.pluginDesc", getClassName(), MESSAGE_PATH);
    }
 
    public String getPropertyOptions() {
        return AppUtil.readPluginResource(getClassName(), "/properties/ganttChartMenu.json", null, true, MESSAGE_PATH);
    }
 
    @Override
    public String getCategory() {
        return "Marketplace";
    }
    @Override
    public String getIcon() {
        //sorry, i am reuse the icon of other plugin here
        return "/plugin/org.joget.apps.userview.lib.HtmlPage/images/grid_icon.gif";
    }
    
    @Override
    public boolean isHomePageSupported() {
        return true; // Can use as first page of the userview
    }
    
    @Override
    public String getDecoratedMenu() {
        return null; // using default
    }
 
    @Override
    public String getRenderPage() {
        throw new UnsupportedOperationException("Not supported yet."); 
    }
}

然后,我们必须为管理员用户提供一个UI来为我们的插件提供输入。在getPropertyOptions方法中,我们已经指定了我们的  插件属性选项和配置  定义文件位于“/properties/ganttChartMenu.json”。让我们在“gantt_chart_menu / src / main”目录下创建一个目录“resources / properties”。创建目录后,在“properties”文件夹中创建一个名为“ganttChartMenu.json”的文件。

在属性定义选项文件中,我们需要提供如下的选项。请注意,我们可以在我们的属性选项中使用“@@ message.key @@”语法来支持i18n。

 [{
    title : '@@userview.ganttchart.config@@',
    properties : [{
        name : 'id',
        label : 'Id',
        type : 'hidden'
    },
    {
        name : 'customId',
        label : '@@userview.ganttchart.customId@@',
        type : 'textfield',
        regex_validation : '^[a-zA-Z0-9_]+$',
        validation_message : '@@userview.ganttchart.invalidId@@'
    },
    {
        name : 'label',
        label : '@@userview.ganttchart.label@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'title',
        label : '@@userview.ganttchart.title@@',
        type : 'textfield'
    },
    {
        name : 'binder',
        label : '@@userview.ganttchart.binder@@',
        type : 'elementselect',
        required : 'True',
        options_ajax : '[CONTEXT_PATH]/web/property/json/getElements?classname=org.joget.apps.datalist.model.DataListBinderDefault',
        url : '[CONTEXT_PATH]/web/property/json[APP_PATH]/getPropertyOptions'
    },
    {
        label : '@@userview.ganttchart.mapping@@',
        type : 'header'
    },
    {
        name : 'category',
        label : '@@userview.ganttchart.mapping.category@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'task',
        label : '@@userview.ganttchart.mapping.task@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'activity',
        label : '@@userview.ganttchart.mapping.activity@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'fromDate',
        label : '@@userview.ganttchart.mapping.fromDate@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'toDate',
        label : '@@userview.ganttchart.mapping.toDate@@',
        type : 'textfield',
        required : 'True'
    },
    {
        name : 'dateFormat',
        label : '@@userview.ganttchart.mapping.dateFormat@@',
        type : 'textfield',
        required : 'True',
        value : 'yyyy-MM-dd'
    },
    {
        name : 'taskId',
        label : '@@userview.ganttchart.mapping.taskId@@',
        type : 'textfield'
    },
    {
        name : 'cssClass',
        label : '@@userview.ganttchart.mapping.cssClass@@',
        type : 'textfield'
    }]
},
{
    title : '@@userview.ganttchart.advanced@@',
    properties : [
    {
        name : 'itemsPerPage',
        label : '@@userview.ganttchart.itemsPerPage@@',
        type : 'textfield',
        required : 'True',
        value : '20'
    },
    {
        name : 'navigate',
        label : '@@userview.ganttchart.navigate@@',
        type : 'selectbox',
        required : 'True',
        value : 'scroll',
        options : [{
            value : 'buttons',
            label : '@@userview.ganttchart.navigate.buttons@@'    
        },
        {
            value : 'scroll',
            label : '@@userview.ganttchart.navigate.scroll@@'    
        }]
    },
    {
        name : 'scale',
        label : '@@userview.ganttchart.scale@@',
        type : 'selectbox',
        required : 'True',
        value : 'days',
        options : [{
            value : 'hours',
            label : '@@userview.ganttchart.scale.hours@@'    
        },
        {
            value : 'days',
            label : '@@userview.ganttchart.scale.days@@'    
        },
        {
            value : 'weeks',
            label : '@@userview.ganttchart.scale.weeks@@'    
        },
        {
            value : 'months',
            label : '@@userview.ganttchart.scale.months@@'    
        }]
    },
    {
        name : 'maxScale',
        label : '@@userview.ganttchart.maxScale@@',
        type : 'selectbox',
        required : 'True',
        value : 'months',
        options : [{
            value : 'hours',
            label : '@@userview.ganttchart.scale.hours@@'    
        },
        {
            value : 'days',
            label : '@@userview.ganttchart.scale.days@@'    
        },
        {
            value : 'weeks',
            label : '@@userview.ganttchart.scale.weeks@@'    
        },
        {
            value : 'months',
            label : '@@userview.ganttchart.scale.months@@'    
        }]
    },
    {
        name : 'minScale',
            label : '@@userview.ganttchart.minScale@@',
        type : 'selectbox',
        required : 'True',
        value : 'hours',
        options : [{
            value : 'hours',
            label : '@@userview.ganttchart.scale.hours@@'    
        },
        {
            value : 'days',
            label : '@@userview.ganttchart.scale.days@@'    
        },
        {
            value : 'weeks',
            label : '@@userview.ganttchart.scale.weeks@@'    
        },
        {
            value : 'months',
            label : '@@userview.ganttchart.scale.months@@'    
        }]
    },
    {
        name : 'useCookie',
        label : '@@userview.ganttchart.useCookie@@',
        type : 'checkbox',
        options : [{
            value : 'true',
            label : ''    
        }]
    },
    {
        name : 'scrollToToday',
        label : '@@userview.ganttchart.scrollToToday@@',
        type : 'checkbox',
        options : [{
            value : 'true',
            label : ''    
        }]
    },
    {
        name : 'onItemClick',
        label : '@@userview.ganttchart.onItemClick@@',
        type : 'codeeditor',
        mode : 'javascript',
        value : '//console.log(data); //data obj hold all the columns value of a row'
    },
    {
        name : 'onAddClick',
        label : '@@userview.ganttchart.onAddClick@@',
        type : 'codeeditor',
        mode : 'javascript',
        value : '//console.log(datetime); //the DateTime in ms for the clicked Cell\n//console.log(rowId); //the row ID of clicked Cell'
    },
    {
        name : 'onRender',
        label : '@@userview.ganttchart.onRender@@',
        type : 'codeeditor',
        mode : 'javascript',
        value : '//console.log("chart rendered");'
    },
    {
        name : 'customHeader',
        label : '@@userview.ganttchart.customHeader@@',
        type : 'codeeditor',
        mode : 'html'
    },
    {
        name : 'customFooter',
        label : '@@userview.ganttchart.customFooter@@',
        type : 'codeeditor',
        mode : 'html'
    }]
}]

完成收集输入的属性选项后,我们可以使用getRenderPage方法的插件的主要方法。通常情况下,我会先详细地将数据填充到视图中,首先将getRenderPage的静态内容先构建并测试插件。这一切都很好,只有我们试图添加数据到视图。

    @Override
    public String getRenderPage() {
        Map model = new HashMap();
        model.put("request", getRequestParameters());
        model.put("element", this);
        
        PluginManager pluginManager = (PluginManager)AppUtil.getApplicationContext().getBean("pluginManager");
        String content = pluginManager.getPluginFreeMarkerTemplate(model, getClass().getName(), "/templates/ganttChart.ftl", null);
        return content;
    }

然后,让我们创建一个位于“/templates/ganttChart.ftl”的模板文件。让我们在“gantt_chart_menu / src / main”目录下创建一个目录“resources / templates”。创建目录后,在“模板”文件夹中创建一个名为“ganttChartMenu.json”的文件。

将我们之前创建的静态HTML放到模板文件中,如下所示。记得把所有的依赖关系的JavaScript库和图像放在“gantt_chart_menu / src / main / resources / resources”下,并相应地更改url。你的项目目录应该看起来像下面的图片。

<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">
    <h3>Plugin Development</h3>
    <div class="gantt"></div>
    <script>
        $(function() {
            "use strict";
            $(".gantt").gantt({
                source: [{
                    name: "Sprint 0",
                    desc: "Analysis",
                    values: [{
                        from: "/Date(1320192000000)/",
                        to: "/Date(1322401600000)/",
                        label: "Requirement Gathering",
                        customClass: "ganttRed"
                    }]
                },{
                    name: " ",
                    desc: "Scoping",
                    values: [{
                        from: "/Date(1322611200000)/",
                        to: "/Date(1323302400000)/",
                        label: "Scoping",
                        customClass: "ganttRed"
                    }]
                 },{
                    name: "Sprint 1",
                    desc: "Development",
                    values: [{
                        from: "/Date(1323802400000)/",
                        to: "/Date(1325685200000)/",
                        label: "Development",
                        customClass: "ganttGreen"
                    }]
                },{
                    name: " ",
                    desc: "Showcasing",
                    values: [{
                        from: "/Date(1325685200000)/",
                        to: "/Date(1325695200000)/",
                        label: "Showcasing",
                        customClass: "ganttBlue"
                    }]
                 },{
                    name: "Sprint 2",
                    desc: "Development",
                    values: [{
                        from: "/Date(1326785200000)/",
                        to: "/Date(1325785200000)/",
                        label: "Development",
                        customClass: "ganttGreen"
                    }]
                 },{
                    name: " ",
                    desc: "Showcasing",
                    values: [{
                        from: "/Date(1328785200000)/",
                        to: "/Date(1328905200000)/",
                        label: "Showcasing",
                        customClass: "ganttBlue"
                    }]
                 },{
                    name: "Release Stage",
                    desc: "Training",
                    values: [{
                        from: "/Date(1330011200000)/",
                        to: "/Date(1336611200000)/",
                        label: "Training",
                        customClass: "ganttOrange"
                    }]
                 },{
                    name: " ",
                    desc: "Deployment",
                    values: [{
                        from: "/Date(1336611200000)/",
                        to: "/Date(1338711200000)/",
                        label: "Deployment",
                        customClass: "ganttOrange"
                    }]
                 },{
                    name: " ",
                    desc: "Warranty Period",
                    values: [{
                        from: "/Date(1336611200000)/",
                        to: "/Date(1349711200000)/",
                        label: "Warranty Period",
                        customClass: "ganttOrange"
                    }]
                 }],
                 navigate: "scroll",
                 maxScale: "hours",
                 itemsPerPage: 10
             });
         });
    </script>
</div>

现在,为了测试目的,我们可以跳到  c。管理你的插件的依赖库d。让你的插件国际化(国际化),  例如。将您的插件注册到Felix Framework和  f。构建它并测试,  然后在测试之后继续下面的内容。你会在你的用户视图中看到类似于下面的内容。

在验证静态HTML在我们的插件中工作之后,我们可以通过向视图添加数据来进一步增强它。现在,修改您的getRenderPage方法和ganttChart.ftl模板如下。

    @Override
    public String getRenderPage() {
        Map model = new HashMap();
        model.put("request", getRequestParameters());
        model.put("element", this);
        
        //populate data in JSON format
        model.put("data", getData());
        
        PluginManager pluginManager = (PluginManager)AppUtil.getApplicationContext().getBean("pluginManager");
        String content = pluginManager.getPluginFreeMarkerTemplate(model, getClass().getName(), "/templates/ganttChart.ftl", MESSAGE_PATH);
        return content;
    }
     
    protected String getData() {
        String json = "[]"; 
        
        try {
            DataListCollection data = null;
            String idColumn = getPropertyString("taskId");
            
            //get the binder
            Object binderData = getProperty("binder");
            if (binderData != null && binderData instanceof Map) {
                Map bdMap = (Map) binderData;
                if (bdMap != null && bdMap.containsKey("className") && !bdMap.get("className").toString().isEmpty()) {
                    PluginManager pluginManager = (PluginManager) AppUtil.getApplicationContext().getBean("pluginManager");
                    DataListBinder binder = (DataListBinder) pluginManager.getPlugin(bdMap.get("className").toString());
                    
                    if (binder != null) {
                        Map bdProps = (Map) bdMap.get("properties");
                        binder.setProperties(bdProps);
                        
                        data = binder.getData(null, bdProps, new DataListFilterQueryObject[0], null, null, null, null);
                        if (idColumn.isEmpty()) {
                            idColumn = binder.getPrimaryKeyColumnName();
                        }
                    }
                }
            }
            
            JSONArray dataArry = new JSONArray();
            String dateFormat = getPropertyString("dateFormat");
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            
            if (data != null && !data.isEmpty()) {
                String currentCategory = null;
                int cat_count = 0;
                String currentTask = null;
                int task_count = 0;
                int act_count = 0;
                
                JSONObject taskObj = null;
                JSONArray taskValuesArray = null;
                for (Object r : data) {
                    String id = getValue(r, idColumn);
                    String cat = getValue(r, getPropertyString("category"));
                    String task = getValue(r, getPropertyString("task"));
                    String act = getValue(r, getPropertyString("activity"));
                    String formDate = getValue(r, getPropertyString("fromDate"));
                    String toDate = getValue(r, getPropertyString("toDate"));
                    String status = getValue(r, getPropertyString("cssClass"));
                    
                    if (currentTask == null || !currentTask.equals(task) || (currentTask.equals(task) && !cat.equals(currentCategory))) {
                        currentTask = task;
                        if (taskObj != null) {
                            taskObj.put("values", taskValuesArray);
                            dataArry.put(taskObj);
                        }
                        taskObj = new JSONObject();
                        taskValuesArray = new JSONArray();
                        taskObj.put("desc", task);
                        taskObj.put("id", id);
                        task_count++;
                    }
                    
                    if (currentCategory == null || !currentCategory.equals(cat)) {
                        currentCategory = cat;
                        taskObj.put("name", cat);
                        cat_count++;
                    }
                    
                    JSONObject valueObj = new JSONObject();
                    JSONObject actObj = new JSONObject();
                    act_count++;
                    
                    actObj.put("taskId", id);
                    actObj.put("category", cat);
                    actObj.put("task", task);
                    actObj.put("activity", act);
                    actObj.put("formDate", formDate);
                    actObj.put("toDate", toDate);
                    actObj.put("status", status);
                    
                    valueObj.put("dataObj", actObj);
                    valueObj.put("label", act);
                    valueObj.put("from", "/Date("+sdf.parse(formDate).getTime()+")/");
                    valueObj.put("to", "/Date("+sdf.parse(toDate).getTime()+")/");
                    valueObj.put("customClass", "cat_"+cat_count+" task_"+task_count+" act_"+act_count+" "+status.replace(" ", "_"));
                    taskValuesArray.put(valueObj);
                }
                if (taskObj != null) {
                    taskObj.put("values", taskValuesArray);
                    dataArry.put(taskObj);
                }
            }
            
            return dataArry.toString();
        } catch (Exception e) {
            LogUtil.error(GanttChartMenu.class.getName(), e, json);
        }
        
        return json;
    }
    
    protected String getValue(Object o, String name) {
        String value = "";
        
        try {
            Object v = LookupUtil.getBeanProperty(o, name);
            if (v != null) {
                return v.toString();
            }
        } catch (Exception e) {
            LogUtil.error(GanttChartMenu.class.getName(), e, name);
        }
        
        return value;
    }
<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. 管理你的插件的依赖库

我们的插件正在使用一些库,我们必须将它们全部添加到我们的POM文件中。

        <!-- 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. 让你的插件国际化(国际化)

我们在getLabel和getDescription方法中使用i18n消息密钥。我们还在我们的属性选项定义中使用了i18n消息密钥。所以,我们需要为我们的插件创建一个消息资源包属性文件。

在“gantt_chart_menu / src / main”目录下创建目录“resources / messages”。然后,在文件夹中创建一个“GanttChartMenu.properties”文件。在属性文件中,让我们添加所有的消息键和它的标签如下。

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. 注册你的插件Felix框架

我们将不得不在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。

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

f. 建设和测试 

让我们建立我们的插件。一旦构建过程完成,我们将在“gantt_chart_menu / target”目录下创建一个“gantt_chart_menu-5.0.0.jar”文件。

然后,让插件jar上传到  管理插件。上传jar文件后,仔细检查插件是否正确上传和激活。

打开一个用户视图,你会看到新的插件被添加到“市场”下。将其拖到您的一个Userview类别.

编辑甘特图菜单的属性。

我选择“表单数据包装器”作为“数据包装器”进行测试。将所有映射填充到相应的字段标识/列标识。

配置选项。

高级设置来配置甘特图。

在“自定义页脚(HTML)”选项中编写一些css样式,为不同的状态提供不同的颜色。

将一些数据填充到表单中进行测试。

最终的结果。

8. 再进一步,分享或出售

您可以从gantt_chart_menu.zip下载源代码  。

本教程的测试应用程序是  APP_testGanttChart-1-20151106194035.jwa

要下载现成的插件jar,请在http://marketplace.joget.org/上找到它  。

 

  • No labels