Aug 07
What is the XMLHttpRequest object?

  • Creating an XMLHttpRequest object.
  • Specifying and submitting your HTTP request to a web server.
  • Synchronously or asynchronously retrieving the server’s response.
Propertie Name
Description

onreadystatechange
An event handler for an event that fires at every state change.

readyState
The readyState property defines the current state of the XMLHttpRequest object.

State Description
0: The request is not initialized.
1: The request has been set up.
2: The request has been sent.
3: The request is in process.
4: The request is completed.

readyState = 0 after you have created the XMLHttpRequest object, but before you have called the open() method.
readyState = 1 after you have called the open() method, but before you have called send().
readyState = 2 after you have called the send() method.
readyState = 3 after browser has established a communication with the server, but before the server has completed the response.
readyState = 4 after the request has been completed, and the response data have been completely received from the server.

responseText
Returns the response as a string.

responseXML
Returns the response as XML, which can be examined and parsed using W3C DOM node tree methods and properties. This property returns an XML document object, when the Content-Type header specifies the MIME(media) type as text/xml, application/xml, or ends in +xml. If the Content-Type header does not contain one of these media types, the responseXML value is null.

status
Returns the status as a number (e.g. 404 for “Not Found” and 200 for “OK”).

statusText
Returns the status as a string (e.g. “Not Found” or “OK”).

Method Name
Description

abort()
Cancel the current request.

getAllResponseHeaders()
The getAllResponseHeaders() method returns all the response headers as a single string with each header on a separate line. The method returns null if readyState value is not 3 or 4.

getResponseHeader(DOMString header)
Returns the value of the specified HTTP header. Call getResponseHeader() only when the readyState value is 3 or 4 (in other words, after the response headers are available); otherwise, the method returns an empty string.

open(DOMString method, DOMString url, boolean async, DOMString username, DOMString password)
Specify the method, url, and other optional attributes of a request.
The method parameter can have a value of “GET”, “POST”, or “HEAD”. Other HTTP methods, such as “PUT” and “DELETE” (primarily used in REST applications), may be possible.
The async parameter specifies whether the request should be handled asynchronously or not. “true” means that script processing carries on after the send() method, without waiting for a response, and “false” means that the script waits for a response before continuing script processing.

send()
After preparing a request by calling the open() method, you send the request to the server. You may call send() only when the readyState value is 1, otherwise the XMLHttpRequest object raises an exception. The request gets sent to the server using the parameters supplied to the open() method. The send() method returns immediately when the async parameter is true, letting other client script processing continue. The XMLHttpRequest object sets the readyState value to 2 (Sent) after the send() method has been called. When the server responds, before receiving the message body, if any, the XMLHttpRequest object sets readState to 3 (Receiving). When the request has completed loading it sets readyState to 4 (Loaded). For a request of type HEAD, it sets the readyState value to 4 immediately after setting it to 3.
The send() method takes an optional parameter that may contain data of varying types. Typically, you use this to send data to the server using the POST method. You can explicitly invoke the send() method with null, which is the same as invoking it with no argument. For most other data types, set the Content-Type header using the setReuqestHeader() method before invoking the send() method. If the data parameter in the send(data) method is of type DOMString, encode the data as UTF-8. If data is of type Document, serialize the data using the encoding specified by data.xmlEncoding, if supported or UTF-8 otherwise.

setRequestHeader(DOMString header, DOMString value)
The setRequestHeader() method sets request headers. You may call this method after calling the open() method when the readyState value is 1; otherwise you will get an exception.

Create an XMLHttpRequest Object

          			function createHttpRequest() {
          				var httpRequest = null;
          					if (window.ActiveXObject) // For IE6 and below
          						httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
          					else // For IE7 and Modern Browsers
          						httpRequest = new XMLHttpRequest();
          				return httpRequest;
          			}
          		
Submit a Request

          			XMLHttpRequest.open("GET", url, true);
          		

If you pass false as the third argument to open(), the send() method is synchronous: it blocks and does not return until the server’s response has arrived. Asynchronous responses are generally preferred.

HTTP GET

          			var xmlHttpRequest = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
          			xmlHttpRequest.onreadystatechange = function() {

          			}
          			xmlHttpRequest.open("GET", "query.php?username=vivian", false);
          			xmlHttpRequest.send(null);
          		

HTTP POST

          			var xmlHttpRequest = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
          			xmlHttpRequest.onreadystatechange = function() {

          			}
          			xmlHttpRequest.open("POST", "query.php", false);
          			xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          			xmlHttpRequest.send("username=vivian");
          		

With POST requests, data is passed to the server in the body of the request, rather than encoding it into the URL itself. Since request parameters are encoded into the URL of a GET request, the GET method is suitable only when the request has no side effects on the server — that is, when repeated GET requests for the same URL with the same parameters can be expected to return the same result. When there are side effects to a request (such as when the server stores some of the parameters in a database), a POST request should be used instead.

Escape the Data

          			var HTTPUTILITY = {
          				encodeFormData: function(data) {
          					if (!data) return;
          					var pairs = [];
          					var regexp = /%20/g; // A regular expression to match an encoded space.
          					for (var name in data) {
          						// Create a name/value pair, but encode name and value first. The global function encodeURIComponent does almost what we want,
          						// but it encodes spaces as %20 instead of as "+". We have to fix that with String.replace().
          						var value = data[name].toString();
          						var pair = encodeURIComponent(name).replace(regexp, "+") + "=" + encodeURIComponent(value).replace(regexp, "+");
          						pairs.push(pair);
          					}
          					return pairs.join("&"); // Concatenate all the name/value pairs, separating them with &.
          				}
          			};
          		

The POST method uses the AJAX.encodeFormData() function to convert the properties of an object to a string form that can be used as the body of a POST request. This string is then passed to the XMLHttpRequest.send() method and becomes the body of the request. (The string returned by AJAX.encodeFormData() can also be appended to a GET URL; just use a quest-mark character to separate the URL from the data.)

Retrieve the Response

          			var xmlHttpRequest = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
          			xmlHttpRequest.onreadystatechange = function() {
          				if (xmlHttpRequest.readyState != 4) {
          					// Start to progress
          				} else { // The server's response is complete.
          					if (xmlHttpRequest.status == 0 || xmlHttpRequest.status == 200)
          						callback(xmlHttpRequest.responseText)
          					else
          						// Error
          				}
          			}
          			xmlHttpRequest.open("POST", "query.php", false);
          			xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          			xmlHttpRequest.send("username=vivian");
          		

Notes on readyState 3

Data is being received from the server.readyState 3 differs somewhat in Firefox and Internet Explorer. Firefox invokes the onreadystatechange handler multiple times in readyState 3, to provide download progress feedback. A script might use these multiple invocations to display a progress indicator to the user. Internet Explorer, on the other hand, interprets the event handler name strictly, and invokes it only when the readyState value actualy changes. This means that it is invoked only once for readyState 3, no matter how large downloaded document is.

Time Out a Request

          			var timer = null;
          			var timeout = 1000;
          			var xmlHttpRequest = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
          			if (timeout) {
          				if (timer) clearTimeout(timer);
          				timer = setTimeout(function(){
          					xmlHttpRequest.abort();
          				}, timeout);
          			}
          			xmlHttpRequest.onreadystatechange = function() {
          				if (xmlHttpRequest.readyState != 4) {
          					// Start to progress
          				} else { // The server's response is complete.
          					if (timer) clearTimeout(timer);
          					if (xmlHttpRequest.status == 0 || xmlHttpRequest.status == 200)
          						callback(xmlHttpRequest.responseText)
          					else
          						// Error
          				}
          			}
          			xmlHttpRequest.open("POST", "query.php", false);
          			xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          			xmlHttpRequest.send("username=vivian");
          		
Prevent Caching for Internet Explorer

By appending the julian day number to the end of the URL(?timestamp=123412341234), we effectively make each call unique and that means Internet Explorer will not cache the Ajax call as it is wont to do.

Related Posts

Jul 16

There is a bug in IE (version 6 and 7) in which the clarity between window.onresize and body.onresize is muddied. This can cause quite a problem for developers and even render the client’s browser unresponsive (throttling the CPU to near 100%) if you’re not very careful. IE fires the onresize multiple times while Firefox only fires it once after the browser has completed resizing.

Prevent IE from Firing onResize Multiple Times

  • Solution One: setTimeout()
  •           				var elements = {"wrapper": null, "topHeader": null, "bottomFooter": null, "leftSide": null, "rightSide": null, "content": null};
              				var properties = ["clientWidth", "clientHeight", "offsetWidth", "offsetHeight"];
              				var resizeTimeout = null;
              				var onloadHandler = function() {
              					for (var name in elements)
              						elements[name] = document.getElementById(name);
              					onresizeHandler();
              				};
              				var onresizeHandler = function() {
              					if (resizeTimeout) clearTimeout(resizeTimeout);
              					resizeTimeout = setTimeout(function(){
              						var height = GEOMETRY.getViewportHeight() - elements.topHeader.offsetHeight - elements.bottomFooter.offsetHeight;
              						height -= parseInt(CSS.get(elements.topHeader, "margin-top"), 10) - parseInt(CSS.get(elements.topHeader, "margin-bottom"), 10) - parseInt(CSS.get(elements.bottomFooter, "margin-top"), 10) - parseInt(CSS.get(elements.bottomFooter, "margin-bottom"), 10);
              						CSS.set(elements.leftSide, {"height": height});
              						CSS.set(elements.rightSide, {"height": height});
              						CSS.set(elements.content, {"height": height});
              					}, 400);
              				};
              				GENERIC.addEvent(window, "load", onloadHandler);
              				GENERIC.addEvent(window, "resize", onresizeHandler);
              			
              				<div id="wrapper" class="wrapper">
              					<div id="topHeader" class="top-header">Header</div>
              					<div id="leftSide" class="side-bar align-left">Side Bar</div>
              					<div id="rightSide" class="side-bar align-right">Side Bar</div>
              					<div id="content" class="content">Content</div>
              					<div id="bottomFooter" class="bottom-footer">Footer</div>
              				</div>
              			
  • Solution Two: setInterval()
  •           				var elements = {"wrapper": null, "topHeader": null, "bottomFooter": null, "leftSide": null, "rightSide": null, "content": null};
              				var properties = ["clientWidth", "clientHeight", "offsetWidth", "offsetHeight"];
              				var initHeight = 0;
              				var resizeInterval = null;
              				var onloadHandler = function() {
              					for (var name in elements)
              						elements[name] = document.getElementById(name);
              					if (resizeInterval) clearInterval(resizeInterval);
              					resizeInterval = setInterval(function(){
              						onresizeHandler();
              					}, 100);
              				};
              				var onresizeHandler = function() {
              					var height = GEOMETRY.getViewportHeight() - elements.topHeader.offsetHeight - elements.bottomFooter.offsetHeight;
              					height -= parseInt(CSS.get(elements.topHeader, "margin-top"), 10) - parseInt(CSS.get(elements.topHeader, "margin-bottom"), 10) - parseInt(CSS.get(elements.bottomFooter, "margin-top"), 10) - parseInt(CSS.get(elements.bottomFooter, "margin-bottom"), 10);
              					if (initHeight != height)
              						CSS.set(elements.leftSide, {"height": height});
              						CSS.set(elements.rightSide, {"height": height});
              						CSS.set(elements.content, {"height": height});
              						initHeight = height;
              					}
              				};
              				GENERIC.addEvent(window, "load", onloadHandler);
              			
              				<div id="wrapper" class="wrapper">
              					<div id="topHeader" class="top-header">Header</div>
              					<div id="leftSide" class="side-bar align-left">Side Bar</div>
              					<div id="rightSide" class="side-bar align-right">Side Bar</div>
              					<div id="content" class="content">Content</div>
              					<div id="bottomFooter" class="bottom-footer">Footer</div>
              				</div>
              			
Related Posts

Jul 05
Scripting Computed Styles

The W3C standard API for determining the computed style of an element is the getComputedStyle() method of the Window object. The first argument to this method is the element whose computed style is desired. The second argument is any CSS pseudoelement, such as “:before” or “:after” whose style is desired. In the Mozilla and Firefox implementation of this method, the second argument is required and may not be omitted. As a result, you’ll usually see getComputedStyle() invoked with null as its second argument.

IE provides a simpler alternative: every HTML element has a currentStyle property that holds its computed style.

          			var CSS =  {
						getStyle: function(element) {
							if (!element) return;
							if (typeof element == "string") element = document.getElementById(element);
							if (element.currentStyle) // For IE
								return element.currentStyle;
							else if (document.defaultView && document.defaultView.getComputedStyle) // For Modern Browsers
								return document.defaultView.getComputedStyle(element, null);
							else
								return element.style;
						}
          			};
          		
Retrive Global/External CSS Properties

These two approaches frequently require different ways of referring to the style properties. In the case of the IE currentStyle object, references are made via the same object model syntax as is used for getting and setting style values. Therefore, hyphenated CSS property names must be referenced via the intercapitalization system (e.g., margin-left becomes marginLeft). But the property name for the W3C DOM getPropertyValue() method must be in the CSS property format (e.g., margin-left is margin-left).

Also be aware that for some CSS properties, different browser versions may return different value types-especially in colors that are specified by CSS syntax other than rgb(r, g, b). For example, if you set the color with a plain-language color name (e.g., orange), the value returned from the browsers may be in a different format. For the most part, if you specify colors in rgb(r, g, b) format, you’ll get that back.

CSS values consisting of length measurements typically contain units (pixels, points, ems, and so on). If you tend to utilize the value of a style property for any math, such as adding five pixels to the left edge of a positioned element, be sure to extract the numeric portion of sorting values that include units. Use the parseInt() function for integers and the parseFloat() function for numeric values that may have digits to the right of the decimal (e.g., 0.5em).

Once you assign a value to a property of an element’s style object, the value can be read subsequently through the style property. But for consistency’s sake, you can continue to read a value the getPropertyValue() method and currentStyle object because it returns the effective value applied to the element at any instant.

          			var CSS =  {
						get: function(element, name) {
							if (!element) return;
							if (typeof element == "string") element = document.getElementById(element);
							// Convert "background-color" to "backgroundColor"
							var camelCase = name.replace(/\-(\w)/g, function(all, letter) {
								return letter.toUpperCase();
							});
							if (element.currentStyle) { // For IE
								return element.currentStyle[name] || element.currentStyle[camelCase];
							} else if (document.defaultView && document.defaultView.getComputedStyle) { // // For Modern Browsers
								name = name.replace(/([A-Z])/g, "-$1").toLowerCase();
								return document.defaultView.getComputedStyle(element, null).getPropertyValue(name);
							} else {
								return element.style[name] || element.style[camelCase];
							}
						},
						set: function(element, properties) {
							if (!element) return;
							if (typeof element == "string") element = document.getElementById(element);
							for (var name in properties) {
								// Convert "background-color" to "backgroundColor"
								var camelCase = name.replace(/\-(\w)/g, function(all, letter) {
									return letter.toUpperCase();
								});
								if (typeof properties[name] == "number") element.style[camelCase] = (parseInt(properties[name], 10) || 0) + "px";
								if (typeof properties[name] == "string") element.style[camelCase] = properties[name];
							}
						}
          			};
          		
Related Posts

Jun 15
Mouse Events

  • onMouseDown: A mouse button has been pressed.
  • onMouseMove: The mouse has been moved.
  • onMouseOut: The mouse pointer has left an element.
  • onMouseOver: The mouse pointer has entered an element.
  • onMouseUp: A mouse button has been released.
  • onClick: One mousedown and one mouseup detected on this element.
  • onDbClick: A mouse button has been double-clicked (clicked twice rapidly).
Mouse Event Properties

Property Name
Description

button
A number that specifies which mouse button changed state during a mousedown, mouseup, or click event. A value of 0 indicates the left button, 1 indicates the middle button, and 2 indicates the right button.

altKey, ctrlKey, metaKey, shiftKey
These four boolean fields indicate whether the Alt, Ctrl, Meta, or Shift keys were held down when a mouse event occurred.

clientX/clientY
Specify the X and Y coordinates of the mouse pointer, relative to the upper-left corner of the browser’s viewport and do not take document scrolling into account.

screenX/screenY
Specify the X and Y coordinates of the mouse pointer, relative to the upper-left corner of the user’s monitor. These values are useful if you plan to open a new browser window at or near the location of the mouse event.

relatedTarget
This property refers to a node that is related to the target node of the event. For mouseover events, it is the node that the mouse left when it moved over the target. For mouseout events, it is the node that the mouse entered when leaving the target.

W3C Standard
Internet Explorer
Description

button
button
Still an integer value but the button value is interpreted differently in IE. A value of 0 indicates none, 1 indicates the left button, 2 indicates the right button, 3 indicates the left and right buttons, 4 indicates middle button, 5 indicates the left and right buttons, 6 indicates the middle and right buttons, 7 indicates the left, middle, and right buttons.

relatedTarget
fromElement
toElement
fromElement specifes the document element that the mouse came from for mouseover events. toElement specifies the document element that the mouse has moved to for mouseout events.

clientX/clientY

          			function onMouseDownHandler(event) {
          				var e = event || window.event; // IE stores events in window object.
          				var mouseObj = {left: e.clientX, top: e.clientY}; // Store the position of the mouse object.
          			}
          			element.onmousedown = onMouseUpHandler;
          		

currentTarget and relatedTarget/fromElement and toElement

          			var GENERIC = {
          				findCurrentTarget: function(event, node) {
          					var currentTarget;
          					if (window.event) // For IE
          						currentTarget = node;
          					else if (event && event.currentTarget) // For Firefox, Opera
          						currentTarget = event.currentTarget;
          					return currentTarget;
          				},
          				findRelatedTarget: function(event) {
          					var relatedTarget;
          					if (window.event) { // For IE
          						if (window.event.fromElement)
          							relatedTarget = window.event.fromElement;
          						else if (window.event.toElement)
          							relatedTarget = window.event.toElement;
          					} else if (event && event.relatedTarget) { // For Firefox, Opera
          						relatedTarget = event.relatedTarget;
          					}
          					return relatedTarget;
          				}
          			};
          		

Convert Mouse Coordinates

          			var CSS = {
          				// Return the position of the element relative to the top-left corner of the document.
          				offset: function(element) {
          					if (!element) return;
							if (typeof element == "string") element = document.getElementById(element);
          					var left = 0, top = 0;
          					for (var elem = element; elem; elem = elem.offsetParent) {
          						left += elem.offsetLeft;
          						top += elem.offsetTop;
          					}
          					for (elem = element.parentNode; elem && elem != document.body; elem = elem.parentNode) {
          						if (elem.scrollLeft) left -= elem.scrollLeft;
          						if (elem.scrollTop) top -= elem.scrollTop;
          					}
          					return {left: left, top: top};
          				}
          			};
          		
Drag and Drop

drag() takes two arguments. The first is the element that is to be dragged. This may be the element on which the mousedown event occurred or a containing element (e.g., you might allow the user to drag on the titlebar of a window to move the entire window).
In either cases, it muse refer to a document element that is absolutely positioned using the CSS position attribute. The second argument is the event object associated with the triggering mousedown event.

drag() records the position of the mousedown event and then registers event handlers for the mousemove and mouseup events that follow the mousedown event. The handler for the mousemove event is responsible for moving the document element, and the handler for the mouseup event is responsible for deregistering itself and the mousemove handler.
It is important to note that the mousemove and mouseup handlers are registered as capturing event handlers because the user may move the mouse faster than the document element can follow it, and some of these events occur outside the original target element. Without capturing, the events may not be dispatched to the correct handlers.
Also, note that the moveHandler() and upHandler() functions that are registered to handle these events are defined as functions nested within drag(). Because they are defined in this nested scope they can use the arugments and local variables of drag(), which considerably simplifies their implementation.

Key Events

  • onKeyDown: A keyboard key is pressed.
  • onKeyPress: A keyboard key is pressed or held down.
  • onKeyUp: A keyboard key is released.

charCode and keyCode

charCode is the integer property specifies for keydown and keyup events and Unicode character code for keypress events. Use String.fromCharCode() to convert character codes to strings.

Related Posts

Jun 04
Types of Errors

  • Syntax Errors
  • Syntax errors are errors in grammar and punctuation such as mismatched quotes or missed commas. These errors are caught quickly if you have the browser’s built-in error detector in display mode or run the script through jsLint.

  • Runtime Errors
  • Runtime errors only show up as the script is executed. Common examples are calling a function that hasn’t been declared (typing error or case-sensitivity issue) or division by zero. Although JavaScript is typeless, many built in objects expect and/or return specific types (eg. style.left needs string type).

  • Logic Errors
  • Logic errors are basic errors in the programmer’s algorithms or procedural errors. Diagnosis only comes when incorrect results occur and solution requires mapping out the flow for test cases. The wrong scoping of a variable is an example of this kind of error.

  • Incorrect Operator Precedence Errors
  • Incorrect operator precedence errors are basic mathematical grouping errors. The best way to avoid them is with brackets to force the order that you want operations to occur explicitly.

  • Browser Implementation Errors
  • Browser implementation errors are quirks that occur in one browser but not others. See Browser Issues for more details. Test your code on all anticipated client browsers!

Global Error Handling

The window object has an event called onerror that is invoked whenever there’s an unhandled error on the page.

As you can see, the event will pass 3 arguments to the invoked function. The first one is the actual error message. The second one is the URL of the file containing the error (useful if the error is in an external.js file.) The last argument is the line number in that file where the error happened.

Returning true tells the browser that you have taken care of the problem. If you return false instead, the browser will proceed to treat the error as unhandled, showing the error message and the status bar icon.

          			var onErrorHandler = function(message, fileName, lineNumber) {
          				var element = document.createElement("p");
          				element.innerHTML = "Error: " + message + "<br />File Name: " + decodeURIComponent(fileName) + "<br />Line: " + lineNumber;
          				document.body.appendChild(element);
          				// Returning true tells the browser that you have taken care of the problem.
          				// If you return false instead, the browser will proceed to treat the error as unhandled, showing the error message and the status bar icon.
          				return true;
          			};
          			window.onerror = onErrorHandler;
          		
Structured Error Handling

If anything goes wrong in the statements that are inside the try block’s statements then the statements in the catch block will be executed and the error will be passed in the error variable. The finally block is optional and, if present, is always executed last, regardless if there was an error caught or not.

The error object has two important properties: name and message. The message property contains the same error message that we have seen before. The name property contains the kind of error that happened and we can use that to decide if we know what to do with that error.

          			function catchError() {
          				var element = document.createElement("p");
          				var html = "";
          				try {
          					var username = window.prompt("Please Enter Your Name: ", "");
          					html = "Your name (" + username + ") has " + username.length + " letters.";
          				} catch(error) {
          					if (error.name == "TypeError")
          						html = error.name + ": " + error.message + "<br />File Name: " + decodeURIComponent(error.fileName) + "<br />Line: " + error.lineNumber;
          					else
          						throw error;
          				} finally {
          					// The finally block is optional and, if present, is always executed last, regardless if there was an error caught or not.
          					element.innerHTML = html;
          					document.body.appendChild(element);
          				}
          			}
          			window.onload = catchError;
          		
Related Posts

May 26
What are cookies?

Cookie

Cookies are small amounts of data stored by the web browser. They allow you to store particular information about a user and retrieve it every time they visit your pages. Each user has their own unique set of cookies.

Cookies are typically used by web servers to perform functions such as tracking your visits to websites, enabling you to log in to sites, and storing your shopping cart.

document.cookie

          			document.cookie = "name=value; expires=date; path=path; domain=domain; secure";
          		
Property
Description

name=value
This sets both the cookie’s name and its value.

expires=date
This optional values sets the date that the cookie will expire on. The date should be in the format returned by the toGMTString() method of the Date object. If the expires value is not given, the cookie will be destroyed the moment the browser is closed.

path=path
This optional value specifies a path within the site to which the cookie applies. Only documents in this path will be able to retrieve the cookie. Usually this is left blank, meaning that only the path that set the cookie can retrieve it.

domain=domain
This optional value specifies a domain within which the cookie applies. Only websites in this domain will be able to retrieve the cookie. Usually this is left blank, meaning that only the domain that set the cookie can retrieve it.

secure
This optional flag indicates that the browser should use SSL when sending the cookie to the server. This flag is really used.

Set a Cookie

          			var COOKIE = {
          				set: function(name, value, options) {
          					if (!name) return;
          					options = options || {};
          					if (!options.expires) options.expires = 1;
          					var date = new Date();
          					date.setTime(date.getTime() + options.expires*24*60*60*1000);
          					var expires = "; expires=" + date.toGMTString();
          					var path = options.path ? '; path=' + (options.path) : '';
          					var domain = options.domain ? '; domain=' + (options.domain) : '';
          					var secure = options.secure ? '; secure' : '';
          					document.cookie = [name, "=", encodeURIComponent(value), expires, path, domain, secure].join("");
          				}
          			};
          		

Retrive a Cookie

          			var COOKIE = {
          				get: function(name) {
          					if (!name) return;
          					var value = "";
          					if (document.cookie && document.cookie != "") {
          						var cookies = document.cookie.split(";");
          						for (var i = 0; i < cookies.length; i++) {
          							var cookie = cookies[i];
          							// Trim the space.
          							while(cookie.charAt(0) == " ") cookie = cookie.substring(1, cookie.length);
          							// Tell if this cookie string begins with the name we want.
          							if (cookie.substring(0, name.length + 1) == (name + "=")) {
          								value = decodeURIComponent(cookie.substring(name.length + 1));
          								break;
          							}
          						}
          					}
          					return value;
          				}
          			};
          		

Delete a Cookie

          			var COOKIE = {
          				del: function(name) {
          					if (!name) return;
          					this.set(name, "", -1);
          				}
          			};
          		
Related Posts

Apr 26
Event Flow

    Javascript Event Handler

  • Event Capturing
  • Netscape maintained that the event on element1 takes place first. This is called event capturing. The event handler of element1 fires first, the event handler of element2 fires last.

     

    Javascript Event Handler

  • Event Bubbling
  • Microsoft maintained that the event on element2 takes precedence. This is called event bubbling. The event handler of element2 fires first, the event handler of element1 fires last.

     

    Javascript Eevent Handler

  • W3C Event Model
  • W3C has very sensibly decided to take a middle position in this struggle. Any event taking place in the W3C event model is first captured until it reaches the target element and then bubbles up again.

The Event Object

Property Name
Description

type
The type of event that occurred. The value of this property is the name of the event type and is the same string value that was used when registering the event handler (e.g., “click” or “mouseover”).

target
The node on which the event occurred, which may not be the same as currentTarget.

currentTarget
The node on which the event is currently being processed. If the event is being processed during the capturing or bubbling phase of propagation, the value of this property is different from the value of the target property.

eventPhase
A number that specifies what phase of event propagation is currently in process. The value of one of the constants Event.CAPTURING_PHASE, EVENT.AT_TARGET, or EVENT_BUBBLING_PHASE.

timeStamp
A Date object that specifies when the event occurred.

bubbles
A boolean that specifies whether this event (and events of this type) bubbles up the document tree.

cancelable
A boolean that specifies whether the event has a default action associated with it that can be canceled with the preventDefault() method.

Method Name
Description

stopPropagation()
Any event handler can call stopPropagation() to prevent the event from being propagated beyond the node at which it is currently being handled.

preventDefault()
Any event handler can call preventDefault() to prevent the browser from performing a default action associated with the event.

W3C Standard
Internet Explorer
Description

type
type
A string that specifies the type of event that occurred.

target
srcElement
The document element on which the event occurred.

currentTarget
none
Not applicable in IE.

eventPhase
none
Not applicable in IE.

timeStamp
none
Not applicable in IE.

stopPropagation()
cancelBubble
A boolean property that, when set to true, prevents the current event from bubbling any further up the element containment hierarchy.

preventDefault()
returnValue
A boolean property that can be set to false to prevent the browser from performing the default action associated with the event.

The IE Event Object as a Global Variable

          			function onMouseDownHandler(event) {
          				var event = event || window.event; // IE stores events in window object.
          			}
          			element.onmousedown = onMouseDownHandler;
          		

currentTarget and relatedTarget/fromElement and toElement

          			var GENERIC = {
          				findCurrentTarget: function(event, node) {
          					var currentTarget;
          					if (window.event) // For IE
          						currentTarget = node;
          					else if (event && event.currentTarget) // For Firefox, Opera
          						currentTarget = event.currentTarget;
          					return currentTarget;
          				},
          				findRelatedTarget: function(event) {
          					var relatedTarget;
          					if (window.event) { // For IE
          						if (window.event.fromElement)
          							relatedTarget = window.event.fromElement;
          						else if (window.event.toElement)
          							relatedTarget = window.event.toElement;
          					} else if (event && event.relatedTarget) { // For Firefox, Opera
          						relatedTarget = event.relatedTarget;
          					}
          					return relatedTarget;
          				}
          			};
          		

Turn all capturing and bubbling off

					var GENERIC = {
						stopPropagation: function(event) {
							if (window.event) // For IE
								window.event.cancelBubble = true;
							if (event && event.stopPropagation) // For Modern Browsers
								event.stopPropagation();
						}
					};
				

Prevent Default Action

					var GENERIC = {
						cancelDefault: function(event) {
							if (window.event) // For IE
								window.event.returnValue = false;
							if (event && event.preventDefault) // For Modern Browsers
								event.preventDefault();
						}
					};
				
Event Handler Registration

  • Example One
  •           				// Add Event Handlers to The Element
              				element.onclick = doSomething;
              			
              				// Remove Event Handlers
              				element.onclick = null;
              			
  • Example Two: attachEvent() and addEventListener()
  •           				// Add Event Handlers to The Element
              				if (element.attachEvent) { // For IE
              					element.attachEvent("onclick", doSomething);
              				} else if (element.addListener) { // For Modern Browsers
              					element.addEventListener("click", doSomething, false);
              				}
              			
              				// Remove Event Handlers
              				if (element.detachEvent) { // For IE
              					element.detachEvent("onclick", doSomething);
              				} else if (element.removeListener) { // For Modern Browsers
              					element.removeEventListener("click", doSomething, false);
              				}
              			

    attachEvent() and the this keyword

    Event handlers registered with attachEvent() are invoked as global functions instead of as methods of the element on which they are registered. This means that the this keyword refers to the global window object. It is compounded, however, by the fact that the IE event object has no equivalent to the DOM currentTarget property. srcElement specifies the element that generated the event, but if the event has bubbled, this may be different from the element that is handling the event.

    Arguments to addEventListener()

    The final argument to addEventListener() is a boolean value. If true, the specified event handler captures events during the capturing phase of event propagation. If the argument is false, the event handler is a normal event handler and is triggered when the event directly on the object or on a descendant of the element and subsequently bubbles up to the element.

    addEventListener() and the this keyword

    When a function is registered as an event handler for a document element, it becomes a method of that document element. When the event handler is invoked, it is invoked as a method of the element, and, within the function, the this keyword refers to the element on which the event occurred.

  • Example Three: Register Objects as Event Handlers
  •           				var GENERIC = {
              					// Fix the bug the "this" keyword refers to the global window object when event handlers registered with attachEvent() are invoked as global functions instead of as methods of the element on which they are registered.
              					addEvent: function(obj, type, fn) {
              						if (!obj) return;
              						if (obj.attachEvent) { // For IE
              							obj["e"+type+fn] = fn;
              							obj[type+fn] = function(){obj["e"+type+fn](window.event);}
              							obj.attachEvent("on"+type, obj[type+fn]);
              						} else if (obj.addEventListener) { // For Modern Browsers
              							obj.addEventListener(type, fn, false);
              						}
              					},
              					removeEvent: function(obj, type, fn) {
              						if (!obj) return;
              						if (obj.detachEvent) { // For IE
              							obj["e"+type+fn] = fn;
              							obj[type+fn] = function(){obj["e"+type+fn](window.event);}
              							obj.detachEvent("on"+type, obj[type+fn]);
              						} else if (obj.removeEventListener) { // For Modern Browsers
              							obj.removeEventListener(type, fn, false);
              						}
              					}
              				};
              			
              				function changeBackground() {
              					this.style.backgroundColor = "#000"; // "this" refers to the element
              				}
              				GENERIC.addEvent(element, "click", changeBackground);
              				GENERIC.removeEvent(element, "click", changeBackground);
              			
Related Posts

Apr 21
Dynamic Style Loading

          			var HTTPUTILITY =  {
						getStyle: function(url, callback) {
							var isLoaded = false;
							var style = document.createElement("link");
							style.setAttribute("rel", "stylesheet");
							style.setAttribute("type", "text/css");
							style.setAttribute("href", url);
							style.onload = style.onreadystatechange = function() {
								if (!isLoaded && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
									isLoaded = true;
									if (typeof callback === "function")
										callback();
									if (this.tagName.toLowerCase() == "link")
										document.getElementsByTagName("head")[0].removeChild(this);
								}
							}
							var head = document.getElementsByTagName("head")[0];
							head.appendChild(style);
						}
          			};
          		
          			function complete() {
          				alert("complete");
          			}
          			HTTPUTILITY.getStyle("myStyle.css", function(){complete();});
          		
Related Posts

Apr 20
Comparison with XMLHttpRequest()

Advantages

  • Can request a file from anywhere on the net, not just the server your page was loaded from.
  • Works in IE even when ActiveX is turned off (though not when Javascript is turned off).
  • Works with a few older browsers that don’t support XMLHttpRequest, like Opera 7 (though not Macintosh versions of IE).

Disadvantages

  • Returned data has to be formatted as Javascript code. XMLHttpRequest() can be used to fetch data in any format, XML, JSON, plain text, or whatever.
  • Can only do GET requests, not POST requests.
  • Whether the request is synchronous or asynchronous is pot luck, depending on the browser. With XMLHttpRequest() you can control this.
  • When fetching JSON data from an untrusted source, there is no possiblity of checking the data before feeding it to the Javascript parser. With XMLHttpRequest() you can parse the data with something like json2.js instead of eval() for secure parsing.
Load Only Once

					var script = document.createElement("script");
					script.setAttribute("language", "javascript");
					script.setAttribute("type", "text/javascript");
					script.setAttribute("src", url);
					var head = document.getElementsByTagName("head")[0];
					head.appendChild(script);
          		
Multiple Loads

  • Cache
  • First, you need to worry about caching. Typically, the url you’re going to be loading is going to be some kind of CGI program. After all, if the output doesn’t vary, why bother loading it more than once? Usually browsers are fairly smart about not caching those, but you might want to take some steps to ensure that the second call doesn’t just get you the cached copy of the result of the first call. So the CGI should probably be outputting headers to suppress caching. You might also put extra arguments on the URL, perhaps by keeping a count of the number of times you’ve called it, and adding a “?count=7″ argument onto the end of the URL (where 7 is the current count). This makes the URL different on each call, and further ensures that you won’t get a cached copy.

  • Delete Script
  • Second, you’ll tend to accumulate a lot of <script> tags in your header. This doesn’t necessarily do a whole lot of harm, but it seems sloppy. So you could probably delete them by doing head.removeChild(script). I think you can actually have the callback function do this immediately after loading. Removing the <script> tag does not undefine functions or variables that were defined by it, so you are done with it the moment it is done loading.

Detect Load Completion

After we have loaded the helper code, we obviously want to call it to start it running. However, we can’t just put a call to complete() after the commands above, because the browser may be loading the “myScript.js” file asynchronously, which means that our call may occur before the function has finished (or even started) loading.

Here we set up two different event handlers on the newly created script tag. Depending on the browser, one or the other of these two handlers is supposed to be called when the script has finished loading. The onreadystatechange handler works on IE only. The onload handler works on Gecko browsers and Opera.

The readyState theoretically goes through a series of states:

0 uninitialized
1 loading
2 loaded
3 interactive
4 complete

          			var HTTPUTILITY =  {
						getScript: function(url, callback) {
							var isLoaded = false;
							var script = document.createElement("script");
							script.setAttribute("language", "javascript");
							script.setAttribute("type", "text/javascript");
							script.setAttribute("src", url);
							script.onload = script.onreadystatechange = function() {
								if (!isLoaded && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
									isLoaded = true;
									if (typeof callback === "function")
										callback();
									if (this.tagName.toLowerCase() == "script")
										document.getElementsByTagName("head")[0].removeChild(this);
								}
							}
							var head = document.getElementsByTagName("head")[0];
							head.appendChild(script);
						}
          			};
          		
          			function complete() {
          				alert("complete");
          			}
          			HTTPUTILITY.getScript("myScript.js", function(){complete();});
          		
document.write

          			document.write('<' + 'script type="text/javascript" src="http://www.lingihuang.com/libraries/library.js"' + '><' + '/script>');
          		
Related Posts

Apr 15
Disable Text Selection

  • With CSS
  •           				<div unselectable="on"></div> /* For IE */
              			
              				.classname {
              					user-select: none;
              					-moz-user-select: none; /* For Firefox */
              					-khtml-user-select: none; /* For Safari */
              					-o-user-select: none; /* For Opera */
              				}
              			
  • With Javascript
  •           				var disableTextSelection = function(element) {
              					element.unselectable = "on"; /* For IE */
              					element.style.UserSelect = "none";
              					element.style.MozUserSelect = "none"; /* For Firefox */
              					element.style.KhtmlUserSelect = "none"; /* For Safari */
              					element.style.OUserSelect = "none"; /* For Opera */
              				};