1 // $Id: drupal.js 144 2007-03-28 07:52:20Z thierry $
4 * Only enable Javascript functionality if all required features are supported.
6 function isJsEnabled() {
7 if (typeof document.jsEnabled == 'undefined') {
8 // Note: ! casts to boolean implicitly.
9 document.jsEnabled = !(
10 !document.getElementsByTagName ||
11 !document.createElement ||
12 !document.createTextNode ||
13 !document.documentElement ||
14 !document.getElementById);
16 return document.jsEnabled;
19 // Global Killswitch on the <html> element
21 document.documentElement.className = 'js';
25 * Make IE's XMLHTTP object accessible through XMLHttpRequest()
27 if (typeof XMLHttpRequest == 'undefined') {
28 XMLHttpRequest = function () {
29 var msxmls = ['MSXML3', 'MSXML2', 'Microsoft']
30 for (var i=0; i < msxmls.length; i++) {
32 return new ActiveXObject(msxmls[i]+'.XMLHTTP')
36 throw new Error("No XML component installed!");
41 * Creates an HTTP GET request and sends the response to the callback function.
43 * Note that dynamic arguments in the URI should be escaped with encodeURIComponent().
45 function HTTPGet(uri, callbackFunction, callbackParameter) {
46 var xmlHttp = new XMLHttpRequest();
48 if (!callbackFunction) {
51 xmlHttp.open('GET', uri, bAsync);
55 if (callbackFunction) {
56 xmlHttp.onreadystatechange = function() {
57 if (xmlHttp.readyState == 4) {
58 callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
65 return xmlHttp.responseText;
70 * Creates an HTTP POST request and sends the response to the callback function
72 * Note: passing null or undefined for 'object' makes the request fail in Opera 8.
73 * Pass an empty string instead.
75 function HTTPPost(uri, callbackFunction, callbackParameter, object) {
76 var xmlHttp = new XMLHttpRequest();
78 if (!callbackFunction) {
81 xmlHttp.open('POST', uri, bAsync);
84 if (typeof object == 'object') {
85 xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
86 for (var i in object) {
87 toSend += (toSend ? '&' : '') + i + '=' + encodeURIComponent(object[i]);
96 if (callbackFunction) {
97 xmlHttp.onreadystatechange = function() {
98 if (xmlHttp.readyState == 4) {
99 callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
106 return xmlHttp.responseText;
111 * Redirects a button's form submission to a hidden iframe and displays the result
112 * in a given wrapper. The iframe should contain a call to
113 * window.parent.iframeHandler() after submission.
115 function redirectFormButton(uri, button, handler) {
116 // (Re)create an iframe to target.
120 button.onmouseover = button.onfocus = function() {
121 button.onclick = function() {
122 // Prepare variables for use in anonymous function.
124 var action = button.form.action;
125 var target = button.form.target;
127 // Redirect form submission
128 this.form.action = uri;
129 this.form.target = 'redirect-target';
133 // Set iframe handler for later
134 window.iframeHandler = function () {
135 var iframe = $('redirect-target');
136 // Restore form submission
137 button.form.action = action;
138 button.form.target = target;
140 // Get response from iframe body
142 response = (iframe.contentWindow || iframe.contentDocument || iframe).document.body.innerHTML;
143 // Firefox 1.0.x hack: Remove (corrupted) control characters
144 response = response.replace(/[\f\n\r\t]/g, ' ');
146 // Opera-hack: it returns innerHTML sanitized.
147 response = response.replace(/"/g, '"');
154 $('redirect-target').onload = null;
155 $('redirect-target').src = 'about:blank';
157 response = parseJson(response);
158 // Check response code
159 if (response.status == 0) {
160 handler.onerror(response.data);
163 handler.oncomplete(response.data);
169 button.onmouseout = button.onblur = function() {
170 button.onclick = null;
175 * Adds a function to the window onload event
177 function addLoadEvent(func) {
178 var oldOnload = window.onload;
179 if (typeof window.onload != 'function') {
180 window.onload = func;
183 window.onload = function() {
191 * Adds a function to a given form's submit event
193 function addSubmitEvent(form, func) {
194 var oldSubmit = form.onsubmit;
195 if (typeof oldSubmit != 'function') {
196 form.onsubmit = func;
199 form.onsubmit = function() {
200 return oldSubmit() && func();
206 * Retrieves the absolute position of an element on the screen
208 function absolutePosition(el) {
209 var sLeft = 0, sTop = 0;
210 var isDiv = /^div$/i.test(el.tagName);
211 if (isDiv && el.scrollLeft) {
212 sLeft = el.scrollLeft;
214 if (isDiv && el.scrollTop) {
217 var r = { x: el.offsetLeft - sLeft, y: el.offsetTop - sTop };
218 if (el.offsetParent) {
219 var tmp = absolutePosition(el.offsetParent);
226 function dimensions(el) {
227 return { width: el.offsetWidth, height: el.offsetHeight };
231 * Returns true if an element has a specified class name
233 function hasClass(node, className) {
234 if (node.className == className) {
237 var reg = new RegExp('(^| )'+ className +'($| )')
238 if (reg.test(node.className)) {
245 * Adds a class name to an element
247 function addClass(node, className) {
248 if (hasClass(node, className)) {
251 node.className += ' '+ className;
256 * Removes a class name from an element
258 function removeClass(node, className) {
259 if (!hasClass(node, className)) {
262 // Replaces words surrounded with whitespace or at a string border with a space. Prevents multiple class names from being glued together.
263 node.className = eregReplace('(^|\\s+)'+ className +'($|\\s+)', ' ', node.className);
268 * Toggles a class name on or off for an element
270 function toggleClass(node, className) {
271 if (!removeClass(node, className) && !addClass(node, className)) {
278 * Emulate PHP's ereg_replace function in javascript
280 function eregReplace(search, replace, subject) {
281 return subject.replace(new RegExp(search,'g'), replace);
285 * Removes an element from the page
287 function removeNode(node) {
288 if (typeof node == 'string') {
291 if (node && node.parentNode) {
292 return node.parentNode.removeChild(node);
300 * Prevents an event from propagating.
302 function stopEvent(event) {
303 if (event.preventDefault) {
304 event.preventDefault();
305 event.stopPropagation();
308 event.returnValue = false;
309 event.cancelBubble = true;
314 * Parse a JSON response.
316 * The result is either the JSON object, or an object with 'status' 0 and 'data' an error message.
318 function parseJson(data) {
319 if (data.substring(0,1) != '{') {
320 return { status: 0, data: data.length ? data : 'Unspecified error' };
322 return eval('(' + data + ');');
326 * Create an invisible iframe for form submissions.
328 function createIframe() {
329 // Delete any previous iframe
331 // Note: some browsers require the literal name/id attributes on the tag,
332 // some want them set through JS. We do both.
333 window.iframeHandler = function () {};
334 var div = document.createElement('div');
335 div.id = 'redirect-holder';
336 div.innerHTML = '<iframe name="redirect-target" id="redirect-target" class="redirect" onload="window.iframeHandler();"></iframe>';
337 var iframe = div.firstChild;
339 name = 'redirect-target';
340 setAttribute('name', 'redirect-target');
341 id = 'redirect-target';
343 with (iframe.style) {
344 position = 'absolute';
347 visibility = 'hidden';
349 document.body.appendChild(div);
353 * Delete the invisible iframe for form submissions.
355 function deleteIframe() {
356 var holder = $('redirect-holder');
357 if (holder != null) {
363 * Wrapper around document.getElementById().
366 return document.getElementById(id);