1// $Id: drupal.js,v 1.22.2.1 2006/05/29 14:23:32 killes Exp $ 2 3/** 4 * Only enable Javascript functionality if all required features are supported. 5 */ 6function 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); 15 } 16 return document.jsEnabled; 17} 18 19// Global Killswitch on the <html> element 20if (isJsEnabled()) { 21 document.documentElement.className = 'js'; 22} 23 24/** 25 * Make IE's XMLHTTP object accessible through XMLHttpRequest() 26 */ 27if (typeof XMLHttpRequest == 'undefined') { 28 XMLHttpRequest = function () { 29 var msxmls = ['MSXML3', 'MSXML2', 'Microsoft'] 30 for (var i=0; i < msxmls.length; i++) { 31 try { 32 return new ActiveXObject(msxmls[i]+'.XMLHTTP') 33 } 34 catch (e) { } 35 } 36 throw new Error("No XML component installed!"); 37 } 38} 39 40/** 41 * Creates an HTTP GET request and sends the response to the callback function. 42 * 43 * Note that dynamic arguments in the URI should be escaped with encodeURIComponent(). 44 */ 45function HTTPGet(uri, callbackFunction, callbackParameter) { 46 var xmlHttp = new XMLHttpRequest(); 47 var bAsync = true; 48 if (!callbackFunction) { 49 bAsync = false; 50 } 51 xmlHttp.open('GET', uri, bAsync); 52 xmlHttp.send(null); 53 54 if (bAsync) { 55 if (callbackFunction) { 56 xmlHttp.onreadystatechange = function() { 57 if (xmlHttp.readyState == 4) { 58 callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter); 59 } 60 } 61 } 62 return xmlHttp; 63 } 64 else { 65 return xmlHttp.responseText; 66 } 67} 68 69/** 70 * Creates an HTTP POST request and sends the response to the callback function 71 * 72 * Note: passing null or undefined for 'object' makes the request fail in Opera 8. 73 * Pass an empty string instead. 74 */ 75function HTTPPost(uri, callbackFunction, callbackParameter, object) { 76 var xmlHttp = new XMLHttpRequest(); 77 var bAsync = true; 78 if (!callbackFunction) { 79 bAsync = false; 80 } 81 xmlHttp.open('POST', uri, bAsync); 82 83 var toSend = ''; 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]); 88 } 89 } 90 else { 91 toSend = object; 92 } 93 xmlHttp.send(toSend); 94 95 if (bAsync) { 96 if (callbackFunction) { 97 xmlHttp.onreadystatechange = function() { 98 if (xmlHttp.readyState == 4) { 99 callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter); 100 } 101 } 102 } 103 return xmlHttp; 104 } 105 else { 106 return xmlHttp.responseText; 107 } 108} 109 110/** 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. 114 */ 115function redirectFormButton(uri, button, handler) { 116 // (Re)create an iframe to target. 117 createIframe(); 118 119 // Trap the button 120 button.onmouseover = button.onfocus = function() { 121 button.onclick = function() { 122 // Prepare variables for use in anonymous function. 123 var button = this; 124 var action = button.form.action; 125 var target = button.form.target; 126 127 // Redirect form submission 128 this.form.action = uri; 129 this.form.target = 'redirect-target'; 130 131 handler.onsubmit(); 132 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; 139 140 // Get response from iframe body 141 try { 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, ' '); 145 if (window.opera) { 146 // Opera-hack: it returns innerHTML sanitized. 147 response = response.replace(/"/g, '"'); 148 } 149 } 150 catch (e) { 151 response = null; 152 } 153 154 $('redirect-target').onload = null; 155 $('redirect-target').src = 'about:blank'; 156 157 response = parseJson(response); 158 // Check response code 159 if (response.status == 0) { 160 handler.onerror(response.data); 161 return; 162 } 163 handler.oncomplete(response.data); 164 } 165 166 return true; 167 } 168 } 169 button.onmouseout = button.onblur = function() { 170 button.onclick = null; 171 } 172} 173 174/** 175 * Adds a function to the window onload event 176 */ 177function addLoadEvent(func) { 178 var oldOnload = window.onload; 179 if (typeof window.onload != 'function') { 180 window.onload = func; 181 } 182 else { 183 window.onload = function() { 184 oldOnload(); 185 func(); 186 } 187 } 188} 189 190/** 191 * Adds a function to a given form's submit event 192 */ 193function addSubmitEvent(form, func) { 194 var oldSubmit = form.onsubmit; 195 if (typeof oldSubmit != 'function') { 196 form.onsubmit = func; 197 } 198 else { 199 form.onsubmit = function() { 200 return oldSubmit() && func(); 201 } 202 } 203} 204 205/** 206 * Retrieves the absolute position of an element on the screen 207 */ 208function 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; 213 } 214 if (isDiv && el.scrollTop) { 215 sTop = el.scrollTop; 216 } 217 var r = { x: el.offsetLeft - sLeft, y: el.offsetTop - sTop }; 218 if (el.offsetParent) { 219 var tmp = absolutePosition(el.offsetParent); 220 r.x += tmp.x; 221 r.y += tmp.y; 222 } 223 return r; 224}; 225 226function dimensions(el) { 227 return { width: el.offsetWidth, height: el.offsetHeight }; 228} 229 230/** 231 * Returns true if an element has a specified class name 232 */ 233function hasClass(node, className) { 234 if (node.className == className) { 235 return true; 236 } 237 var reg = new RegExp('(^| )'+ className +'($| )') 238 if (reg.test(node.className)) { 239 return true; 240 } 241 return false; 242} 243 244/** 245 * Adds a class name to an element 246 */ 247function addClass(node, className) { 248 if (hasClass(node, className)) { 249 return false; 250 } 251 node.className += ' '+ className; 252 return true; 253} 254 255/** 256 * Removes a class name from an element 257 */ 258function removeClass(node, className) { 259 if (!hasClass(node, className)) { 260 return false; 261 } 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); 264 return true; 265} 266 267/** 268 * Toggles a class name on or off for an element 269 */ 270function toggleClass(node, className) { 271 if (!removeClass(node, className) && !addClass(node, className)) { 272 return false; 273 } 274 return true; 275} 276 277/** 278 * Emulate PHP's ereg_replace function in javascript 279 */ 280function eregReplace(search, replace, subject) { 281 return subject.replace(new RegExp(search,'g'), replace); 282} 283 284/** 285 * Removes an element from the page 286 */ 287function removeNode(node) { 288 if (typeof node == 'string') { 289 node = $(node); 290 } 291 if (node && node.parentNode) { 292 return node.parentNode.removeChild(node); 293 } 294 else { 295 return false; 296 } 297} 298 299/** 300 * Prevents an event from propagating. 301 */ 302function stopEvent(event) { 303 if (event.preventDefault) { 304 event.preventDefault(); 305 event.stopPropagation(); 306 } 307 else { 308 event.returnValue = false; 309 event.cancelBubble = true; 310 } 311} 312 313/** 314 * Parse a JSON response. 315 * 316 * The result is either the JSON object, or an object with 'status' 0 and 'data' an error message. 317 */ 318function parseJson(data) { 319 if (data.substring(0,1) != '{') { 320 return { status: 0, data: data.length ? data : 'Unspecified error' }; 321 } 322 return eval('(' + data + ');'); 323} 324 325/** 326 * Create an invisible iframe for form submissions. 327 */ 328function createIframe() { 329 // Delete any previous iframe 330 deleteIframe(); 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; 338 with (iframe) { 339 name = 'redirect-target'; 340 setAttribute('name', 'redirect-target'); 341 id = 'redirect-target'; 342 } 343 with (iframe.style) { 344 position = 'absolute'; 345 height = '1px'; 346 width = '1px'; 347 visibility = 'hidden'; 348 } 349 document.body.appendChild(div); 350} 351 352/** 353 * Delete the invisible iframe for form submissions. 354 */ 355function deleteIframe() { 356 var holder = $('redirect-holder'); 357 if (holder != null) { 358 removeNode(holder); 359 } 360} 361 362/** 363 * Wrapper around document.getElementById(). 364 */ 365function $(id) { 366 return document.getElementById(id); 367}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.