Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Tuesday, November 17, 2015

Limiting Keyboard Input in XPages

One way to make your validation easier is limit the types of characters allowed in a specific input field. For example, if you have a numeric field you simply don’t allow the user to type a letter in that field. If you know that an email address cannot contain special characters, you can simply prevent the user from typing those special characters. I would caution that if using this technique for public facing applications, that the use of tooltips or helper text be considered.

Last Thursday I was told that in my application, the field was allowing the entry of numbers from the main keyboard but not the numeric keypad. I discovered that the behavior of the dojo combobox differs from that of the core controls. In this post, I will explain the usage of the keypress event in general, and then explain how to use it with a dojo combobox. 

Before I begin, I have to laugh at the irony of this new Stack Overflow question (http://stackoverflow.com/questions/33680515/how-to-prevent-special-characters-input-into-edit-box) about this very subject that appeared a few hours after working on this. Amazingly no one had answered it by the time I saw it, and of course it was fresh on my mind, so I answered it with what I was already going to put in this new blog post.

Keyboard Events


There are three key events that you can use. The onkeypress, and the okeydown, and the onkeyup. As the name implies these are keyboard events. In XPages you can assign client and/or server code to each. I would strongly caution for performance reasons against doing anything serverside that is more complicated then setting a scoped variable. The code that we want to use to limit certain keys is all clientside javascript.

Usage in an Edit Control



This code shown here will only allow numbers and the backspace key. In XPages, if applied to a core control, this also allows the numeric keyboard to work even though it uses different keycodes. The
keycodes for the numeric keyboard are 96-105. For an edit box the only event you need is the onKeyPress.

Usage in a Dojo Combobox


One of the nice features of the dojo combobox is that you can choose from the list or type in a value. You also get built in type ahead. The key events work differently in two specific ways though. If you just use the onkeypress event, then if the user types really fast they can bypass the event and type an unwanted character. These are the types of things the quality assurance people are happy to point out to you. The way to prevent this behavior is to put the code in both the onkeydown and onkeyup events.


How to selectively include or exclude any key


My example above on specifically includes numbers, your needs may differ. You can use http://keycode.info/ to easily figure out any keycode. Modify the code below to meet your specific requirements. This example only allows letters, numbers, backspace, and delete.

var keyCode = event.keyCode;
if((keyCode >= 48 && keyCode <= 57) || (keyCode >= 65 && keyCode <= 90)|| keyCode == 8 || keyCode == 46){
   event.returnValue = true;
}else{
   event.returnValue = false;
}

Saturday, February 21, 2015

Using Javascript RegExp Object to replace a XPages Contraint Validator


I had an occasion yesterday where I needed change a partial refresh to process data without validation in order to fix another problem. Despite this I still needed to validate the data the user enters based on a regular expression.  The previous developer was was using a <xp:validateContraint> to check the data, but this check would no longer trigger since I am skipping validation. The constraint validator uses a regular expression to determine whether the validation passes or not.

Even though the regular expression in this case was simplistic, I did not want to mirror what it does using string manipulation to validate it. 
I remembered from one of my Javascript books (Professional JavaScript for Web Developers) that Regular Expressions are built into the language.  It was very easy to duplicate the constraint functionality by just copying the RegExp string that already worked and then creating a RegExp javascript object.   

The code here lives in a button in the SSJS onclick event: 

        
var thisID = getComponent("inputID").getValue(); 
var pattern = /^([A-Za-z]{2}[A-Za-z0-9]{0,2})$/; 
        
if(!pattern.test(thisID)){ 
     return viewScope.infoMessage = "No Can Do";
} 

The built-in RegExp object can be created in one of two ways, you can either use the slash as I do in the above code or you can create it using new RegExp("....").  Either way that you choose, it works the same. The object has a method called test() which will return a true/false depending if the passed in string matches.  Of course, you can use this in any javascript, client or serverside.

Monday, June 9, 2014

Force your expired XPage to return to the login page

One of things that I have found annoying about XPages apps is that an application page left open in the browser for a long time will act like it is usable, but in fact the session has timed out and the page is unusable. When you try to actually submit anything the page will fail, and you will have to re-login.  I work for a bank now, where they are very concerned with security so I wanted my application to work similar to most financial websites.  In addition, I find a page you can't use a very poor user experience.  I had some time while the project is ramping up, so I decided to do something about it.

In this post, I will go over a simple way to force the page to redirect to the login page after the session expires.  I was actually surprised when I researched this that I couldn't find anyone who had already done it.  I put this Stack Overflow question in, and Stephan Wissel answered it and pointed me in the right direction.  He reinforced what I suspected that I would have to do this entirely in the client.

What does it do, how does it work

The concept here is pretty simple, when you load a page it sets a timer.  Whenever you submit anything to the server, or switch tabs in the application the timer is reset.  The timer accepts two parameters, the time to wait, and the page to redirect to.  The function does NOT log you out, that is what happens automatically by the server, this simply makes the client aware of what already happened.  In my case, I redirect to the application home page, so that after the login is re-entered it goes where I want it to.  It would be easy to just make the function refresh the current page.

var timeoutID; 
function setAutoRefresh(refreshTime, relativePath) { 
        if(timeoutID){ 
                window.clearTimeout(timeoutID); 
        } 
        timeoutID = window.setTimeout(function(){ location.replace(relativePath);}, refreshTime); 
} 


The same function will work for setting and resetting the timer.   Not sure why you would, but if you wanted to, you could have any number of timeouts on a page by giving them different variables.

You call the function like this:
var pathArray = window.location.pathname.split( '/' ); 
var path = "/" + pathArray[1] + "/" + pathArray[2]; 
//returns relative path to application home, example: "/atm/atm.nsf" 
//1860000 represents 31 minutes, one minute after session timeout 
setAutoRefresh(1860000, path); 

I made my timer set to one minute after the default 30 minute session logout.  The way this is written now, if the time was set less then it would redirect to the page and skip the login page which to me defeats the purpose. One warning, if you miss resetting the timer then the page could redirect unexpectedly.  In my application, I call the function from the onClientLoad of my layout custom control once and then in each button that perform updates. Note:  If you are not using a layout custom control, then you will have to put this in the onClientLoad of every XPage.  

Potential Enhancements

The code I wrote is pretty basic, maybe too basic.   Here are a two ways that you could make it more robust:
  • When the timer is up, you could create an ajax call to ping the server, and then redirect the page if you get returned a "Not Authorized" message.  If the session is still active you could reset the timer.  With this method, you could load it once, and just have it run every ten minutes, and never have to worry about it.  
  • Another enhancement, would be not reset the timer when you switch tabs or submit anything, but instead reset if based on a mouse moving event.  I considered this but thought it overkill for the application I am writing and didn't want to be calling the function non-stop. 
If anyone had any better ways of doing this, or anything to add, please comment.



August 2016 Edit:  


For some strange reason David Leedy is unable to comment on my blog so I am adding his comment here.

I'm adapting this code for my day job and also a future MWLug presentation and maybe even NotesIn9. I had problems with the code as it seemed to hardcode in the level of folder nesting. I ended up using this:
var thisUrl = window.location.href;
var lastSlash = thisUrl.lastIndexOf("/");
var dbPath = thisUrl.substring(0, lastSlash);
var finalPath = dbPath + "?Logout&redirectto=" + dbPath + "/sessionExpired?OpenPage";



console.log("dbPath : " + dbPath);
console.log("FinalPath : " + finalPath);

//1 minute = 60,000 milliseconds
setAutoRefresh(60000,finalPath); 

Thanks to both you Steve, and Daniel for this post and comment! 

Thursday, April 4, 2013

Useful tool for creating Regular Expressions

I needed to create a regular expression in javascript to validate a textbox where I was using typeahead to populate the data.    If the user entered garbage the typeahead data would go away and the garbage would stay.

I decided to use a RegEx to fix this issue, but honestly I was not all that familiar with them.   I had used them in years past, but just copied and pasted ones created by someone else.   In this case, I had to create my own expression.

I tried reading up on them in my javascript book: Javascript for Web Developers, but I just wasn't getting it.   I then remembered that there was a video training course on Lynda.com that covered RegEx.   The whole course is over five hours, but I was able to get what I needed in the first 4 chapters.   The teacher really helps to make sense of them.  (You will need to be a subscriber to see videos)

In the course, he recommends the tool Regex Pal, as a means of testing your expressions.   It is very simple and easy to use and a good tool in the toolbox.  The format is standard across all major programming languages.

Here is the finished clientside javascript that I added to my application.  The tool helped me to generate the second line, and allow me to paste actual data to test that the expression correctly matches.

var x=document.getElementById("#{id:inputText2}").value;
var expression = /.* - .* - .*/;  //regex matching vendor format

if (expression.test(x)=== false)
{
   alert("Please choose proper Vendor Name from the dropdown list.");
   document.getElementById("#{id:inputText2}").value = "";
   document.getElementById("#{id:inputText2}").focus();
   return false;