1/** 2 * ExtraWatch - A real-time ajax monitor and live stats 3 * @license http://www.gnu.org/licenses/gpl-3.0.txt GNU General Public License v3 4 * @copyright (C) by CodeGravity.com - All rights reserved! 5 * @website http://www.codegravity.com 6 */ 7 8var ew_Utf8Encoder = { //added ex_ to avoid conflicts 9 /** Credits: http://www.webtoolkit.info/javascript-url-decode-encode.html **/ 10 11// URL utf-8 encoding 12 encode : function (str) { 13 return escape(ew_Utf8Encoder._utf8_encode(str)); 14 }, 15 16// UTF-8 encoding 17 _utf8_encode : function (str) { 18 str = str.replace(/\r\n/g,"\n"); 19 var encoded_str = ""; 20 21 for (var n = 0; n < str.length; n++) { 22 var c = str.charCodeAt(n); 23 if (c < 128) { 24 encoded_str += String.fromCharCode(c); 25 } 26 else if((c > 127) && (c < 2048)) { 27 encoded_str += String.fromCharCode((c >> 6) | 192); 28 encoded_str += String.fromCharCode((c & 63) | 128); 29 } else { 30 encoded_str += String.fromCharCode((c >> 12) | 224); 31 encoded_str += String.fromCharCode(((c >> 6) & 63) | 128); 32 encoded_str += String.fromCharCode((c & 63) | 128); 33 } 34 } 35 return encoded_str; 36 }, 37 38 /** prevent restricted %2F in paths */ 39 ew_encodeURIComponent : function (str) { 40 str = str.replace("/","_SLASH_"); 41 str = encodeURIComponent(str); 42 return str; 43 } 44 45} 46 47var ew_Helper = { /* helper functions which can be used anywhere*/ 48 replaceString: function (_str, _search, _replace) { 49 var re = new RegExp(_search, 'g') 50 return _str.replace(re, _replace); 51 }, 52 53 getQueryVariable: function (variable) { 54 var query = window.location.search.substring(1); 55 var vars = query.split("&"); 56 for (var i = 0; i < vars.length; i++) { 57 var pair = vars[i].split("="); 58 if (pair[0] == variable) { 59 return pair[1]; 60 } 61 } 62 }, 63 endsWith: function (str, suffix) { 64 if (str == null || suffix == null) { 65 return false; 66 } 67 return str.indexOf(suffix, str.length - suffix.length) !== -1; 68 }, 69 startsWith : function(str, prefix) { 70 if (str == null || prefix == null) { 71 return false; 72 } 73 return str.indexOf(prefix) === 0; 74 } 75} 76 77 78function extrawatch_createRequestObject() { 79 var ro; 80 if(window.ActiveXObject){ 81 ro = new ActiveXObject("Microsoft.XMLHTTP"); 82 }else{ 83 ro = new XMLHttpRequest(); 84 } 85 return ro; 86} 87 88 89 90var ew_Heatmap = { 91 92 extraWatch_click : function(evt, frontendTokenToPass, uri2titleId) { 93 94 var positionFromEvent = ew_Heatmap.getPositionFromEvent(evt); 95 var xpath = ew_Heatmap.createXPathFromElement(evt.target); 96 97 var scrollx = window.pageXOffset == undefined ? clickDoc.scrollLeft : window.pageXOffset; 98 var scrolly = window.pageYOffset == undefined ? clickDoc.scrollTop : window.pageYOffset; 99 100 /* Is the click in the viewing area? Not on scrollbars. The problem still exists for FF on the horizontal scrollbar */ 101 var url = urlBase + "¶ms=" + encodeURIComponent("&action=click&uri2titleId=" + uri2titleId + "&x=" + positionFromEvent[0] + "&y=" + positionFromEvent[1] + "&w=" + w + "&h=" + h + "&xpath=" + encodeURIComponent(encodeURIComponent(xpath))); 102 103 104 if(ew_Heatmap.checkIfDoSynchronousClick(evt)) { 105 downloadUrl(url, function (e) {}, true, false); //download it synchronously 106 } else { 107 setTimeout(function() { 108 downloadUrl(url, function (e) {}, true); 109 }, 100); //we had to add some delay so that this call is last one. If it was called first, it was causing some problems with some shopping cart ajax calls 110 } 111 112 113 }, 114 keyListener: function (evt) { 115 var evt = (evt) ? evt : ((event) ? event : null); 116 var key = (evt) ? evt.which : event.keyCode; 117 118 if (String.fromCharCode(key) == "p") { 119 ew_Heatmap.changeDayInUrl(-1); 120 } else if (String.fromCharCode(key) == "n") { 121 ew_Heatmap.changeDayInUrl(1); 122 } else if (String.fromCharCode(key) == "t") { 123 ew_Heatmap.toggleHeatmap(); 124 } 125 }, 126 127 changeDayInUrl: function (_increment) { 128 var dayVariable = "extraWatchDay"; //todo - move to constants 129 var location = document.location.href; 130 var extraWatchDay = ew_Helper.getQueryVariable(dayVariable); 131 var prevDay = parseInt(extraWatchDay) + _increment; 132 var newLocationString = ew_Helper.replaceString(location, extraWatchDay, prevDay); 133 document.location.href = newLocationString; 134 }, 135 136 toggleHeatmap: function () { 137 xx.toggleDisplay(); 138 }, 139 140 141 /** 142 source and thanks to: http://nickthecoder.wordpress.com/2013/02/26/offsetx-and-offsety-in-firefox/ 143 */ 144 ew_getOffset: function (evt) { 145 if (evt.offsetX != undefined) 146 return {x: evt.offsetX, y: evt.offsetY}; 147 148 var el = evt.target; 149 var offset = {x: 0, y: 0}; 150 151 while (el.offsetParent) { 152 offset.x += el.offsetLeft; 153 offset.y += el.offsetTop; 154 el = el.offsetParent; 155 } 156 157 offset.x = evt.pageX - offset.x; 158 offset.y = evt.pageY - offset.y; 159 160 return offset; 161 }, 162 163 /* attach click event listener on onclick event */ 164 attachExtraWatchClickListener: function (frontendTokenToPass, uri2titleId) { 165 166 if(false) { //bugfix: binding via jquery was taking too long, using rather native js addEventListener //registering click listener via jQuery if it's loaded 167 jQuery(document).bind("click", function (event) { 168 ew_Heatmap.extraWatch_click(event, frontendTokenToPass, uri2titleId); 169 }); 170 } else { 171 window.document.onclick = function (evt) { 172 if (window.addEventListener) { 173 window.addEventListener("onclick", ew_Heatmap.extraWatch_click(evt, frontendTokenToPass, uri2titleId), false); 174 } else if (window.attachEvent) { 175 window.attachEvent("onclick", ew_Heatmap.extraWatch_click(evt, frontendTokenToPass, uri2titleId)); 176 } else { 177 window.addEventListener("onclick", ew_Heatmap.extraWatch_click(evt, frontendTokenToPass, uri2titleId), false); 178 } 179 } 180 } 181 }, 182 183 184 extraWatch_decorateLinksWithCustomHandler: function (extraWatchLinkElementsList, frontendTokenToPass, uri2titleId) { 185 for (i = 0; i < extraWatchLinkElementsList.length; i++) { 186 try { 187 if (extraWatchLinkElementsList[i].onclick != null) { /* go through all onclick methods */ 188 var replaceOnClick= ["javascript:",""]; 189 window.ewTemp_frontendTokenToPass = frontendTokenToPass; 190 window.ewTemp_uri2titleId = uri2titleId; 191 replaceOnClick.forEach(function(entry) { /* for each search pattern */ 192 var searchMask = entry + "(.*)"; 193 var regEx = new RegExp(searchMask, "i"); 194 if (extraWatchLinkElementsList[i].outerHTML.match(regEx) != null) { /* if outer HTML matches pattern */ 195 var replaceMask = entry + "ew_Heatmap.extraWatch_click\(event, window.ewTemp_frontendTokenToPass, window.ewTemp_uri2titleId\);$1;"; /* inserting click method before original onclick method content */ 196 var originalOnClick = extraWatchLinkElementsList[i].getAttribute('onclick'); 197 var decoratedOnClick = originalOnClick.replace(regEx, replaceMask); 198 extraWatchLinkElementsList[i].setAttribute('onclick', decoratedOnClick); 199 return true; 200 } 201 }); 202 } 203 } catch (e) { 204 } 205 } 206 }, 207 208 findPos: function (obj) { 209 var curtop = 0; 210 if (obj.offsetParent) { 211 do { 212 curtop += obj.offsetTop; 213 } while (obj = obj.offsetParent); 214 return [curtop]; 215 } 216 }, 217 218 createXPathFromElement: function (elm) { 219 var allNodes = document.getElementsByTagName('*'); 220 for (segs = []; elm && elm.nodeType == 1; elm = elm.parentNode) { 221 if (elm.hasAttribute('id')) { 222 var uniqueIdCount = 0; 223 for (var n = 0; n < allNodes.length; n++) { 224 if (allNodes[n].hasAttribute('id') && allNodes[n].id == elm.id) uniqueIdCount++; 225 if (uniqueIdCount > 1) break; 226 } 227 ; 228 if (uniqueIdCount == 1) { 229 //segs.unshift('id("' + elm.getAttribute('id') + '")'); 230 segs.unshift('//*[@id="' + elm.getAttribute('id') + '"]'); 231 return segs.join('/'); 232 } else { 233 segs.unshift(elm.localName.toLowerCase() + '[@id="' + elm.getAttribute('id') + '"]'); 234 } 235 } else if (elm.hasAttribute('class')) { 236 segs.unshift(elm.localName.toLowerCase() + '[@class="' + elm.getAttribute('class') + '"]'); 237 } else { 238 for (i = 1, sib = elm.previousSibling; sib; sib = sib.previousSibling) { 239 if (sib.localName == elm.localName) i++; 240 } 241 ; 242 segs.unshift(elm.localName.toLowerCase() + '[' + i + ']'); 243 } 244 ; 245 } 246 ; 247 return segs.length ? '/' + segs.join('/') : null; 248 }, 249 250 isTargetElementNavigatingAway: function (target) { 251 252 switch (target.localName) { 253 case "a": { 254 /* if there's A element and contains # or javascript: in href="..." we are assuming that we are not navigating away */ 255 if (target.href == "" || ew_Helper.endsWith(target.href,"#") || ew_Helper.startsWith(target.href, 'javascript:')) { 256 return false;
257 } 258 return true; 259 break; 260 } 261 case "input": { 262 switch (target.type) { 263 264 case "button": { 265 return false; //we assume that all buttons are not navigating away, most of them are on site 266 } 267 268 default : { 269 if (target.type == "submit") { 270 return true; 271 } else { 272 return false; 273 } 274 break; 275 } 276 } 277 278 } 279 case "submit": { 280 /* in case of submit and form buttons we'll assume this is navigating away */ 281 return true; 282 } 283 default: { 284 return false; 285 } 286 } 287 288 289 }, 290 291 checkIfElementContainsHrefWithHttp: function (targetElement, domain) { 292 while(targetElement != null) { /* go through all parent elements */ 293 if (targetElement.href != null && ew_Helper.startsWith(targetElement.href,"http") || ew_Helper.startsWith(targetElement.href,"https") /* && !(targetElement.href.indexOf(domain) > 0) */) { 294 return true; 295 } 296 targetElement = targetElement.parentElement; 297 }; 298 return false; 299 }, 300 301 checkIfElementContainsHash: function (targetElement, domain) { 302 while(targetElement != null) { /* go through all parent elements */ 303 if (targetElement.href != null && targetElement.href.indexOf("#") != -1) { 304 return true; 305 } 306 targetElement = targetElement.parentElement; 307 }; 308 return false; 309 }, 310 311 312 checkIfDoSynchronousClick: function (evt) { 313 var currentDomain = null; 314 if (window.location && window.location.href && window.location.href.split('/') && (window.location.href.split('/').length > 0)) { 315 currentDomain = window.location.href.split('/')[2]; 316 } 317 if (evt.target != null && evt.target.type != null && evt.target.type == "submit") { /* shopping cart submit buttons etc. */ 318 return true; 319 } 320 if (evt.target != null && ew_Heatmap.checkIfElementContainsHash(evt.target, currentDomain)) { //only for links which have http:// 321 return false; 322 } 323 324 if (evt.target != null && ew_Heatmap.checkIfElementContainsHrefWithHttp(evt.target, currentDomain)) { //only for links which have http:// 325 return true; 326 } 327 328 return false; /* do synchronous click if navigating away */ 329 }, 330 331 332 getPositionFromEvent : function (evt) { 333 var pos = window.h337.util.mousePosition(evt); //relative position to element 334 if (evt.offsetX == null || evt.offsetY == null) { 335 var calculatedOffset = ew_Heatmap.ew_getOffset(evt); 336 var x = calculatedOffset.x; 337 var y = calculatedOffset.y; 338 } else { 339 var x = evt.offsetX; // offset relative within the element 340 var y = evt.offsetY; 341 } 342 return [x,y]; 343 }, 344 345 highlightElementsByXPath: function(xpathElements, document){ 346 var xpath = null; 347 var length = xpathElements.length; 348 349 for (var i = 0; i < length; i++) { 350 xpath = xpathElements[i]; 351 try { 352 var elementFound = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); 353 var element = elementFound.singleNodeValue; 354 if (element != null) { 355 element.style.border="2px solid " + xpathElementColors[i]; 356 element.style.backgroundColor=xpathElementColors[i]; 357 } 358 } catch (e) { 359 //suppress if no element was found 360 } 361 } 362 }, 363 364 365 renderHeatmap : function (randHash, data) { 366 try { 367 var ip = ew_Helper.getQueryVariable('ip'); 368 var obj = eval( data ); 369 xx.displayLoading 370 xx.store.setDataSet(obj); 371 } catch (e) { 372 alert("There was problem loading ExtraWatch Heatmap. This is not fault of ExtraWatch but fact that you might have some other javascript errors on your website.\n\nError:\n" + e.message + "\nStack:\n" + e.stack); 373 } 374 } 375 376 377 378} 379
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.