1// $Id: functions.js 40080 2026-06-17 10:11:10Z warren $ 2 3//--- Init JS code ---------------------------------- 4 5(function() { 6 // Avoid console errors in browsers that lack a console (borrowed from H5BP) 7 var method; 8 var noop = function () {}; 9 var methods = [ 10 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 11 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 12 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 13 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' 14 ]; 15 var length = methods.length; 16 var console = (window.console = window.console || {}); 17 18 while (length--) { 19 method = methods[length]; 20 21 // Only stub undefined methods. 22 if (!console[method]) { 23 console[method] = noop; 24 } 25 } 26}()); 27 28//--- Browser polyfills ------------------------------------ 29 30function getElementsByClassName (className, tag, elm){ 31 var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)"); 32 var tag = tag || "*"; 33 var elm = elm || document; 34 var elements = (tag == "*" && elm.all) ? elm.all : elm.getElementsByTagName(tag); 35 var returnElements = []; 36 var current; 37 var length = elements.length; 38 for (var i = 0; i < length; i++) { 39 current = elements[i]; 40 if (testClass.test(current.className)) { 41 returnElements.push(current); 42 } 43 } 44 return returnElements; 45} 46 47// Add support for the array push method in IE 5 48if (typeof Array.prototype.push != "function") { 49 Array.prototype.push = ArrayPush; 50 function ArrayPush(value) { 51 this[this.length] = value; 52 } 53} 54 55if (typeof Object.assign != 'function') { 56 // Sourced from: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 57 Object.assign = function(target, varArgs) { // .length of function is 2 58 'use strict'; 59 if (target == null) { // TypeError if undefined or null 60 throw new TypeError('Cannot convert undefined or null to object'); 61 } 62 63 var to = Object(target); 64 65 for (var index = 1; index < arguments.length; index++) { 66 var nextSource = arguments[index]; 67 68 if (nextSource != null) { // Skip over if undefined or null 69 for (var nextKey in nextSource) { 70 // Avoid bugs when hasOwnProperty is shadowed 71 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 72 to[nextKey] = nextSource[nextKey]; 73 } 74 } 75 } 76 } 77 return to; 78 }; 79} 80 81//--- Utility functions ------------------------------------ 82 83function $() { /* jQuery-like function */ 84 var elements = new Array(); 85 for (var i = 0; i < arguments.length; i++) { 86 var element = arguments[i]; 87 if (typeof element == 'string') element = document.getElementById(element); 88 if (arguments.length == 1) return element; 89 elements.push(element); 90 } 91 return elements; 92} 93 94// Implement a PHP-like function to check if a value exists in an array 95function inArray (needle, haystack, strict) { 96 if (typeof haystack == 'undefined') { 97 return false; 98 } 99 var length = haystack.length; 100 if (typeof strict == 'undefined' || (typeof strict == 'number' && strict < 0)) { 101 strict = false; 102 } 103 for (var i = 0; i < length; i++) { 104 if ((strict && haystack[i] === needle) || (!strict && haystack[i] == needle)) { 105 return true; 106 } 107 } 108 return false; 109} 110 111// Implement a PHP-like function to recursively count the number of occurrences of a substring 112function substrCount (str, substr, start, foundCount) { 113 foundCount = (typeof foundCount != "undefined") ? foundCount : 0; 114 start = (typeof start != "undefined") ? start : 0; 115 var pos = str.indexOf(substr, start); 116 if (!(pos == -1)) { 117 foundCount = substrCount(str, substr, pos + 1, foundCount + 1); 118 } 119 return foundCount; 120} 121
122/* 123http://onlinetools.org/articles/unobtrusivejavascript/cssjsseparation.html 124 125a defines the action you want the function to perform. 126o the object in question. 127c1 the name of the first class 128c2 the name of the second class 129 130Possible actions are: 131swap replaces class c1 with class c2 in object o. 132add adds class c1 to the object o. 133remove removes class c1 from the object o. 134check test if class c1 is already applied to object o and returns true or false. 135*/ 136function multipleClasses (a, o, c1, c2) { 137 switch (a) { 138 case "swap": 139 o.className =! multipleClasses("check", o, c1) ? o.className.replace(c2, c1) : o.className.replace(c1, c2); 140 break; 141 142 case "add": 143 if (!multipleClasses("check", o, c1)) { 144 o.className += o.className ? ' ' + c1 : c1; 145 } 146 break; 147 148 case "remove": 149 var rep = o.className.match(" " + c1) ? " " + c1 : c1; 150 o.className = o.className.replace(rep, ""); 151 break; 152 153 case "check": 154 return new RegExp('\\b'+c1+'\\b').test(o.className); 155 break; 156 } 157} 158 159// Returns true if Google Gears is installed, otherwise false 160function gearsInstalled () { 161 var gearsResult = false;
162 if (typeof google != 'undefined' && typeof google.gears != 'undefined') { 163 gearsResult = true; 164 } 165 return gearsResult; 166} 167 168function setRawCookie (name, value, expires, path, domain, secure) { 169 if (typeof expires === 'string' && (/^\d+$/).test(expires)) { 170 expires = parseInt(expires, 10); 171 } 172 173 if (expires instanceof Date) { 174 expires = expires.toGMTString(); 175 } else if (typeof expires === 'number') { 176 var date = new Date(); 177 date.setTime(date.getTime() + (expires * 24 * 60 * 60 * 1000)); 178 expires = date.toGMTString(); 179 } 180 181 var r = [name + '=' + value], s = {}, i = ''; 182 s = { 183 expires: expires, 184 path: path, 185 domain: domain 186 }; 187 for (i in s) { 188 if (s.hasOwnProperty(i)) { 189 s[i] && r.push(i + '=' + s[i]); 190 } 191 } 192 193 return secure && r.push('secure'), document.cookie = r.join(';'), true; 194} 195 196function setCookie (name, value, expires, path, domain, secure) { 197 return setRawCookie(name, encodeURIComponent(value), expires, path, domain, secure); 198} 199 200function getCookie (name) { 201 var cookies = document.cookie.split('; '); 202 203 for (var i = cookies.length - 1; i >= 0; i--) { 204 var cookie = cookies[i].split('='); 205 if (name == cookie[0]) { 206 return decodeURIComponent(cookie[1]); 207 } 208 } 209 210 return null; 211} 212 213function deleteCookie (name) { 214 setCookie(name, '', -1); 215} 216 217function isOldBlackberry () { 218 var userAgent = navigator.userAgent.toLowerCase(); 219 return (userAgent.indexOf("blackberry") >= 0 && userAgent.indexOf("webkit") == -1); 220} 221 222// Escape html entities for XSS prevention on the JS side 223function escapeHtml (text) { 224 return text 225 .replace(/&/g, "&") 226 .replace(/</g, "<") 227 .replace(/>/g, ">") 228 .replace(/"/g, """) 229 .replace(/'/g, "'"); 230} 231 232// Returns a dateTime string (Y-m-d H:i:s). The dateTime returned will be a reflection of the time currently set on the users device. 233function getCurrentClientDateTime (serverTime, secondsToAdd, friendlyDateFormat) { 234 serverTime = serverTime.replace(/-/g,"/"); // Required to convert serverTime string into date object 235 var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 236 var currentDate = new Date(serverTime); 237 currentDate = new Date(currentDate .getTime() + (secondsToAdd * 1000)); 238 239 var months = (currentDate.getMonth() < 9) ? "0" + (currentDate.getMonth() + 1) : (currentDate.getMonth() + 1); 240 var days = (currentDate.getDate() < 10) ? "0" + currentDate.getDate() : currentDate.getDate(); 241 var hours = (currentDate.getHours() < 10) ? "0" + currentDate.getHours() : currentDate.getHours(); 242 var minutes = (currentDate.getMinutes() < 10) ? "0" + currentDate.getMinutes() : currentDate.getMinutes(); 243 var seconds = (currentDate.getSeconds() < 10) ? "0" + currentDate.getSeconds() : currentDate.getSeconds(); 244 245 if (friendlyDateFormat) { 246 if (varStrings["rwd2015"]) { 247 var clientDataTime = hours + ":" + minutes; 248 } else { 249 var clientDataTime = days + " " 250 + monthNames[currentDate.getMonth()] + " " 251 + currentDate.getFullYear() + ", " 252 + hours + ":" 253 + minutes; 254 } 255 } else { 256 var clientDataTime = currentDate.getFullYear() + "-" 257 + months + "-" 258 + days + " " 259 + hours + ":" 260 + minutes + ":" 261 + seconds; 262 } 263 264 return clientDataTime; 265} 266 267// Returns a date string e.g. "15 June 2014". 268function getCurrentClientDate () { 269 var currentDate = new Date(); 270 var day = currentDate.getDate(); 271 var month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][currentDate.getMonth()]; 272 var year = currentDate.getFullYear(); 273 274 return day + " " + month + " " + year; 275} 276 277// jQuery function that is equivalent to the Prototype's toQueryParams method, returns all parameters as a JS object 278function toQueryParams (url) { 279 var params = {}; 280 if (!url) { 281 return params; 282 } 283 var urlParam = url.replace(/(^\?)/,'').split("&"); 284 urlParam.forEach(function (param) { 285 var kvPair = param.split("="); 286 var key = decodeURIComponent(kvPair[0] || ""); 287 var value = decodeURIComponent(kvPair[1] || ""); 288 if (key) { 289 params[key] = value; 290 } 291 }); 292 return params; 293} 294 295function goPage (list) { 296 var quickNavList = (list != null) ? list : document.quicknavForm.quicknav; 297 var newPage = quickNavList.options[quickNavList.selectedIndex].value; 298 document.location.href = newPage; 299} 300 301// Toggle a password input field type between "password" and "text" 302function togglePasswordField (passwordElement, showPasswordElement) { 303 var passwordInput = document.getElementById(passwordElement); 304 var togglePasswordButton = document.getElementById(showPasswordElement); 305 if (passwordInput.type === 'password') { 306 passwordInput.type = 'text'; 307 togglePasswordButton.setAttribute('aria-label', valStrings["hidePasswordLabel"]); 308 } else { 309 passwordInput.type = 'password'; 310 togglePasswordButton.setAttribute('aria-label', valStrings["showPasswordLabel"]); 311 } 312 passwordInput.focus(); 313} 314 315// Disable page zooming for mobile browsers 316function viewportZoomDisable () { 317 $('head meta[name=viewport]').remove(); 318 $('head').prepend('<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, user-scalable=0" />'); 319} 320 321// Enable page zooming in mobile browsers 322function viewportZoomEnable () { 323 $('head meta[name=viewport]').remove(); 324 $('head').prepend('<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, user-scalable=1" />'); 325} 326 327// Copy content to the clipboard. 328function copyToClipboard(source, target, successResponse, errorResponse) { 329 var copyValue; 330 if (navigator.clipboard) { 331 if ($(target).is(':input')) { 332 copyValue = $(target).val(); 333 } else {
334 copyValue = $(target)[0].innerText; 335 } 336 if (copyValue != "") { 337 navigator.clipboard.writeText(copyValue) 338 .then(function() { 339 // clipboard successfully set 340 forceTriggerTooltip(source, successResponse); 341 }, function() { 342 // clipboard write failed 343 forceTriggerTooltip(source, errorResponse); 344 }); 345 } 346 } 347} 348 349// Mimic a tooltip trigger event 350function forceTriggerTooltip (source, value) { 351 if (typeof window.jQuery.fn.tipsy != 'undefined') { 352 $(source).tipsy({gravity: $.fn.tipsy.autoBounds("auto", 's'), opacity: 1}); 353 $(source).attr('title',value); 354 $(source).trigger('mouseenter'); 355 $(source).removeAttr('title'); 356 $(source).attr('original-title', ''); 357 } 358} 359 360// Standard bitshift implementation of the djb2 hashing algorithm 361function djb2 (str) { 362 var hash = 5381; // magic constant 363 var len = str.length; 364 365 for (var i = 0; i < len; i++) { 366 hash = ((hash << 5) + hash) + str.charCodeAt(i); 367 } 368 369 return hash >>> 0; 370} 371 372// Alternative XOR implementation of the djb2 hashing algorithm 373function djb2Xor (str) { 374 var hash = 5381; // magic constant 375 var len = str.length; 376 377 for (var i = 0; i < len; i++) { 378 hash = (hash * 33) ^ str.charCodeAt(i); 379 } 380 381 return hash >>> 0; 382}
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.