Modernizing a Notes application

Introduction

The quickest way of modernizing your application build on Notes is probably by keeping it on that sublime application platform and provide a new user-interface and updated business logic to it.

As a demonstratable example I would like to bring up my own Bildr project on OpenNTF.

A brief history

The application started initially as a web browser display only and create content via the Notes client application in the early 2000’s. From that the application was updated in a create content via the web browser too features.

Later the oneUI was implemented in a later step also utilizing the Application Layout control. With the Bootstrap4XPages plugin a responsive UI could be delivered a couple of years ago.

Nowadays the Application Layout control is no longer used but the Bootstrap responsive features and components are used further through the application.

The application still relies on XPages and Notes data (allthough used mainly in JSON format). The business logic resides mainly in Java Classes. With the separation of design and data the application could be hosted on Bluemix (not tested, please do).

Modernization

Looking back at this application story I believe the application will change also in the future (or die) perhaps a challenge could be to have the data optional in a different source (e.g. MongoDB) or exchange XPages for Angular and run it on Node.js.

So if you have experience moving data from Notes to MongoDb, applying a similar ACL and Roles security model on your application I would be happy to hear your experiences.

Or if you are still on the Notes client only level and want to bring your application to a (mobile) browser I am happy to exchange ideas with you and learn from your situation.

New release

Why am I saying this? Today I uploaded a new version on OpenNTF and for many Notes developers who a) not have taken the XPages path yet b) unfamiliar with Java and JSON the application could be a great starter example.

Lately there are not that many (new, updated) projects (applications) available at OpenNTF so the chance to find a working demo to see and understand the code and data running are a bit scarce (I am sorry).

I remember in the days of Superhuman Software a quote about Notes and collaboration was “dare to share” so I would challenge more developers to do so. We can learn a lot from examples from others and I thank those people who (still) do and from which I can learn from!

I wish you a wonderful learning experience at IBMConnect 2016!

Capture04

 

Bildr 5 released on OpenNTF

Announcement

Today I released a new version of Bildr on OpenNTF ! There have been spent quiet a few long evenings coding but it was fun (I may drink at home) and interesting!

So just before the holiday season and January’s  IBM Connect buzz I thought it would be a proper moment for a release. So consider it my Xmas present to the community :-)

Modernization

I label this version 5.0 since I (almost) completely rewrote the application from scratch. Lot of the logic I have placed in Java classes and the data format is mainly JSON.

I also separated the design from the data so in principle you should be able to place the app in the IBM Bluemix environment.

Because of these decisions there is no backward compatibility so a simple replace design will not work for your existing installation.

Below you can find some screenshots of the new interface. I hope you like it.

Screenshots

startpage

uploadprofilepicture

Thank you

I would like to thank all the teachers in our community who post their presentations, code samples and answers on the platforms out there.

I have tried to post the code on Github but this failed with the Github desktop client. If some can get me started with that I will distribute the project there too.

For now:

A Merry Christmas and fortune in 2016 !

Beware when removing ID’s of controls

In an exercise to maximize performance of an Xpages application we decided to remove as much as redundant ID’s of controls as possible, as described in this best practice.

In summary the ID of an control gets rendered in a much longer ID when the HTML page is rendered. A simple label with ID ‘label1’ could become ‘view:_id1:_id2:_id11:label1’ and if you put that label in a repeat control the generated ID could become even much longer.

A downsize of removing the ID I found out that some properties like tagName for example does not get applied anymore. Of course you can replace the tag around the control, but I found that out afterwards.

Nevertheless a good best practice removing ID’s but do it with caution. Read the comments in the post to update yourself on the subject.

Managed properties

For an application we aggregate the data from several servers and databases. In SSJS applications I tend to save such properties in Notes configuration documents and store them in scoped Variables during initialization. Something like was provided in the XPages Framework a while ago.

In episode 182 of Notes in 9 David Leedy gives a great demonstration how to work with Notes documents via Managed Beans. However for properties that should not be altered likely by an application administrator (could be the application owner, a regular Notes user) I tend to work with managed properties. With managed properties you more or less configure your managed bean.

So how could this look like?

In the faces-config.xml I set the properties for a managed bean e.g.

<?xml version=”1.0″ encoding=”UTF-8″?>
<faces-config>
<managed-bean>
<managed-bean-name>dataBean</managed-bean-name>
<managed-bean-class>com.wordpress.quintessens.ConfigBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>

<managed-property>
<property-name>dataSource</property-name>
<value>dev1.quintessens.com</value>
<property-class>java.lang.String</property-class>
</managed-property>

</managed-bean>
</faces-config>

which I can use then in my java code:

package com.wordpress.quintessens;
import java.io.Serializable;
public class ConfigBean implements Serializable {
private String dataSource;
//… more variable declarations

public JsonJavaObject loadBackEndConfig(String Key) throws NotesException {
JsonJavaObject json = null;
NotesContext nct = NotesContext.getCurrent();
Session session = nct.getCurrentSession();
String DatabaseName = session.getCurrentDatabase().getFilePath();
String ViewName = “(LookUpBackEndConfig)”;
try {
json = loadJSONObject(this.dataSource, DatabaseName, ViewName, Key, 1);
} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return json;
}

public void setDataSource(String dataSource{
this.dataSource = dataSource
}
public String getDataSource() {
return dataSource
}

}

You can check if the value is passed correctly e.g. via Expression Language:

<xp:text escape=”true” id=”computedField1″
value=”#{ConfigBean.dataSource}”>
</xp:text>

I am curious how you prefer to configure your applications? In some cases I find it perhaps an overkill to store the configuration in Notes documents and publish the values via a managed bean.

Happy development =)

 

new release XPages OpenLog Logger and custom runtime error page

Introduction

Good news for me! In an XPage application I wanted to provide an error logging function and preferably to OpenLog. I had problems with implementing the previous version of OpenLog logger but yesterday a new version is released on OpenNTF which took away that pain.

OpenLog logger

The OpenLog logger has some powerful features:

  • It can be used in your managed beans and other Java classes.
  • It can be used directly from SSJS with as little as openLogBean.addError(e,this);.
  • From SSJS all caught errors on the page are logged out together, at the end of the request.
  • Only two method names are used from SSJS, one to add an error, one to add an event, making it easy to pick up
  • From SSJS you only need to pass the information you wish. There is no need to pass nulls or empty strings.
  • From SSJS only one unique error per component is logged, regardless of how many times the error is encountered during the refresh lifecycle.
  • In SSJS, if you use a custom error page, uncaught errors will also be logged.
  • Uncaught errors will be logged for the page the error occurs on, not your custom error page.
  • You can define the OpenLog path and a variety of other variables without needing to change the code.
  • The functionality and code are available as an OSGi plugin (the best practice approach) but can also be included in individual NSFs.

Custom Runtime Error Page

In case you want to implement such functionality then I recommend you also take a look at how to define a custom run time error page. In my project I am using Bootstrap for UI look & feel, so I followed the steps Erick McCormick provides in this blog post.

code-prettify

In Erick’s post you will find that he uses Google’s code-prettify project. A nice feature is to ability to set a skin for the error message box. There are plenty of color themes available for the prettify project but if you use Bootstrap like I do you could try this theme.

A big thank you to the OpenLog logger project members and Erick!

custom_error_page

 

Infinite scroll and prevent multiple event fire

Probably a lot of you use the “Simple custom control to add infinite scrolling to repeat or views” available as codesnippet on OpenNTF.

This snippet allows you to load a next set of documents for a repeat or view control when you reach the bottom of the page. A feature that will be appreciated highly by mobile users of your Notes app.

If you look at the code, it fires the click event of a pagerAddRows control when you have reached the bottom of the window. This will happen as long as you are on the bottom of the window. What can this cause for disturbance:

  • It fires multiple events, while it is at the bottom of the window. You only asked for 1.
  • The events are not chained so when the second event is returned quicker that the first it will be inserted before it, which messes up the sorting of your collection.

I have not found a way to create a JS function to load a set of data from a repeat control in the ajax way. That would allow you to use the success property and set a state (ajaxready, true/false) for your window. This state could be used to check if the fire event is entitled to run or not.

Drop a line in cause you know the answer to such a function.

As a temporarily solution I suggest to keep the click event for the pagerAddRows control but set a timeout.

Here is what the code could look like:

<xp:scriptBlock id=”scriptBlock1″>
<xp:this.value>
<![CDATA[$(window).data(‘ajaxready’, true).scroll(function(e) {
if ($(window).data(‘ajaxready’) == false) return;
if ($(window).scrollTop() >= ($(document).height() – $(window).height())) {
$(window).data(‘ajaxready’, false);
setTimeout(function() {
$(“.infiniteScroll ul li a”).click();
dojo.query(“.timeago”).forEach( function(el) {
var timeagoWidget= dijit.getEnclosingWidget(el);
if(!timeagoWidget){
timeagoWidget = new timeago.Timeago({}, el);
}

//refresh timeago
timeagoWidget.refresh();
});
$(window).data(‘ajaxready’, true);
}, 200);

}
});]]>
</xp:this.value>
</xp:scriptBlock>

Here is set a timeout for 200 milliseconds which turns out to be quiet generous in my application, but at least I have prevented the disturbances mentioned earlier.

Happy coding!

collapsible menu with persistent state

Introduction

For a project I needed to have collapsible menus where the state is persistent, in other words after a refresh or a reload it should now if the menu was opened or closed.

The content of the menu is dynamic and rather complicated containing sub levels with multiple actions in them. Each level item would trigger to rebuild the presented document collection via Java (perhaps more common known as a faceted search).

dijitTitlePane

Since we are using the Extension Library I took a look at the controls but I could not find one that fulfills my requirements (accordion, dojo accordion pane, dojo tab pane, outline). To prevent to embed “another” Jquery plugin I looked across the Dojo site and found the titlePane dijit.

A TitlePane is a pane that can be opened or collapsed, with a title on top. The visibility of the pane’s contents is toggled by activating an arrow “button” on the title bar via the mouse or keyboard. It extends ContentPane but since it isn’t used inside other layout widgets it’s not in the dijit.layout module.

To be honest I am not a Dojo warrior and mostly are satisfied with jQuery plugins but this sounded like something that I could use. For now I only have to menu sections to collapse; a KPI section and a Filter section. Each section has there level 1 and level 2 items.

Since the application works as much as possible with partial refresh and each filtering affects the content of these 2 sections I also needed to save the state of the panes (open or closed). This sounded like a combination of client (open / close the pane) and server side (save the state in a scope variable) actions. Hmmm. From day 1 I have found this mixture of CSJS and SSJS a problem child which you tend to forget/mess up. I decided to implement the approach Oliver Busse promotes in the following post “Writing and reading scoped variables via client side Javascript“. This approach probably makes the code less cluttered with mixture of languages.

I also noticed that the titlePane dijit is not error-proof implemented in the Bootstrap4XPages project in the Extension Library but I found a fix described in the post “fix for down caret icon in dijit.TitlePane when using Bootstrap from ExtLib“. I got a response from Brian Gleeson (IBM): A fix for the dijit.TitlePane issue has been delivered, and should show up in the next Extension Library release. Great & thank you Brian!

So having conquered the circumstances described above what became the result and how did I implement it?

Result

Let’s start with the result:

menu01

Image 1: first section opened.

menu2

Image 2: both sections opened.

Implementation

Each of the KPI and Filter item (can) have sub levels with different presentation and functionality which I will not describe for simplicity reasons.

dijitTitlePane

The titlePane dijit is not so hard to implement. Add the dojo module to your resources:

<xp:this.resources>
<xp:dojoModule name=”dijit.TitlePane”></xp:dojoModule>
</xp:this.resources>

Next add a div to your XPage and set the dojoType and title property. The mat-card styleclass provides a material design presentation.

Attributes

Also define custom attributes for open and toggleble for the div element. These are properties of the titlepane dijit.

Event handler

The event handler checks the state of the pane and writes the state to a scoped variable when the title section of the pane is clicked. For a complete description how to implement Oliver Busse’s utility I would like to direct you to his site.

<xp:div
id=”titlePaneKPI”  dojoType=”dijit.TitlePane” title=”Sales KPI”  styleClass=”mat-card”>
<xp:this.attrs>
<xp:attr name=”open” value=”false”></xp:attr>
<xp:attr name=”toggleable” value=”true”></xp:attr>
</xp:this.attrs>
<xp:eventHandler event=”onclick” submit=”false”>
<xp:this.script><![CDATA[var KPI = dojo.dijit.byId(“#{id:titlePaneKPI}”);
if (KPI.open){
setScopeValue(“view”, “MenuKPI”, “1”);
}
else{
setScopeValue(“view”, “MenuKPI”, “0”);
}]]></xp:this.script>
</xp:eventHandler>

</xp:div><!– /dijit.TitlePane –>

Odd behaviour

I also noticed a strange behaviour of the titlePane. At start I had multiple controls on my xpage to see their differences and capabilities. When I removed the Dojo Accordion Pane the carets for the dijitPane behaved odd:

menuodd

Note the plus (+) and minus (-) signs after the caret :-?

So in front of the TitlePane dijit divs I placed a Dojo Accordion Pane and set the display style property to none (via a styleclass):

<xe:djAccordionPane id=”djAccordionPane1″

styleClass=”paneAccordian”>
</xe:djAccordionPane>

titlePane content

The content of the titlepane can be anything, in my case via a repeat controls a list group with list-group-items is generated.

  • Lead Flow

    <!– /col-xs-12 col-sm-12 col-md-12 col-lg-12 –>
    </div><!– /row –>

    Qualified Opportunities

    <!–/col-xs-12 col-sm-12 col-md-12 col-lg-12 –>
    </div><!– /row –>

    </div><!–/list-group–>

  • Personally I find it a good practice to comment the closure of elements, especially when using Bootstrap nowadays.

    Event handler when loading the page/custom control

    The last thing to include is an event handler that opens or closes the titlePane dijits depending on their last states that are stored in scoped variables.

    I placed the event handler on the custom control where the titlepanes reside in so it gets initiated every time a partial refresh takes place for the custom control.

    <xp:eventHandler event=”onClientLoad” submit=”false”>
    <xp:this.script><![CDATA[function getMenuState(){
    var KPI = dojo.byId(“#{id:titlePaneKPI}”);
    var Filter = dojo.byId(“#{id:titlePaneFilter}”);
    var KPI_status = getScopeValue(“view”, “MenuKPI”);
    var Filter_status = getScopeValue(“view”, “MenuFilter”);
    if(KPI_status==”1″){
    dijit.byId(“#{id:titlePaneKPI}”).set(‘open’,true);
    }
    if(Filter_status==”1″){
    dijit.byId(“#{id:titlePaneFilter}”).set(‘open’,true);
    }
    }
    getMenuState();]]></xp:this.script>
    </xp:eventHandler>

    I was not able to store the function in a CSJS library because it kept telling me then that dojo could not find any note to act upon, but this is probably due to my lack of guru knowledge of Dojo.

    Wrap up

    That is about it! With little programming and a couple of hordes I managed to apply a menu with a consistent state when performing partial refreshes!

    I am looking forward to hear what alternative solutions you have produced, perhaps they can serve me in the future. Happy coding!