In this article I will discuss the need as a developer to use an auto-focus on your XPages. You do this when the end-user needs to type something onto your webpage and should not have to use their mouse to click in the field first.
Introduction
You’ve been there – you go to a website internal or external to your company and you have to login in or type something into the page – the search field or something of that ilk. It is the only field on the whole page and you have to use your mouse to focus on the field – frustrating beyond belief and quite frankly, lazy on the part of the developer. It is a pet peeve of mine when something as simple as one line of code can make a big difference to the first thing a user does on your site.
Can you imagine going to Google.com and having to focus on the field to get started on your search? Stupid idea – or so you would think.
Login Pages
The login page is perhaps the most obvious thing – as the developer you should ALWAYS focus on the username field – it is just lazy not to! It is harder on the user to have to click in the field and they are entering your website with an irritation on their mind already.
Auto-focus on the Username field
So how do we do this?
Well it depends on what takes your fancy that day…..but this is normally something you would do within some <script> tags on your web page.
Using the plain old JavaScript method
document.getElementById("username").focus()
In Dojo
dojo.byId("username").focus()
In jQuery
$("#username")[0].focus()
NOTE
We use the [0] to get the DOM Node element and use the HTML focus() method .focus() when applied to a jQuery object is an event handler which determines what happens when you focus on something – be careful to use correctly
$('#target').focus(function() {
alert('Handler for .focus() called.');
});
In HTML5
The autofocus attribute of a field is new in HTML5 (thanks to David Walsh). You can also focus on a button and other DOM objects
In this article I am going to show you how I created stencil.js – A technique for making a transparent mask on top of an image. But I am a little lost as to what to do with the technique now I have created it – any suggestions would be gratefully received and much appreciated.
Example
So I have been working on this idea for a couple of weeks and I finally figured out how to make the technique work whereby you can draw a picture ontop of a web font text (or make it look like that anyway)
Drawing a picture on top of web based text
I think it is kinda cool – shame the font has sharp edges and isn’t feathered but hey.
How does it work?
So what I am actually doing is taking an image
An image
Drawing a “<CANVAS>” element on top of it and writing some text onto the canvas (so no IE)
Writing some text onto the canvas
Then I make all the red pixels on the canvas have opacity=0 (i.e. see through) and everything else color white with opacity 255 (not see through)
It is easier to see the effect if I make the white canvas slightly opaque – in this image you can JUST see the original as I have set it to 225 not 255.
This canvas manipulation was what I found Patrick Wied had used in making the watermark.js plugin which I wrote about earlier in the year. Each pixel in the canvas can be manipulated with the RGB value and Opacity – so I can make anything white and or transparent.
The plan is to turn this into a jQuery plugin – but for what purpose? Other than a demonstration of it can be done – what’s the good practical usage for it. And then from that what variables are required to make the end result work?
In the jsFiddle example I pass in the Text, font and font-size. But there are also some tweaking to be done to position the text optimally over the image – and this varies based on the font and the size. I used Fascinate because it was a “fat” font and therefore showed a lot of the background image……Probably the transparency of the “white” mask could be a variable as well.
We are going to look at the new HTML5 eventSource capability. Adapting the articles (posted here) and (posted here) I am goign to show you how to send data from the server to your XPage without using ajax to initiate the communication. I have the feeling there is a lot to learn in this area and we are just scratching the surface.
Browser Support
Yep – it is HTML5 which means no IE right now – Chrome should support this but my copy does not – so right now this demonstration is only tested and working in the latest version of FireFox.
Demonstration
The results of this article are demonstrated here, and I strongly suggest you use some kind of plugin to watch the traffic as the values chance – quite fascinating. Right click – View Source and see for yourself – no ajax! no jQuery, nothing fancy, just HTML5 in action!
I have modified Stephan Wissel’s xAgent XSnippet to create a simple data stream using server-side output. Calling this xAgent through the web generated the following simple data output as seen here through Firefox HTTPFox plugin.
The thing to highlight is the Content-Type text/event-stream
xAgent output
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.afterRenderResponse>
<![CDATA[#{javascript:
var externalContext = facesContext.getExternalContext();
var writer = facesContext.getResponseWriter();
var response = externalContext.getResponse();
// set content type, e.g. ...
response.setContentType("text/event-stream");
response.setHeader("Cache-Control", "no-cache");
// read parameters, e.g. ...
var param = context.getUrlParameter("myParam");
// write HTML output e.g. ...
writer.write("data: the number is "+@Random());
writer.endDocument();
}]]>
</xp:this.afterRenderResponse>
</xp:view>
HTML5 JavaScript
In our xPage we create some JavaScript to instantiate and then listen to the eventSource
First of all we test to see if the EventSource is supported in this browser
Using the following code we subscribe to the EventSource (xSendHTML5Data_1.xsp is the xPage described above)
var eSource = new EventSource("xSendHTML5Data_1.xsp");
And then when we receive a message from the server we act on it
eSource.onmessage = function(event) {
//write the received data to the page
dojo.byId("#{id:serverData}").innerHTML = event.data;
};
This all comes together as the following ScriptBlock in the page
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[//check for browser support
if(typeof(EventSource)!=="undefined") {
//create an object, passing it the name and location of the server side script
var eSource = new EventSource("xSendHTML5Data_1.xsp");
//detect message receipt
eSource.onmessage = function(event) {
//write the received data to the page
dojo.byId("#{id:serverData}").innerHTML = event.data;
};
}
else {
dojo.byId("#{id:serverData}").innerHTML="Whoops! Your browser doesn't receive server-sent events.";
}]]>
</xp:this.value>
</xp:scriptBlock>
Stopping the source
We are able to stop the source using eSource.close() that will stop the data being sent. I added mine in a button
<xp:button id="button1" value="Stop the Source">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[eSource.close()]]></xp:this.script>
</xp:eventHandler></xp:button>
Changing the refresh time
We are able to change the refresh time by returning the retry value in millisecond along with our data
writer.write("retry: 2000\ndata: the number is "+@Random());
setting the refresh time 2000ms
Specifying an event name
This mercilessly ripped directly from the article – I have not done anything with the event listeners yet, but here the next thing I want to look at….using the data returned from the server to trigger events in the browser without having to parse the return string and take action on it – that’s a huge performance gain and distributes the tasks….more to come on that in the near future….
For example, the following server output sends three types of events, a generic ‘message’ event, ‘userlogon’, and ‘update’ event:
data: {"msg": "First message"}\n\n
event: userlogon\n
data: {"username": "John123"}\n\n
event: update\n
data: {"username": "John123", "emotion": "happy"}\n\n
With event listeners setup on the client:
source.addEventListener('message', function(e) {
var data = JSON.parse(e.data);
console.log(data.msg);
}, false);
source.addEventListener('userlogon', function(e) {
var data = JSON.parse(e.data);
console.log('User login:' + data.username);
}, false);
source.addEventListener('update', function(e) {
var data = JSON.parse(e.data);
console.log(data.username + ' is now ' + data.emotion);
}, false);
You need to use the latest Chrome or FF browsers to get the full effect as he uses Drag and Drop to pull in the image but you can make something like this – how cool is that !!
Update – Thanks to Tim Tripcony for pointing this out
If you are using 8.5.3 you can add the custom attributes to the field in the designer client. This removes the need to use the dojo.query
and added the javascript functions to a scriptblock at the bottom of the page
//function called when drag starts
function dragIt(theEvent) {
//tell the browser what to drag
theEvent.dataTransfer.setData("Text", theEvent.target.id);
}
//function called when element drops
function dropIt(theEvent, keepMe) {
//get a reference to the element being dragged
var theData = theEvent.dataTransfer.getData("Text");
//get the element
var theDraggedElement = document.getElementById(theData);
//add it to the drop element
if (keepMe){
//Add a clone of the element to the field - rather than move it
var newObj=dojo.clone(theDraggedElement)
theEvent.target.appendChild(newObj);
} else {
theEvent.target.appendChild(theDraggedElement);
}
//Add a new line for visual line up
var theBR=document.createElement("br")
theEvent.target.appendChild(theBR);
//instruct the browser to allow the drop
theEvent.preventDefault();
}
I changed the example slightly to add a clone capability rather than just drag and drop
Drag and Drop example 1 (Move)
Dragging to the first box “moves” the label
Drag and Drop example 2 (Clone)
Dragging the label to the second box create a copy of it using dojo.clone(node)
Conclusion
This is merely a prototype but demonstrates nicely the new and exiting capabilities of HTML5 without having the need for a dojo or jQuery library to do the drag/drop for you