XPages hack – visualizing checkboxes that fail validation

In an application I have added some CSS to highlight fields that fail validation. The css looks as followed:

Basically I an looking for the aria-invalid=true attribute on input elements. Works great but not on all input elements. For example re-styling of checkboxes requires some work. But what if you would re-style the element that contains the checkbox?

In the following example I have captured a checkbox control inside a table data cell of 1% width:

For the checkbox control I have defined a custom validator that gets only triggered when a certain element send the xpage to the server (an button control with id btnSendToCommittee)). When the validation fails the checkbox also gets the aria-invalid=true attribute.

To apply a visual indication if a certain checkbox fails I have setup a simple JS function:

This function scans the page for inputs with the aria-invalid=true attribute and for all matches checks if the found item is a checkbox. If so, the parent, containing element (the table data cell) will be applied some styling.

Besides a listing in the xp:messages control I also have a visual indicator for the checkbox on the location of the xpage:

I have not managed to write a single-line css selector therefor I still loop through the found inputs that match the aria-invalid=true attribute. Here your assistance comes in… 😉

Happy coding!

Sticky headers in Bootstrap from ExtLib

I received a request from a customer who would like to preserve the action buttons on an xpage when the user scrolls downs a very long form.

The application is already using the BS theme from the Extension Library with the sticky navbar option in use so this would implement a second ‘sticky element’.

Here is an example how the xpage looks like:

Note: I added some Lorem Ipsum content in stead of form elements for demo purpose, but you get the idea of a endless form to fill in.

So first I added a listener for the scroll event:

window.onscroll = function() {scrollFunction()};

The scrollFunction is as followed:

function scrollFunction() {
if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {
console.log('make SMALL')
$('.navbar').css({
'min-height': '32px',
'height': '32px'
});
$('.navbar-brand').css({
'height': '32px',
'padding-top': '5px',
'padding-bottom': '5px'
});
$('.navbar-nav > li > a').css({
'padding-top': '5px',
'padding-bottom': '5px'
});
$('#infoLanguage > div.dropdown').css({
'padding': '5px 5px'
});
$('#form-header').css({
'display': 'block',
'z-index': '-1'
});
$('#form-header-hidden').css({
'display': 'block',
'position': 'fixed',
'top': '30px',
'height': '30px',
'z-index': '996'
});
$('navbar').addClass('shrink');
} else {
console.log('make LARGE')
$('.navbar').css({
'min-height': '50px',
'height': '50px'
});
$('.navbar-brand').css({
'height': '50px',
'padding-top': '15px',
'padding-bottom': '15px'
});
$('.navbar-nav > li > a').css({
'padding-top': '15px',
'padding-bottom': '15px'
});
$('#infoLanguage > div.dropdown').css({
'padding': '15px 10px'
});
$('#form-header').css({
'display': 'block'
});
$('#form-header-hidden').css({
'display': 'none',
'position': 'fixed',
'top': '0px',
'height': '30px',
'z-index': '0'
});
$('navbar').removeClass('shrink');
}
}

I also added some additional styling for style and transition effects:

<style> 
	#form-header-hidden{ 
	width:100%; 
	background-color:white; 
	height:0px; 
	padding:5px 150px; 
	box-shadow: 0px 3px 5px 0px rgba(182,182,182,0.75); 
	transition: all 0s, opacity 0.5s linear;
} 

#form-header{ 
	transition: all 0s, opacity 0.5s linear;
}

.navbar{
	transition: all 0.5s;
}
.navbar-brand img{
    transition: all 0.5s;
}
</style>

So I basically make 2 form-header elements, on for ‘normal’ display when focus is on the top and one when the user starts to scroll down from a certain point. The form elements are basically the same but more adapted on the height of their container.

One thing I would like to note is that I had to place the ‘smaller’ sticky header under the navbar so it can inherit the same with as its parent. Otherwise I would look not nice with a bit of displacement.

I also noted a small shaking effect when I would use the visibility option to show/hide which form-header to display. Choosing here to play mess with the z-index property solves that issue with shaking when scrolling slowly in the beginning.

Here is the result when the user starts to scroll down. The form header becomes small but sticky under the navbar. The buttons to interact with the form are available where ever the user is in the form:

A small new feature in the app but I think it will bring a lot of user satisfaction! Happy coding 🙂

Quick responsive type-ahead function

For an XPages form I needed a workaround for a combobox with a large data-set. At first I tried the select2 jQuery plugin so I could also have a filter option as some form of type-ahead. However it turned out that my select2 list became quiet unresponsive when an entry far in the list was selected (generating the list and filtering was fine).

So my next option was to go for a type-ahead approach. First hit on Google was a NotesIn9 vid about a fancy type based upon the original post of Tim Tripcony (hello 2009).

Due to the large data-set instead of the getAllEntriesByKey method I decided to go for a getEntryByKey method and from the found view entry continue with createViewNavFrom. This turned out to be extremely responsive!

Further I noticed in the original code a hash object is used so that does not guaranteed me a correct order of my result list so I added an additional array, just for a returning a list with correct sort order.

I like especially in this approach the option to control the returned markup so think here about Bootstrap Media object lists. And of course the ease to set the value that you want to have returned in the edit box.

This is not my first blog-post on delivering search function to your application so now you have just another solution available for your toolbox.

The script is available as a gist.

Happy development =)

 

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 !

 

Adding a Dojo tooltip to your XPages valuepicker

Here is a simple usability tip.

In some corporate organizations not all members are acquainted with modern, modest UI. For those an icon does not always tell them that an action lies underneath it.

For example the value picker from the Extension Library offers you a nice magnifier icon out of the box (which you can set to a custom icon in case desired). If you want to help your senior colleague that there lies no danger beneath clicking that icon you could provide an alternative tooltip for it.

Here is some sample code how you could do this:

<section class=”container”>
<div class=”row”>
<div class=”col-sm-1″><label for=”exampleInputName2″>Name</label></div>
<div class=”col-sm-2″><xp:inputText id=”inputText1″></xp:inputText></div>
<div class=”col-sm-9″>
<span id=”valuePickerTooltip”>
<xe:valuePicker id=”valuePicker1″ for=”inputText1″>
<xe:this.dataProvider>
<xe:dominoViewValuePicker databaseName=”FakeNames40K.nsf”
viewName=”People”>
</xe:dominoViewValuePicker>
</xe:this.dataProvider>
</xe:valuePicker>
</span>
<xe:tooltip id=”tooltip1″ for=”valuePickerTooltip”
label=”Pick a Person from the Address Book” position=”after”>
</xe:tooltip>
</div>
</div>
<div class=”row”>
<div class=”col-sm-9 col-sm-offset-1″><button type=”submit” class=”btn btn-primary”>Send invitation</button>
</div>
</div>
</section>

As a result the user will be presented something as followed when hovering over that icon:

tooltip

Breadcrumbs from Notes view in Twitter Bootstrap (with XPages)

Long long long time ago I wrote how to create breadcrumbs in Notes and on the Web with help of JQuery. In case you are interested using Twitter Bootstrap with XPages chances are you want to provide similar navigational options for your beloved users.

The code below demonstrates how to achieve this.

<xp:this.data>
<xp:dominoDocument var=”currentDocument” formName=”Document”></xp:dominoDocument>
</xp:this.data>

<xp:text escape=”false” id=”computedField1″
value=”#{javascript:getBreadCrumb()}”>
</xp:text>

and the SSJS function looks like:

function getBreadCrumb(){
var nav:NotesViewNavigator = database.getView(“$v-treeview”).createViewNav();
var doc:NotesDocument = currentDocument.getDocument();
if (nav.gotoEntry(doc)) {
var entry:NotesViewEntry = nav.getCurrent();
var list = “”;
list = “<li>” + entry.getColumnValues().elementAt(1).toString() + “</li>” + list;
while (nav.gotoParent(entry)){
entry = nav.getCurrent();
list = “<li>” + entry.getColumnValues().elementAt(1).toString() + “<span class=\”divider\”>/</span></li>” + list;
}
return “<ul class=\”breadcrumb\”>” + list + “</ul>”;
}
return “no docs found”
}

The Notes view $v-treeview has already href references in the column where I collect the information from:

notes view

Don’t forget to set the Display options for Web for the form. I select the form that contains the computed text that calls the getBreadCrumb() function.

Here is how the view looks like in the browser:

Notes view for web

And here the result when I open a document:

breadcrumb tb

Please leave a note when you have suggestions for improvement OR if you have code to put view info into a nav list to create a collapsible menu.

Job Wanted

Looking for a creative brain? Choose me!

job-wanted