Archive | May 2016

XPages Tip: Displaying Bootstrap Applications Properly on Mobile Devices

Do you have a Bootstrap navigation menu in XPages that collapses properly in a full browser but not on a mobile device? You may need to set a meta tag to force it to display properly. In this post, I’ll show the effects with and without the tag on a mobile device.

Navbar Collapsing

One of the great features of Bootstrap is its built-in responsive UI that scales well to work on screens of varying sizes. The navigation bars collapse nicely into the hamburger menus to make better use of available space on smaller devices.

However, in recent testing of an XPages application with a Bootstrap UI, it was noted that the navigation menus did not collapse properly when viewed on a phone. It was a little confusing because it collapsed as expected on a full browser.

When the navigation bar is set up properly, it should collapse properly on its own when the screen width is below 768 px. I verified that there are no CSS rules overruling that cutoff and that 768px is, in fact, the point where the menu collapses on the full browser.

Bootstrap Navbar Test Page

To test it out, I tried out the Bootstrap Navbar test page

On my laptop with a full browser, it showed the navigation normally.

Nav Collapse 1A - Full Browser Over 768px

When I shrunk the screen to be less than 768px wide, it collapsed the navigation properly.

Nav Collapse 1B - Full Browser Under 768px

When I checked it on my phone, it was collapsed properly.

Nav Collapse 1C - Phone - Collapsed

Test Page in XPages

I copied the div that contains the navigation from that test page and pasted into an XPage in my application to see how it worked.

It collapsed as expected in a full browser but not on the phone.

Nav Collapse 2A - Phone - NOT Collapsed in XPages

It is also apparent that the page has been scaled so that it fits fully on the phone.

To verify this, I put a button on the page to tell me the screen width. As expected, it showed a width > 768 px, which is why it did not collapse the menus. It scaled the entire page to fit on the screen, so it did not fall below the threshold of the responsive design media queries.

Nav Collapse 2B - Phone - Screen Width

(This is on a Samsung Galaxy. An iPhone showed it to be roughly 900px.)

And this is just a simple page. Imagine how that looks with a much bigger XPage!

The Difference

Ultimately, the main difference is that the Bootstrap test page contains a meta tag to make sure the device doesn’t shrink to fit the entire page on the screen.

<meta name="viewport" content="width=device-width, initial-scale=1">

In XPages, this can be set at the page level, but it’s easiest to do it application-wide via a theme, within a resources tag.

<resources>
  <metaData>
    <name>viewport</name>
    <content>width=device-width, initial-scale=1.0</content>
  </metaData> 
</resources>

Now, when I reload the Bootstrap test page, it is displayed properly on the phone.

Nav Collapse 3 - Phone - Collapsed in XPages

The button showing the screen with on the phone now shows it to be 360px wide.

Advertisements

Efficiently Keeping an XPages Session Alive with JSON RPC

In my last post, I talked about the difference between two reasons that a user may be prompted to login again while using an XPages application: idle session timeouts and LTPA token expiration. There are a variety of ways to programmatically prevent an browser session from timing out due to inactivity. In this post, I’ll show how to do it with JSON-RPC and why I prefer it to the standard methods.

Keeping the Session Alive

The Keep Session Alive control (xe:keepSessionAlive) in the extension library was designed to make it easy to prevent idle session timeouts; all you have to do is drop the control onto a page and optionally set the refresh period and it will send requests to keep the session alive.

In earlier versions of Notes/Domino, this would not be available without the extension library, which was a limiting factor in many situations. It’s built into version 9+, so it’s more readily available.

Other solutions popped up for those without the extension library (and to work around an earlier bug in the control, including Mark Roden’s XSnippet. In this solution, a timer is set to periodically trigger a partial refresh of an empty div in order to send a request to the server and keep the session alive.

This works well and is easy to add to any application.

However, while it can be set to run very infrequently, the partial refresh is more overhead than necessary. It only refreshes a single empty DIV tag, but it’s still posting the entire form and causing the entire component tree to go through most of the life JSF lifecycle. If the user happens to be viewing the page, the responsiveness may lag due to the synchronous processing and refresh.

Keep Alive 2A - Keep Session Alive XSP partial refresh

(In contrast, the Keep Session Alive control appears to be efficient, sending a GET request and getting a minimal response.)

Keep Alive 2B - Keep Session Alive control

RPC Efficiency

My first thought when looking for a more efficient solution was, at minimum, to use the code to trigger an even that for which I could also enable partial execution (explained really well here by Paul Withers) to limit the scope of the processing to make it much more efficient.

However, in thinking through it further, I realized that it would be even more efficient to use JSON RPC, because the amount of information sent is minimal, the response is minimal, and the request is asynchronous, so it doesn’t have any of the aforementioned issues. (If you’re not familiar with JSON RPC — take a look at the first section of this presentation for more information.)

Without further adieu, here is a solution using JSON RPC.

<xe:jsonRpcService id="jsonRpcService1" serviceName="rpcUserSession">
  <xe:this.methods>
    <xe:remoteMethod name="keepAlive">
      <xe:this.script><![CDATA[return '';]]></xe:this.script>
    </xe:remoteMethod>
  </xe:this.methods>
</xe:jsonRpcService>
	
<xp:eventHandler event="onClientLoad" submit="false">
  <xp:this.script><![CDATA[ setInterval(function(){ console.log('keeping session alive (rpc): ' + new Date()); rpcUserSession.keepAlive(); }, 1500000) ]]></xp:this.script>
</xp:eventHandler>

The first 8 lines simply define an rpc service that has a single method that just returns an empty string.

The last 8 lines are an onClientLoad event handler that set a timer to write a message to the browser console and call the RPC method every 25 minutes.

The request sent to the server is minimal…

Keep Session Alive 2F - RPC Post

… as is the response.

Keep Session Alive 2F - RPC Response

No page processing occurs and the request is asynchronous, so it cannot affect the user.

This can be added to it’s own custom control and then added to your application’s page layout control so it’s available throughout. All you have to do is set the refresh duration, which should be slightly less than the idle session timeout.

Timeout Handling

In addition to being more efficient, this method also has the benefit of failing much more gracefully and also providing the ability to handle the timeout.

In my testing the Keep Session Alive control doesn’t show any error to the user or to the browser console.

The partial refresh method first shows this message…

Keep Session Alive 2C - Partial Refresh Failure

…and then pops up a second error message, saying that there’s no element to submit, along with the client-side ID of the <div> that’s the target of the partial refresh.

Keep Session Alive 2C2- Partial Refresh Failure 2 - No Element to Submit

This is an ugly way to fail.

One of the benefits of the RPC method is that it fails more gracefully AND you can trap the error and handle it however you’d like.

Here’s the error message that is displayed in the browser console when the session ends due to the machine going to sleep:

Keep Session Alive 2D - RPC Post Failure Due to Machine Going to Sleep

A different message is returned when it times out due to the expiration of the LTPA token:

Keep Session Alive 2D2 - RPC Post Failure When Timed Out

The user never gets a message. They would just be prompted to login the next time they tried to run any action on the page that required server interaction.

However, as I described in a previous post, you can handle errors within an RPC call. You could use this to either display a nicer message to the user or redirect to a login page, either of which allows you to handle it much more gracefully.

Browser Session Lifespan – Idle Session Timeout vs LTPA Token Expiration

I recently spent some time investigating a client’s reports of unexpected behavior with the duration of browser sessions while testing an application on a test server. From time to time, they were required to login even while actively using an application. In this post, I’ll highlight the difference between an idle session timeout and an LTPA token expiration, which serve different purposes and, in the latter case, may cause frustration if not understood.

User Expectations

Most users are familiar with the concept of a browser session timing out if left idle for too long. In this case, websites will generally inform the user that a session has expired and require the user to login again in order to continue.

But users will generally not expect to be required to login again while actively using an application, so it’s important to understand why it might happen and what you can do about it.

Idle Session Timeout – Server

The Domino server document has a setting to define how long it will take for the session to be automatically logged out due to inactivity. This is configured on the server document: Internet Protocols... > Domino Web Engine > Idle session time-out

Keep Alive 1A - Server - Idle Session Timeout

The default is 30 minutes.

Idle Session Timeout – Application

There is also an application-level setting for the session timeout, which can be found on the General tab of Xsp Properties.

 

Keep Alive 1B - Application - Idle Session TimeoutThis sets the xsp.session.timeout property.

xsp.session.timeout=30

LTPA Token Timeout

If single sign-on is configured to share the session between multiple servers, a Web Configuration document will define the SSO parameters.

The key setting in this case is the Expiration (minutes) field on the Basics tab of the document. This defines the lifespan of the LTPA token that is issued when the user logs in.

Keep Alive 1C - SSO Token Expiration

The important thing to understand is that this has nothing to do with how active or idle the session is.

This is a fixed length of time for which the key will be valid. Once it expires, the user will be prompted to login again. This can be very confusing to a user who is actively using the application!

Improving the Experience

There are a number of ways to implement controls to keep a session from timing out due to inactivity, but they will have no effect on the expiration of the LTPA token.

In order to prevent users from being frustrated with frequent logouts, some very smart people including Per Lausten and Sean Cull, have written about this in years past and have recommended setting the token expiration to a much larger number in order to prevent unexpected behavior. The idle session timeout can still do it’s job dealing with inactive sessions (and you as a developer can programmatically work to keep them alive if desired).