1 (function($, rf) { 2 var logLevels = ['debug', 'info', 'warn', 'error']; 3 var logLevelsPadded = {'debug': 'debug', 'info': 'info ', 'warn': 'warn ', 'error': 'error'}; 4 var logLevelValues = {'debug': 1, 'info': 2, 'warn': 3, 'error': 4}; 5 6 var logClassMethods = { 7 8 __import: function(doc, node) { 9 if (doc === document) { 10 return node; 11 } 12 13 var result = $(); 14 for (var i = 0; i < node.length; i++) { 15 if (doc.importNode) { 16 result = result.add(doc.importNode(node[i], true)); 17 } else { 18 var container = doc.createElement("div"); 19 container.innerHTML = node[i].outerHTML; 20 for (var child = container.firstChild; child; child = child.nextSibling) { 21 result = result.add(child); 22 } 23 } 24 } 25 26 return result; 27 }, 28 29 __getStyles: function() { 30 var head = $("head"); 31 32 if (head.length == 0) { 33 return ""; 34 } 35 36 try { 37 //TODO - BASE element support? 38 var clonedHead = head.clone(); 39 if (clonedHead.children().length == head.children().length) { 40 return clonedHead.children(":not(style):not(link[rel='stylesheet'])").remove().end().html(); 41 } else { 42 var result = new Array(); 43 head.children("style, link[rel='stylesheet']").each(function() { 44 result.push(this.outerHTML); 45 }); 46 47 return result.join(''); 48 } 49 } catch (e) { 50 return ""; 51 } 52 }, 53 54 __openPopup: function() { 55 if (!this.__popupWindow || this.__popupWindow.closed) { 56 this.__popupWindow = open("", "_richfaces_logWindow", "height=400, width=600, resizable = yes, status=no, " + 57 "scrollbars = yes, statusbar=no, toolbar=no, menubar=no, location=no"); 58 59 var doc = this.__popupWindow.document; 60 61 doc.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" + 62 "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>" + this.__getStyles() + "</head>" + 63 "<body onunload='window.close()'><div id='richfaces.log' clas='rf-log rf-log-popup'></div></body></html>"); 64 doc.close(); 65 this.__initializeControls(doc); 66 } else { 67 this.__popupWindow.focus(); 68 } 69 }, 70 71 __hotkeyHandler: function(event) { 72 if (event.ctrlKey && event.shiftKey) { 73 if ((this.hotkey || 'l').toLowerCase() == String.fromCharCode(event.keyCode).toLowerCase()) { 74 this.__openPopup(); 75 } 76 } 77 }, 78 79 __getTimeAsString: function() { 80 var date = new Date(); 81 82 var timeString = this.__lzpad(date.getHours(), 2) + ':' + this.__lzpad(date.getMinutes(), 2) + ':' + 83 this.__lzpad(date.getSeconds(), 2) + '.' + this.__lzpad(date.getMilliseconds(), 3); 84 85 return timeString; 86 }, 87 88 __lzpad: function(s, length) { 89 s = s.toString(); 90 var a = new Array(); 91 for (var i = 0; i < length - s.length; i++) { 92 a.push('0'); 93 } 94 a.push(s); 95 return a.join(''); 96 }, 97 98 __getMessagePrefix: function(level) { 99 return logLevelsPadded[level] + '[' + this.__getTimeAsString() + ']: '; 100 }, 101 102 __setLevelFromSelect: function(event) { 103 this.setLevel(event.target.value); 104 }, 105 106 __initializeControls : function(doc) { 107 var console = $("#richfaces\\.log", doc); 108 109 var clearBtn = console.children("button.rf-log-element"); 110 if (clearBtn.length == 0) { 111 clearBtn = $("<button type='button' name='clear' class='rf-log-element'>Clear</button>", doc).appendTo(console); 112 } 113 114 clearBtn.click($.proxy(this.clear, this)); 115 116 var levelSelect = console.children("select.rf-log-element"); 117 if (levelSelect.length == 0) { 118 levelSelect = $("<select class='rf-log-element' name='richfaces.log' />", doc).appendTo(console); 119 } 120 121 if (levelSelect.children().length == 0) { 122 for (var l = 0; l < logLevels.length; l++) { 123 $("<option value='" + logLevels[l] + "'>" + logLevels[l] + "</option>", doc).appendTo(levelSelect); 124 } 125 } 126 127 levelSelect.val(this.getLevel()); 128 levelSelect.change($.proxy(this.__setLevelFromSelect, this)); 129 130 var consoleEntries = console.children(".rf-log-contents"); 131 if (consoleEntries.length == 0) { 132 consoleEntries = $("<div class='rf-log-contents'></div>", doc).appendTo(console); 133 } 134 this.__contentsElement = consoleEntries; 135 }, 136 137 __append: function(element) { 138 var target = this.__contentsElement; 139 if (this.mode == "popup") { 140 var doc = this.__popupWindow.document; 141 $(doc.createElement("div")).appendTo(target).append(this.__import(doc, element)); 142 } else { 143 $(document.createElement("div")).appendTo(target).append(element); 144 } 145 }, 146 147 __log: function(level, message) { 148 var configuredLevel = this.getLevel(); 149 150 if (!logLevelValues[configuredLevel]) { 151 // unknown log level 152 if (console.log) { 153 console.log('Warning: unknown log level "' + this.getLevel() + '" - using log level "debug"'); 154 } 155 configuredLevel = 'debug'; 156 } 157 if (logLevelValues[level] < logLevelValues[configuredLevel]) { 158 // message is not loggable due to its level 159 return; 160 } 161 162 if (this.mode == 'console') { 163 var logMsg = 'RichFaces: ' + message; 164 if (console[level]) { 165 console[level](logMsg); 166 } else if (console.log) { 167 console.log(logMsg); 168 } 169 return; 170 } 171 172 if (!this.__contentsElement) { 173 return; 174 } 175 176 var newEntry = $(); 177 newEntry = newEntry.add($("<span class='rf-log-entry-lbl rf-log-entry-lbl-" + level + "'></span>").text(this.__getMessagePrefix(level))); 178 179 var entrySpan = $("<span class='rf-log-entry-msg rf-log-entry-msg-" + level + "'></span>"); 180 if (typeof message != 'object' || !message.appendTo) { 181 entrySpan.text(message); 182 } else { 183 message.appendTo(entrySpan); 184 } 185 186 newEntry = newEntry.add(entrySpan); 187 188 this.__append(newEntry); 189 }, 190 191 init: function(options) { 192 $super.constructor.call(this, 'richfaces.log'); 193 this.attachToDom(); 194 rf.setLog(this); 195 196 options = options || {}; 197 198 this.level = (options.level || 'info').toLowerCase(); 199 this.hotkey = options.hotkey; 200 this.mode = (options.mode || 'inline'); 201 202 if (this.mode == 'console') { 203 // do nothing 204 } else if (this.mode == 'popup') { 205 this.__boundHotkeyHandler = $.proxy(this.__hotkeyHandler, this); 206 $(document).bind('keydown', this.__boundHotkeyHandler); 207 } else { 208 this.__initializeControls(document); 209 } 210 }, 211 212 destroy: function() { 213 rf.setLog(null); 214 215 //TODO test this method 216 if (this.__popupWindow) { 217 this.__popupWindow.close(); 218 } 219 this.__popupWindow = null; 220 221 if (this.__boundHotkeyHandler) { 222 $(document).unbind('keydown', this.__boundHotkeyHandler); 223 this.__boundHotkeyHandler = null; 224 } 225 226 this.__contentsElement = null; 227 $super.destroy.call(this); 228 }, 229 230 setLevel: function(level) { 231 this.level = level; 232 this.clear(); 233 }, 234 235 getLevel: function() { 236 return this.level || 'info'; 237 }, 238 239 clear: function() { 240 if (this.__contentsElement) { 241 this.__contentsElement.children().remove(); 242 } 243 } 244 }; 245 246 for (var i = 0; i < logLevels.length; i++) { 247 logClassMethods[logLevels[i]] = (function() { 248 var level = logLevels[i]; 249 return function(message) { 250 this.__log(level, message); 251 } 252 }()); 253 } 254 255 rf.HtmlLog = rf.BaseComponent.extendClass(logClassMethods); 256 // define super class link 257 var $super = rf.HtmlLog.$super; 258 259 $(document).ready(function() { 260 if (typeof jsf != 'undefined') { 261 (function($, rf, jsf) { 262 263 //JSF log adapter 264 var identifyElement = function(elt) { 265 var identifier = '<' + elt.tagName.toLowerCase(); 266 var e = $(elt); 267 if (e.attr('id')) { 268 identifier += (' id=' + e.attr('id')); 269 } 270 if (e.attr('class')) { 271 identifier += (' class=' + e.attr('class')); 272 } 273 274 identifier += ' ...>'; 275 276 return identifier; 277 } 278 279 var formatPartialResponseElement = function(logElement, responseElement) { 280 var change = $(responseElement); 281 282 logElement.append("Element <b>" + responseElement.nodeName + "</b>"); 283 if (change.attr("id")) { 284 logElement.append(document.createTextNode(" for id=" + change.attr("id"))); 285 } 286 287 $(document.createElement("br")).appendTo(logElement); 288 $("<span class='rf-log-entry-msg-xml'></span>").appendTo(logElement).text(change.toXML()); 289 $(document.createElement("br")).appendTo(logElement); 290 } 291 292 var formatPartialResponse = function(partialResponse) { 293 var logElement = $(document.createElement("span")); 294 295 partialResponse.children().each(function() { 296 var responseElement = $(this); 297 if (responseElement.is('changes')) { 298 logElement.append("Listing content of response <b>changes</b> element:<br />"); 299 responseElement.children().each(function() { 300 formatPartialResponseElement(logElement, this); 301 }); 302 } else { 303 formatPartialResponseElement(logElement, this); 304 } 305 }); 306 307 return logElement; 308 } 309 310 var jsfAjaxLogAdapter = function(data) { 311 try { 312 var log = rf.log; 313 314 var source = data.source; 315 var type = data.type; 316 317 var responseCode = data.responseCode; 318 var responseXML = data.responseXML; 319 var responseText = data.responseText; 320 321 if (type != 'error') { 322 log.info("Received '" + type + "' event from " + identifyElement(source)); 323 324 if (type == 'beforedomupdate') { 325 var partialResponse; 326 327 if (responseXML) { 328 partialResponse = $(responseXML).children("partial-response"); 329 } 330 331 var responseTextEntry = $("<span>Server returned responseText: </span><span class='rf-log-entry-msg-xml'></span>").eq(1).text(responseText).end(); 332 333 if (partialResponse && partialResponse.length) { 334 log.debug(responseTextEntry); 335 log.info(formatPartialResponse(partialResponse)); 336 } else { 337 log.info(responseTextEntry); 338 } 339 } 340 } else { 341 var status = data.status; 342 log.error("Received '" + type + '@' + status + "' event from " + identifyElement(source)); 343 344 var message = "[status=" + data.responseCode + "] "; 345 if (data.errorName && data.errorMessage) { 346 message += " " + data.errorName + ": " + data.errorMessage; 347 } else if (data.description) { 348 message += " " + data.description; 349 } else { 350 message += " no error details"; 351 } 352 log.error(message); 353 } 354 } catch (e) { 355 //ignore logging errors 356 } 357 }; 358 359 var eventsListener = rf.createJSFEventsAdapter({ 360 begin: jsfAjaxLogAdapter, 361 beforedomupdate: jsfAjaxLogAdapter, 362 success: jsfAjaxLogAdapter, 363 complete: jsfAjaxLogAdapter, 364 error: jsfAjaxLogAdapter 365 }); 366 367 jsf.ajax.addOnEvent(eventsListener); 368 jsf.ajax.addOnError(eventsListener); 369 // 370 }($, rf, jsf)); 371 } 372 }); 373 374 }(RichFaces.jQuery, RichFaces));