Thursday, September 07, 2006

Getting the Scrolling position using Javascript


Page scrolling is one of the least-standardized properties in JavaScript: three variations are now in use by different versions of different browsers. But with a few careful object tests, we can reliably get a consistent value.

Solution

There are three ways of getting this information. We'll use object tests on each approach, to determine the level of support available:

Example 7.8. get-scrolling-position.js (excerpt)
function getScrollingPosition()
{
var position = [0, 0];
if (typeof window.pageYOffset != 'undefined')
{
position = [
window.pageXOffset,
window.pageYOffset
];
}
else if (typeof document.documentElement.scrollTop
!= 'undefined' && document.documentElement.scrollTop > 0)
{
position = [
document.documentElement.scrollLeft,
document.documentElement.scrollTop
];
}
else if (typeof document.body.scrollTop != 'undefined')
{
position = [
document.body.scrollLeft,
document.body.scrollTop
];
}
return position;
}

The function can now be called as required. Here's a simple demonstration, using a window.onscroll event handler, that gets the figures and writes them to the title bar:

Example 7.9. get-scrolling-position.js (excerpt)
window.onscroll = function()
{
var scrollpos = getScrollingPosition();
document.title = 'left=' + scrollpos[0] + ' top=' +
scrollpos[1];
};

The Problem with scroll

scroll is not the most reliable of events: it may not fire at all in Konqueror or Safari 1.0, or when the user navigates with a mouse wheel in Firefox. And if it does fire, it may do so continually and rapidly (as it does in Internet Explorer), which can be slow and inefficient if the scripting you set to respond to the event is very complex.

If you have difficulties of this kind, you may find it better to use the setInterval function instead of an onscroll event handler. setInterval will allow you to call the function at a predictable interval, rather than in response to an event.

window.setInterval(function()
{
var scrollpos = getScrollingPosition();
document.title = 'left=' + scrollpos[0] + ' top=' +
scrollpos[1];
}, 250);

Discussion

The only real complication here is that IE 5 actually does recognize the documentElement.scrollTop property, but its value is always zero, so we have to check the value as well as looking for the existence of the property.

Otherwise, it doesn't really matter to us which browser is using which property; all that matters is that our script gets through one of the compatibility tests and returns a useful value. However, the properties used by each browser are shown here for reference:

  • window.pageYOffset is used by Firefox and other Mozilla browsers, Safari, Konqueror, and Opera.
  • document.documentElement.scrollTop is used by IE 6 in standards-compliant mode.
  • document.body.scrollTop is used by IE 5, and IE 6 in "Quirks" mode.

This list doesn't tell the complete story, but it's intended primarily to describe the ordering of the tests. More recent Mozilla browsers (such as Firefox) also support documentElement.scrollTop and body.scrollTop, by the same rendering mode rules as IE 6. Safari and Konqueror support body.scrollTop in either mode. Opera supports all three properties in any mode!

But none of this is important for you to know -- browser vendors add these multiple properties to allow for scripts that are unaware of one property or another, not to provide arbitrary choices for the sake of it. From our perspective, the important point is to settle on a set of compatibility tests that ensures our script will work as widely as possible.

Get more information

Tags: scroll position, javascript, javascript code, mouse position, browsers, page scrolling, scrolltop

Monday, September 04, 2006

AJAX, PHP and Javascript Errors


Javascript is a powerful tool in the web programmers toolbox however, it's also one of our greatest headaches. Dealing with browser inconsistencies is always a source of great pain. You test on multiple platforms, find everyone you know with a mac running safari and think you have your code locked down however it rarely always works out this way. Being able to detect javascript errors in the wild can be a great resource for you to really see how your code is performing on a day to day basis. Mozilla and IE support a powerful event handler called "onerror" used like window.onerror = function(){};
You can create a custom function at the top of all your scripts that will record any parsing or exception errors generated. You can create your function to accept 3 parameters, the message of the error, the URL of the error and the Line number of the error. Creating this function is as simple as so:

  1. <SCRIPT>

  2. window.onerror = function(msg, err_url, line) {

  3. alert('an error occured on line: ' + line);

  4. }

  5. </SCRIPT>


Now the end user really doesn't care which line an error occurred on but the powerful part is being able to get this information back to the developers. Using AJAX technologies you can easily record a log of all js errors on your site so you can take appropriate action to fix these issues. Not only can you include msg, line and error URL, but you can also send any other information javascript can capture such as referring page and the type of browser the client is using.
I'm going to use my standard AJAX class I use in my applications. I'm not a big fan of overhyped, oversized, slow AJAX frameworks that take a very simple concept and turn it into a serialized mess so I just use my trusty 97 line js class which can be found here http://www.litfuel.net/tutorials/js_errors/class_xmlhttp.js. I'm not going to go over ajax as I'm sure there are many other places you can get the basics. Basically this script just allows you to create an XMLHTTP object and pass POST parameters and a callback function.
To use the object you simple write:
  1. // post data you want to send to the server

  2. var POSTData = 'msg=' + msg ;

  3. // create the actual xmlhttprequest object and pass the URL of the PHP page you want to call

  4. var s = new XMLHTTP("error_server.php?");

  5. // post data to the server and assign processReqChange as the function to call back when the data is posted

  6. var xmlDoc = s.call(POSTData, processReqChange);


Putting these two things together you can now log all of your JS error msgs behind the scenes and create an offline viewer that you and your other programmers can sift through. I prefer to err on the side of performance so the goal is just to log some quick info to the server and set up a cron job to email that data each night to the developers.

FILE 1 - Our main HTML File index.html
  1. <HTML>

  2. <HEAD>

  3. <TITLE></TITLE>

  4. <SCRIPT SRC="class_xmlhttp.js" type="text/javascript"></SCRIPT>

  5. <SCRIPT SRC="js_error_logger.js" type="text/javascript"></SCRIPT>

  6. <SCRIPT>

  7. // This function does not exist so it will generate an exception error

  8. test();

  9. </SCRIPT>

  10. </HEAD>

  11. <BODY>

  12. </BODY>

  13. </HTML>


So what we're doing here is first including our XMLHTTPRequest class to instantiate our JS Object, then including the onerror functionality that will log the data to our server on every webpage. You can find the js_error_logger.js file here: http://www.litfuel.net/tutorials/js_errors/js_error_logger.js
js_error_logger.js file:

Javascript and Java


JavaScript and Java are similar in some ways but fundamentally different in others. The JavaScript language resembles Java but does not have Java's static typing and strong type checking. JavaScript supports most Java expression syntax and basic control-flow constructs.

In contrast to Java's compile-time system of classes built by declarations, JavaScript supports a runtime system based on a small number of data types representing numeric, Boolean, and string values. JavaScript has a prototype-based object model instead of the more common class-based object model. The prototype-based model provides dynamic inheritance; that is, what is inherited can vary for individual objects. JavaScript also supports functions without any special declarative requirements. Functions can be properties of objects, executing as loosely typed methods.

JavaScript is a very free-form language compared to Java. You do not have to declare all variables, classes, and methods. You do not have to be concerned with whether methods are public, private, or protected, and you do not have to implement interfaces. Variables, parameters, and function return types are not explicitly typed.

Java is a class-based programming language designed for fast execution and type safety. Type safety means, for instance, that you can't cast a Java integer into an object reference or access private memory by corrupting Java bytecodes. Java's class-based model means that programs consist exclusively of classes and their methods. Java's class inheritance and strong typing generally require tightly coupled object hierarchies. These requirements make Java programming more complex than JavaScript authoring.

In contrast, JavaScript descends in spirit from a line of smaller, dynamically typed languages such as HyperTalk and dBASE. These scripting languages offer programming tools to a much wider audience because of their easier syntax, specialized built-in functionality, and minimal requirements for object creation.

What is Javascript?


JavaScript is Netscape's cross-platform, object-oriented scripting language. JavaScript is a small, lightweight language; it is not useful as a standalone language, but is designed for easy embedding in other products and applications, such as web browsers. Inside a host environment, JavaScript can be connected to the objects of its environment to provide programmatic control over them.

Core JavaScript contains a core set of objects, such as Array, Date, and Math, and a core set of language elements such as operators, control structures, and statements. Core JavaScript can be extended for a variety of purposes by supplementing it with additional objects; for example:


  • Client-side JavaScript extends the core language by supplying objects to control a browser (Navigator or another web browser) and its Document Object Model (DOM). For example, client-side extensions allow an application to place elements on an HTML form and respond to user events such as mouse clicks, form input, and page navigation.

  • Server-side JavaScript extends the core language by supplying objects relevant to running JavaScript on a server. For example, server-side extensions allow an application to communicate with a relational database, provide continuity of information from one invocation to another of the application, or perform file manipulations on a server.
Through JavaScript's LiveConnect functionality, you can let Java and JavaScript code communicate with each other. From JavaScript, you can instantiate Java objects and access their public methods and fields. From Java, you can access JavaScript objects, properties, and methods.

Netscape invented JavaScript, and JavaScript was first used in Netscape browsers.