A generic approach to display Notes data via a Bootstrap table

This week I became inspired by a question I noticed on Stackoverflow regarding collecting values from Java objects.

For a project we were discussing what to use for display “Notes View data”:

  • jQuery DataTables plugin and use a customRestService via a Java class as data provider for the JSON.
  • a Repeat control and display an Arraylist of Java objects.

Some of the participants liked the jQuery approach because it provides a lot of functionality out of the box (sorting, search, responsiveness,…) and their lack in knowledge regarding Java.

Others were questioning of the Repeat control approach would be flexible enough so we could display easy different sets of data with different number of columns.

So… to the drawing board.

Mostly in Notes views (e.g. via the View Panel control) one column serves as link (often the first) and all others just display data of all kind. In the DataTables plugin the display is flexible because you can define a custom render function for each column which is great. So you could display a button that will call a dialog to interact with the underlying document for example. However this custom render definition resides in a CSJS library so becomes part of the design.

I had already a custom control that could consume properties for the data and how to set a fixed set of columns. So the last part I needed to make flexible.

Because I have an arraylist of Java objects as source for my Repeat control I need to access the fields “on the fly” when rendering the column values. This turned out to be quiet simple because the fields are already in my Java object.

In my approach I provide the columns via a JSON object that could look as followed:

dyntable00

 

And for my columns I repeat it and collect the value from my underlying Java object:

dyntable01

Note: my code is not final, I would to define more types of data and the option to provide a custom render function for each column. So far I only have computation for string and date fields.

I also applied some basic functionality as Pager controls (top + bottom), a Page Sizer control, icon display and row numbering.

Here is what a result might look like:

dyntable001

Nothing special but now now I have just one custom control to display 80% of my tables/views.

Here are the GIST files for the custom control and its configuration xml file.

IBM Champion Nomination

Is this blog-article useful to you? Perhaps you can nominate me as IBM Champion.

Advertisements

Using the beanNamePicker dataProvider for a namepicker

For an application I needed to provide a namepicker with data from a NotesView. Unfortunately I could not use the default dominoViewNamePicker option as the data provider because the column to select from may not be a multi-value field or contain multiple fields. 😕

A search on google provided me an example how to use a beanNamePicker that will read the data from Domino Directories.

I created a GIST for the XPage: https://gist.github.com/PatrickKwinten/0bcc951a8eb1f5ef287c0c9b05a535a3 and for the Java class it uses: https://gist.github.com/PatrickKwinten/4aa15ea09717833bcc9fd1a941d9e5a8 .

Basically here is how you set it up:

<xe:namePicker id=”npDomino” for=”person1″>
<xe:this.dataProvider>
<xe:beanNamePicker dataBean=”org.wordpress.quintessens.demo.app.NamePickerDirectory”
loaded=”true”>
</xe:beanNamePicker>
</xe:this.dataProvider>
</xe:namePicker>

Key is that you return an object of type SimplePickerResult containing a list of objects of type <IPickerEntry>.

For my case I needed to go to a view where all the activities for users for the application where logged. Again I used a similar setup:

<xe:namePicker id=”npDomino” for=”person1″>
<xe:this.dataProvider>
<xe:beanNamePicker dataBean=”org.wordpress.quintessens.demo.app.NamePickerView”
loaded=”true”>
</xe:beanNamePicker>
</xe:this.dataProvider>
</xe:namePicker>

But now I go to a different class which I created a Gist for: https://gist.github.com/PatrickKwinten/c3580344a48704b3589251c0d5bbb8e5 .

Key difference is that my data source has become a Notes view and I check the type of column (columnValue instanceof String, ArrayList, Vector) because I have different type of fields and values in my first column.

So once you understand how you can extend the basic functionality within XPages you gain much flexibility and new opportunities with out of the box controls.

Please IBM provide us with more examples!!!

IBM Champion Nomination

Is this blog-article useful to you? Perhaps you can nominate me as IBM Champion.

 

 

Java and XPages

I still meet Domino developers who want to use XPages in the way IBM told them how to use it. Completely wrong I would say. Now that you have to chance to learn Java skills – EMBRACE IT!

Okay the other way around is sometimes a pain in the ass and complete examples are scarce but it gives you a better way to control your application and it’s behavior. After a while you get better understanding of the underlying technique and there is nothing wrong with that.

At the end it is mostly about creating, reading, updating and deleting stuff.

So for those developers I have setup a simple presentation to get a better understanding of JSF, Java and XPages:

Send a message from your XPage application to a Slack channel

Introduction

While everyone is ‘waiting in vain’ for the delivery of Project Toscana organizations have start using Slack as a modern way to send messages within departments.

For an example a operation team is using an instructions quality book build on XPages and it would be great to get notified in your Slack channel when new instructions come in or have been updated. Or you want to highlight a specific instruction just to create extra attention to it (e.g. an increasing number of incoming incidents).

slack_sample

Be creative with use-cases 🙂

Slack integration points

Incoming Webhooks are a simple way to post messages from external sources into Slack. They make use of normal HTTP requests with a JSON payload, which includes the message and a few other optional details described later.

JSON, HTTP request… this sounds doable with XPages! So what are the steps you must take?

Setup your integration

Go to http://yourteam.slack.com/apps/build/custom-integration and click on Incoming Webhooks, then select a channel or user you want to post your messages to.

Setup your message

You have two options for sending data to the Webhook URL above:

  • Send a JSON string as the payload parameter in a POST request
  • Send a JSON string as the body of a POST request

Simple message

For a simple message, your JSON payload could contain a text property at minimum. This is the text that will be posted to the channel e.g.:

payload={"text": "This is a line of text in a channel.\nAnd this is another line of text."}

You can decorate your message with text formatting. You will find descriptions in the custom integration page on Slack.

Message attachments

To display a richly-formatted message attachment in Slack, you can use the same JSON payload as above, but add in an attachments array. Each element of this array is a hash containing the following parameters:

{
	"fallback": "Required text summary of the attachment that is shown by clients that understand attachments but choose not to show them.",

	"text": "Optional text that should appear within the attachment",
	"pretext": "Optional text that should appear above the formatted data",

	"color": "#36a64f", // Can either be one of 'good', 'warning', 'danger', or any hex color code

	// Fields are displayed in a table on the message
	"fields": [
		{
			"title": "Required Field Title", // The title may not contain markup and will be escaped for you
			"value": "Text value of the field. May contain standard message markup and must be escaped as normal. May be multi-line.",
			"short": false // Optional flag indicating whether the `value` is short enough to be displayed side-by-side with other values
		}
	]
}

Send the message

With a simple post request you send the message in JavaScript:

function postMessageToSlack(url){
webhook_url = url;
payload= JSONStr;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', webhook_url, false);
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlhttp.send(payload);
}

XSnippet

This whole approach I have added as an XSnippet on OpenNTF:

https://openntf.org/XSnippets.nsf/snippet.xsp?id=slack-integration

You can customize it to your needs. Basically I have a script block and a button on a custom control. Via the Property Definition tab you can set the desired values. In my example I am sending a message to a Slack channel about a picture / document in my Bildr application (shameless plug).

Here is how the message could look like:

sample_slack_message

Since my XPages app is running on a local development machine it is of no use to send sampel thumbnails of the page, but I could. This also refers to the user icon, which could be the icon of the application.

So grab the snippet and start integrating your XPages with Slack (untill Toscana arrives) !

FYI: I am not aware of any restrictions on the number of message you may send to Slack. Please let me know if you have details on this.

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

 

Using Apache POI to create Presentations from your XPages application

Introduction

Apache POI is perhaps THE Java API for Microsoft Documents, if you do not live in the Microsoft bubble. It inspired people to build the Poi4XPages plugin to easily generate Word and Excel Files out of XPages (using data from Notes documents).

Yeah but Microsoft Office has so many other great types of documents you might think. Take for example PowerPoint presentations. Have you ever met a sales guy without one?

sample_layout

It turns out that it not that hard to use Apache POI to create powerpoint slides. I will describe how you can start developing your own solution in a few steps.

Step 1 – Download and install Apache POI

You have the link so download the library. While I was developing my application a new release (v3.15, September 21) came out so this project is alive an kicking.

I added the following jar files to my webcontent/web-inf/lib folder and added them to the build path so they appear as referenced libraries:

ref_libraries

Step 2 – Write some code

In my application I want to use data that is stored in Notes documents in the presentation slides. I also want to import a template first, so I have some styling for the slides e.g. background image.

Note that I am not a PowerPoint export, so my template might be far from correct. I store the presentation in my NSF so in order to import it into my PPT object I am using Sven Hasselbachs Domino Napi Utility class. For this class I need to add the lwpd.domino.napi.jar file on my Domino server to the build path of my application,

With this in place I could write my Output class:

package org.quintessens;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.Document;

import org.apache.poi.xslf.usermodel.SlideLayout;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFHyperlink;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.apache.poi.xslf.usermodel.XSLFTextShape;

import com.ibm.domino.xsp.module.nsf.NotesContext;
import com.ibm.xsp.webapp.XspHttpServletResponse;

import ch.hasselba.napi.NAPIUtils;

public class Output {

NotesContext nct = NotesContext.getCurrent();
Session session = nct.getCurrentSession();

public void createPptx(String docId) {
System.out.println(docId);
try {

Document doc = session.getCurrentDatabase().getDocumentByUNID(docId);
DateFormat dateFormat = new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”);
Date date = new Date();
System.out.println(dateFormat.format(date));
System.out.println(doc.getUniversalID());

XMLSlideShow ppt;
try {
ppt = new XMLSlideShow( NAPIUtils.loadBinaryFile( session.getServerName(),session.getCurrentDatabase().getFilePath(), “Duffbeers.pptx”));
//System.out.println(ppt.getProperties());
int slideCounter = ppt.getSlides().size();
System.out.println(“contains ” + slideCounter + ” number of slides”);
// first see what slide layouts are available :
System.out.println(“Available slide layouts:”);
for (XSLFSlideMaster master: ppt.getSlideMasters()) {
for (XSLFSlideLayout layout: master.getSlideLayouts()) {
System.out.println(layout.getType());
}
}

XSLFSlideMaster defaultMaster = ppt.getSlideMasters().get(0);
XSLFSlideLayout defaultLayout = defaultMaster.getLayout(SlideLayout.BLANK);

/*
* Add a slide based on TITLE_ONLY layout
*/
defaultLayout = defaultMaster.getLayout(SlideLayout.TITLE_ONLY);
XSLFSlide slide01 = ppt.createSlide(defaultLayout);
XSLFTextShape title01 = slide01.getPlaceholder(0);
title01.setText(doc.getItemValueString(“refName”));

/*
* Add a slide based on TITLE_AND_CONTENT layout
*/
defaultLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
XSLFSlide slide02 = ppt.createSlide(defaultLayout);
XSLFTextShape title02 = slide02.getPlaceholder(0);
title02.setText(“Strength”);
XSLFTextShape body02 = slide02.getPlaceholder(1);
Vector < String > strength = doc.getItemValue(“refStrength”);
for (int i = 0; i < strength.size(); i++) {
body02.addNewTextParagraph().addNewTextRun().setText(strength.get(i));
}

/*
* Add another slide based on TITLE_AND_CONTENT layout
*/
XSLFSlide slide03 = ppt.createSlide(defaultLayout);
XSLFTextShape title03 = slide03.getPlaceholder(0);TutorialsPoint
title03.setText(“Weakness”);
XSLFTextShape body03 = slide03.getPlaceholder(1);
Vector <String> weak = doc.getItemValue(“refWeakness”);
for (int i = 0; i < weak.size(); i++) {
body03.addNewTextParagraph().addNewTextRun().setText(weak.get(i));
}

/*
* Add another slide based on TEXT layout
*/
defaultLayout = defaultMaster.getLayout(SlideLayout.TEXT);
XSLFSlide slide04 = ppt.createSlide(defaultLayout);
XSLFTextShape title04 = slide04.getPlaceholder(0);
title04.setText(“Link(s) of interest”);TutorialsPoint
XSLFTextShape body04 = slide04.getPlaceholder(1);
body04.clearText();

XSLFTextRun textRunLine2 = body04.addNewTextParagraph().addNewTextRun();
textRunLine2.setText(doc.getItemValueString(“refLinkLabel”));
XSLFHyperlink link04 = textRunLine2.createHyperlink();
link04.setAddress(doc.getItemValueString(“refLinkURL”));

// 0-based index of a slide to be removed
for (int i = 0; i < slideCounter; i++) {
ppt.removeSlide(0);
}

String filename = doc.getItemValueString(“refName”) + “.pptx”;

TutorialsPointFacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ex = fc.getExternalContext();
XspHttpServletResponse response = (XspHttpServletResponse) ex.getResponse();

try {
ServletOutputStream writer = response.getOutputStream();
response.setContentType(“application/vnd.openxmlformats-officedocument.presentationml.presentation”);
response.setHeader(“Cache-Control”, “no-cache”);
response.setHeader(“Content-Disposition”, “inline; filename=” + filename);
response.setDateHeader(“Expires”, -1);
ppt.write(writer);
writer.flush();
writer.close();
fc.responseComplete();
} catch (Exception e) {
e.printStackTrace();
}

} catch (NotesException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

doc.recycle();

} catch (NotesException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
}

 

In this example I am creating new 4 slides, with different layouts and content. You can be creative as you like and for example format text and present them as hyperlinks or include images.

Step 3 – Register a managed bean and call the code

With the java class Output written I can register it as a managed bean in the faces-config file:

<managed-bean>
<managed-bean-name>Presentation</managed-bean-name>
<managed-bean-class>org.quintessens.Output</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

This makes it easy to call the code from anywhere. The only think I need to provide is an universal ID of a document:

<xp:button id=”button4″ value=”Download as Presentation” styleClass=”pull-right btn-primary”
style=”margin-right:5px;”><i class=”fa fa-slideshare” aria-hidden=”true”></i>

<xp:eventHandler event=”onclick”
submit=”true” refreshMode=”complete”>
<xp:this.action><![CDATA[#{javascript:Presentation.createPptx(ReferenceController.objectId);}]]></xp:this.action>
</xp:eventHandler>
</xp:button>

In my button the ReferenceController.objectId will provide the universal Id of a Notes document. I am using a controller class to get the value from a document, instead of a DominoDocument data-soruce.

With this in place. We are basically good to go! With just 1 click any sales guy can now create a corporate presentation from a Notes document and start spreading the word!

result

If you want to know more about Apache Poi, Powerpoint files and XPages I am happy to answer your questions. I can also recommend to read the XSLF Cookbook or the Apache Poi PPT tutorial on TutorialsPoint.

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

I Like Bubble Commenting

Strange subject title isn’t?

I have created a repository of my bubble/social speech layout, so if you want to have a closer look and implement it yourself then you are free to go.

I updated the @mention implementation so you get a nice icon in front of the name:

mention20

In order to have icons I updated my LotusScript agent to add a URL to an image in the PhotoURL field of the Person form in the FakeNames.nsf. For now I stored the icons in the NSF but in case you have a directory you use the reference to images from there.

I have also added an updated version to Like/Unlike comments, in stead of SSJS now most of the logic resides in the LikeController class. When you hover over the icon you get a list presented with people who have liked the comment.

likes_hover_icon

Ofcourse nothing is stress-tested but I have not seen major issues so far. I hope you like it and get inspired to modernize your IBM Notes applications !

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

Adding @mention autocomplete like Facebook, Twitter & Google+ to your XPages app

Introduction

For an application I was asked to add a feature to add commenting on main topics. In order to stimulate discussions it should be easy to include people in the stream, similar as in Twitter. So writing an @sign should invoke a type-ahead or auto-complete to a user-list and provide suggested users to address.

In XPages you have type-ahead option, but that is only for inputText controls, not for inputTextArea controls. So how to solve this?

A search after “lightweight wrappers for adding @user mention functionality to Twitter Bootstraps Typeahead plugin” brought me to this library. The provided examples looked promising and were just what I needed, even the option to include a profile icon, similar to IBM Connections Smartcloud.

mention_sample2

Basic setup

I will guide you setting up a basic structure to add “@Mention” to your XPages app and use a REST service to provide a list of users from your directory.

Step 1 – get the resources in

Not that difficult. Just drop the files somewhere (ordered) in your WebContent folder e.g:

mention_impl1

Step 2 – Reference your resources

Next we are going to make these resources available via a Theme design element:mention_impl2

Step 3 – Add an inputTextArea control and bind it to the library

We want to have the @Mention function available to an inputTextArea control so we must not forget to add that to the XPage:

mention_impl3

When the document is ready we want to bind the @Mention library to our inputTexArea. I use the infamous XSnippet “x$ jQuery selector for XPages”. Since we will be using the Bootstrap theme in the Extension Library we have jQuery available:

mention_impl4

Step 4 – Add REST service

Wait, did we just add $.getJSON(‘REST.xsp/users’, function(result)? What does that provide us?

REST.xsp is an XPage that contains a REST service control from the Extension Library. It calls a serviceBean org.quintessens.comments.rest.Users:

mention_impl5

The serviceBean is a simple service that will go to a database and collect column values from a view. In this case I am using the also infamous fakenames NSF but that could be your ordinary Domino Directory (names.nsf)

mention_impl6

If you open your developer tools in your browser you see the service provides as data:

mention_impl7

We have to strip that down with line x$(“#{id:comment}”).mention({users:result.data}).

Since we are also using the bootstrap theme for @Mention the result looks like:

mention_impl8

Splendid! So how is your social application modernization doing?

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

 

Show / hide columns dynamically

To show or hide columns dynamically is a nice feature in the jQuery dataTables component. With a few simple steps you can deliver something similar in your XPages application as I demonstrate in the video.

The technologies used: XPages, Extension Library, Bootstrap.

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

FlipSwitch style for your checkboxes

A flip switch is an alternative look for a checkbox or the two-option select menu. It can be toggled by a click or a swipe.

flipswitchoff

I am not sure if it’s originated from mobile interfaces, at least it is there where they are most common. So if you modernize an application and optimize it for mobile access you might consider adding flip switch behaviour to these form elements.

Here is an example how to do this with XPages:

htmlswith

 

Ofcourse you have to provide the CSS. The CSS depends on your theme. There are handy sites that might help you with it.

Here is my CSS:

.onoffswitch {
position: relative; width: 90px;
-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block; overflow: hidden; cursor: pointer;
border: 2px solid #999999; border-radius: 20px;
}
.onoffswitch-inner {
display: block; width: 200%; margin-left: -100%;
transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
box-sizing: border-box;
}
.onoffswitch-inner:before {
content: “ON”;
padding-left: 10px;
background-color: #34A7C1; color: #FFFFFF;
}
.onoffswitch-inner:after {
content: “OFF”;
padding-right: 10px;
background-color: #EEEEEE; color: #999999;
text-align: right;
}
.onoffswitch-switch {
display: block; width: 18px; margin: 6px;
background: #FFFFFF;
position: absolute; top: 0; bottom: 0;
right: 56px;
border: 2px solid #999999; border-radius: 20px;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 0px;
}

I hope you find this tip useful…

flipswitch

 

Add 20 years of experience to your workforce

 

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !

Draggable modal

For a project a request was to make a Bootstrap modal (a Dialog control in the Extension Library) as draggable. By default, the modal does not have that feature. So can you make it draggable again?

In xsp-mixin stylesheet the class xsp-responsive-modal is using !important for the left and top properties which prevents that the modal is draggable. A work-around can be achieved by replacing these class properties with your own that does not use !important.

To replace the default class add for the onShow event of the dialog:

<xe:this.onShow>
<![CDATA[
x$(“#{id:dialog1}”).removeClass(“xsp-responsive-modal”).addClass(“draggable-responsive-modal”);
]]>
</xe:this.onShow>

Your custom class could look as followed:

.draggable-responsive-modal {
display: block;
width: auto;
left: 0;
top: 0;
z-index: 1050 !important;
}

The x$() function is the infamous utility function from Mark Roden to work with JQuery.

I added the code to GitHub Gist: https://gist.github.com/PatrickKwinten/1d442e28ff0d59f8e01728bffab13e4f

Add 20 years of experience to your workforce

 

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !