URL references in XPages

Aaaah URL references, I guess everyone with Domino and XPages have struggled with them. At first you think you have tackled them, but then you open your app from another perspective (e.g. web browser launch – open designated xpage) and you discover the references did no work like you thought they would.

So how do they work? I made an xpage to demonstrate their working:

url-references

I made 6 types of references:

/.ibmxspres/domino -> this brings me back to the root of the server (or data directory)

/.ibmxspres/global -> this brings me to the folder domjava/xsp/ on the server. This is where for example server-side themes are installed

/.ibmxspres/dojoroot -> this brings me back to the folder /xsp/.ibmxspres/dojoroot-1.9.7/ on the server. This is the installation folder of dojo.

/ -> this brings me to the root of the nsf (when standing on an xpage ofcourse).

./ -> this brings me also to the root of my nsf.

../ -> a step to much, the filename is cut off, so I am standing in the installation folder of my nsf.

Can you fix the broken ones? Ofcourse:

/.ibmxspres/domino -> compute: return “/.ibmxspres/domino/” + database.getFilePath() + “/” + the resource where you want to point to.

/.ibmxspres/global -> compute: “/.ibmxspres/global/” + “../../” + database.getFilePath() + “/” + the resource where you want to point to.

/.ibmxspres/dojoroot -> compute: “/.ibmxspres/dojoroot/” + “../../../” + database.getFilePath() + “/” + the resource where you want to point to.

../ -> “../” + database.getFileName() + “/” + the resource where you want to point to.

If you have a custom stylesheet called custom.css in your nsf you can refer to it in a Theme design element as followed:

<resource>
<content-type>text/css</content-type>
<href>/.ibmxspres/domino/css/custom.css</href>
</resource>

I made the sample available on Github. Hopefully next time I do not make the same mistakes with URL references. Happy development =)

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 !

 

 

Reading files stored in the NSF webcontent folder

In an XPages application I am creating presentations (openxml presentations is perhaps a more correct defintion I guess).

Since I would like to use the template for house-styling I have to read it in from somewhere and use it in my code. I do not want to go for the option to read it from a server location, so after a while I ran into Sven Hasselbach’s NAPIUtils class available on GitHub.

If you search a bit further I found this handy description on Notesin9 how to add the lwpd.domino.napi.jar file to the build path of your application, which is required.

What the NAPIUtils class makes possible is to read files that reside inside your NSF e.g. the webcontent folder.

Just call something like

var fileIn:java.io.FileInputStream = NAPIUtils.loadBinaryFile(database.getServer(),database.getFilePath(),”your_file_in_webcontent_folder.correctextension”)

And you have a your file in a FileInputStream!

In my case I am using

var inputstream = NAPIUtils.loadBinaryFile(database.getServer(),database.getFilePath(),”Duffbeers.pptx”);
var ppt: XMLSlideShow = new XMLSlideShow(inputstream);

And I have my presentation template residing in my NSF in my XMLSlideshow object =)

So no more hustling and asking your administrators for a folder on your Domino server to read/write to.

Ofcourse, they probably have to change the java security settings, but that is another discussion.😕

In some cases you do not want users to have access directly to an URL of a resource. In such cases you could read the file in and write it out in the browser. E.g.:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core”&gt;
<xp:this.beforeRenderResponse><![CDATA[#{javascript:importPackage( ch.hasselba.napi );

var exCon = facesContext.getExternalContext();
var response = exCon.getResponse();
var out = response.getOutputStream();
try {
response.setContentType(“application/octet-stream”);
response.setHeader(“Content-Disposition”,”attachment;filename=cv_patrick_kwinten.pdf”);
response.setHeader(“Cache-Control”, “no-cache”);
var fileIn:java.io.FileInputStream = NAPIUtils.loadBinaryFile(database.getServer(),database.getFilePath(),”Patrick_Kwinten_visualcv_resume.pdf”)
var buffer = new byte[10000];
var len;
while ((len = fileIn.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
} catch (e) {
// some basic error logging here…
} finally {
if (fileIn != null) {
fileIn.close();
}
if (out != null) {
out.close();
}
facesContext.responseComplete();
}}]]></xp:this.beforeRenderResponse>
</xp:view>

Happy development =)

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 !

Build JSON from NotesView, support for multiple value fields

The problem

An old-fashioned NotesView can be a fast way to define JSON objects. Here is a xsnippet that give you some inpsiration.

If you have fields with multiple values then the formula does not work anymore. You want to store an array in the JSON.

The fix

The following formula checks if the desired output fields contains more than 1 value  and if so transforms it to an array if not, then you get a normal key:value pair returned.

_fld:=”refName”:”refSub”:”refStrength”:”refWeakness”;

json:=””;

@For(n :=1; n<=@Elements(_fld); n:= n + 1;

@If(
@Elements(
@GetField(_fld[n])
)>1;
json := json + @Transform ( _fld[n]; “_fn” ; “\”” + _fn + “\”:”) + “[” + @Implode(@Transform( @GetField(_fld[n]) ; “_fn” ; “\”” + _fn + “\”” ) ; “,”) + “],” ;
json := json +
@Transform (
_fld[n]; “_fn” ; “\”” + _fn + “\”:\”” + @Text ( @GetField ( _fn) ) + “\”” + “,”)
)
);
“{ \”unid\”:\””
+@Text(@DocumentUniqueID)+”\”,” + @LeftBack(json;1) + + “}”

Test

I added my formula to a column and calling several single and multiple text fields. Here is my output in a browser:

notesview-as-json

If I validate the json it says it is valid:

valid-json

I added my code to the XSnippets database.

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 !

User Information class

For a project I needed to check which rights a user has in a database and on documents. The UserBean in the Extension Library did not seem to match my needs since that the rights of the current effective user against the database from which the code is called. In my case the documents reside in different databases than the one serving the Xpages.

Second stop was the UserBean class written by Oliver Busse. This allows me to change the effective username againt a given name.

Name name = session.createName(“a string here”);

The same principle goes for the database.

this.aclLevel = session.getDatabase(“a string here”,”a string here”).queryAccess(this.userNameCanonical);

The aclPriviliges are no part of the original code so I added something as followed:

public final List<String> aclPriviliges = new ArrayList<String>();

if ((accPriv & db.DBACL_CREATE_DOCS) > 0){
if (!aclPriviliges.contains(“DBACL_CREATE_DOCS”)){
aclPriviliges.add(“DBACL_CREATE_DOCS”);
}
}
if ((accPriv & db.DBACL_DELETE_DOCS) > 0){
if (!aclPriviliges.contains(“DBACL_DELETE_DOCS”)){
aclPriviliges.add(“DBACL_DELETE_DOCS”);
}
}

I registered my class as a Managed Bean and I invoke it from the beforepageload event:

<xp:this.beforePageLoad><![CDATA[#{javascript:UserInfo.init(“location of my nsf”,”Ja user name here”);}]]></xp:this.beforePageLoad>

With this I can use it in the same way Oliver demonstrated in his snippet. But I can also check the acl Priviliges:

<xp:div>
<xp:label value=”ACL Priviliges:”></xp:label> 
<xp:label value=”#{javascript:UserInfo.aclPriviliges}”></xp:label>
</xp:div>

Next I wanted to check if a user can edit a document or not. This is not that easy as it might seem. This code is what I took as starting-point. It became this piece of code:

public boolean canEdit(String docId){
boolean canEdit = false;
NotesContext ctx = new NotesContext(null).getCurrent();
Session session = null;
session = getCurrentSession();
try {
Database db = session.getDatabase(“”, this.activeDb);
Document doc = db.getDocumentByUNID(docId);
if(null != doc){
canEdit = ctx.isDocEditable(doc);
}
} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return canEdit;
}

Unfortunately I cannot set the username, so it runs against against the effective username😦

I tried to achieve the same functionality with the lock function for documents (which you have to enable on database level) but it fails. Even a given user with Reader access was able to lock a document (name added to $Writers field)

public boolean canWriteDocument(String docId, String userName) {
boolean canWrite = false;
Session session = null;
session = getCurrentSession();
try {
Database db = session.getDatabase(“”, this.activeDb);
if (db.isDocumentLockingEnabled()) {
//Document locking is enabled
Document doc = db.getDocumentByUNID(docId);
if (null != doc){
if (doc.lock(userName)) {
canWrite = true;
doc.unlock();
}
}

} else {
//Document locking is NOT enabled
}

} catch (NotesException e) {
// fail silently
e.printStackTrace();
}
return canWrite;
}

I assume I am doing something wrong but I am not sure what. If you happen to know what then drop a comment.

Happy development🙂

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 !

A modern commenting view in XPages

Introduction

In the old days you a typical commenting feature was something with a form and a view. Typically you could read a list of comments in a historical (flat) order and on the bottom you had the form to enter your comment. Something like in the IBM Domino blog template.

domino-blog

With the rise of social and mobile it became more important to be able to comment-only so the form moved to the top and the list of comments became sorted in the opposite order (Youtube).

Discussions are still displayed in a thread but since threads are less friendly on a mobile device a more what’app like chat display. But these are more instant messaging apps, similar to Slack or IBM’s upcoming Toscana.

slack

My idea: welcome to the bubble

So what can/should we do to modernize the display of the comment feature in our Notes/XPages application?

Well mainly we still have a top level object (TLO) where people comment on. To stimulate people to comment the form should be close to this TLO. We can promote the interaction between a user and others and provide some form of “bubble speech” experience and (ofcourse) the option to “like” a comment.

That would bring us to something more like this:

social_comment

 

Notice on the left you see the comments I have made and on the right comments made by others. The latest comment is displayed first and mines are a bit more outstanding using a background-color.

Now how it’s made

To come to this solutions I am using the following technologies:

  • XPages
  • Java
  • SSJS
  • Bootstrap
  • PrettyTime
  • CSS
  • JavaScript / mention JS

Note that in a previous post I described how to add @mention autocomplete like Facebook, Twitter & Google+ to your XPages app. So I will not discuss in this post how to build the form to comment.

Here is a general outline of what we are going to build:

outline

Step 1 – basic structure; a repeater with a panel

step01

First I have a repeat control which is bound to an ArrayList containing JsonObjects. This approach you can find in my Bildr project on OpenNTF (shameless plug).

I also added an infinite scroll function. You can read about how to set that up in this post.

The panel has a computed styleclass. The style defintion “right” does nothing more than a  text-align: right. This makes sure the text in the content is … aligned right.

Step 2 – adding a user icon

Humans are visually oriented and idle so nothing wrong making our display attractive with a user icon.

step02

In this example I am just displaying some random icons, but if you have a corporate directory with user profiles containing icons you should embed them here.

The pull-left and pull-right classes are from Bootstrap. My comments are pulled to the left, comments from others to the right.

Step 3 – the media body

Next item that we add is a div with a media-body class. It contains out of 2 sections: the content of the comment (text written) and some meta-data (date, author). I also added a “like” link which is inspired by Thomas Adrian’s Intrapages app also available on OpenNTF.

step03

(Guess I don’t need the attributes here…). Here is the part of the meta-data:

step03b

First I display the Author name, only for comments written by others. In order to make the date more human friendly to read I am using PrettyTime. In the past I have blogged about how to use it.

For the remove link I am using the userbean to check if I can delete documents in the database and if the comment is mine: (@UserName() == obj.From) && (userBean.canDeleteDocs == true)

For the event I check and ask if I am sure that I want to remove the entry and then I simply remove it by UNID:

step03c

For the “like” button I would like to point to Adrian’s example in his Intrapages project. I made however the exeption to store the likes in a separate document, so not in the comment. By this way I can tighten my security model. Everybody has the role of [liker] and author access. So everybody can update a like document and not the original comment document.

The like function uses the cookie management principles described here. It stores the username:

userCookie = new javax.servlet.http.Cookie(“userid”, @UserName());

I have set the duration of the cookie as long as the session is active:

//Cookie.setMaxAge(-1) will make the cookie expire after the browser is closed
userCookie.setMaxAge(-1);

But beware that the cookie still exists when users logout and login with a different username-password combination !!

So I have a counter for the number of likes, and depending on my activity I have a like or unlike link.

Ready! Some CSS whistles

After we have added some more (basic) CSS we are done! As a result we have created something much more modern that the old school comments display as we know from the IBM Domino Blog template.

If you are interested and want to receive the details of this setup I welcome you to send me a message and we can exchange code.

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 !

 

DevTip: using the latest font-awesome CSS toolkit in your XPages application

Tired off or you feel restricted by the Bootstrap Glyphicons? I bet you do. So you fancy to use Font-awesome as addition? Excellent choice. But after you have added them to your web-content folder and place them on an XPage you will notice the desired font does not appear.

Luckily for you other people have bumped into this before and allocated the problem and come with a fix.

So now you started to load the libraries your XPage application is depending on into ODP/NSF by using Bower or another package manager. If you do not specify a specific version but go for “latest” you will notice that in the suggested fix a version is specified for the font, so which each new release (which you are not aware of due to the “latest” option) your fix is out of sync.

CDN to the resque you might think. Since they handle the URL complication you are good to go as a consumer. Try to add a style sheet resource to an XPage without the http/https protocol is not allowed. If you modified it by hand in the source code like:

href=”//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.css”

in the browser something as

link rel=”stylesheet” type=”text/css” href=”/apps/customerx/fontawesomecdn.nsf//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.css”

will be produced which won’t work. You can add the protocol only once and you can not make the protocol conditional here.

Themes to the rescue! In a Theme design element you can check against what scheme the application runs and if so go for the corresponding protocol:

<theme>
<!– FontAwesome –>
<resource rendered=”#{javascript:context.getUrl().getScheme().equals(‘http’)}”>
<content-type>text/css</content-type>
<href>http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css</href&gt;
</resource>
<resource rendered=”#{javascript:context.getUrl().getScheme().equals(‘https’)}”>
<content-type>text/css</content-type>
<href>https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css</href&gt;
</resource>
</theme>

Here I have choosen to go against maxcdn which provides a “latest” option. If I check in the browser if delivers me

/*!
* Font Awesome 4.6.3 by @davegandy – http://fontawesome.io – @fontawesome
* License – http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/

Summary: problem solved.

  • I have the latest version of font-awesome
  • I have not an URL problem
  • I respect the protocol my application runs under

Unfortunately, my library is gone from my package manager file.

If you have a better suggestion then please drop a comment here below.

Update – Use Grunt

After writing this post I thought that their might be customers who block CDN resources. What to do then?

In Brad Ballasaitis example he created an additional CSS to overwrite the default font-family specification, one without the URL ?v= parameter.

In case you use a tool like Bower to download and install 3rd party libraries or plugins the original CSS with the URL ?=v parameter will be installed. You could write a simple Grunt task (I am new to this) that picks up your custom font-family CSS file from a temporary (fixes?) directory and copy it into the font-awesome CSS directory. A simple example would be:

/*
Copy font-awesome fix
Author Patrick Kwinten
All rights reserved
*/
‘use strict’;

module.exports = function (grunt) {

    require(‘load-grunt-tasks’)(grunt);
grunt.initConfig({
copy: {
main: {
src: ‘fixes/font-awesome-fontFamily.css’,
dest: ‘WebContent/libs/font-awesome/css/font-awesome-fontFamily.css’,
options: {
process: function (content, srcpath) {
return content;
},
},
},
}
});
};

If you run this task you are back to a state where you can now overwrite the default font-family selector again.

Load the CSS files via a Theme design element e.g.:

<!–
Not the following is not working in conjuction with the
XSP Property ‘runtime optimized resources’.

Therefor the following workaround is applied:
– Move the @font-face part into 2 new CSS e.g.
./font-awesome/css/font-awesome-fontFamily.css
./font-awesome/css/font-awesome-fontFamily.min.css

Note the paths to the fonts differ in these files.

– Load 1 of the css via the Theme based upon the context.getProperty(‘xsp.resources.aggregate’) property
–>
<resource rendered=”#{javascript:context.getProperty(‘xsp.resources.aggregate’).equals(‘false’)}”>
<content-type>text/css</content-type>
<href>font-awesome/css/font-awesome-fontFamily.css</href>
</resource>
<resource rendered=”#{javascript:context.getProperty(‘xsp.resources.aggregate’).equals(‘true’)}”>
<content-type>text/css</content-type>
<href>font-awesome/css/font-awesome-fontFamily.min.css</href>
</resource>
<resource>
<content-type>text/css</content-type>
<href>font-awesome/css/font-awesome.min.css</href>
</resource>

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 !

OpenNTF: New release Bildr

Yesterday I added a new release of my Bildr project on OpenNTF. I do not know how many applications you know for IBM Notes who enables you to share pictures across your organisation?

Some use-cases I have heard off:

  • Product showcase
  • Organizational events
  • Trade shows
  • Team building (sharing private pictures)

The applications allows you to (multi) upload images, group them in albums or categories, comment on them, …

In a previous release there was the option to tag images. I will bring that option back in a later version. Rating could be a nice feature too. We’ll see how much time I have available.

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 !

Uncategorized