--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length--;\r
+ return firstItem;\r
+ }\r
+ };\r
+}\r
+\r
+var log4javascript;\r
+\r
+(function() {\r
+ var newLine = "\r\n";\r
+ function Log4JavaScript() {}\r
+ log4javascript = new Log4JavaScript();\r
+ log4javascript.version = "1.4.6";\r
+ log4javascript.edition = "log4javascript_lite";\r
+\r
+ function getExceptionMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ } else {\r
+ return String(ex);\r
+ }\r
+ }\r
+\r
+ // Gets the portion of the URL after the last slash\r
+ function getUrlFileName(url) {\r
+ var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));\r
+ return url.substr(lastSlashIndex + 1);\r
+ }\r
+\r
+ // Returns a nicely formatted representation of an error\r
+ function getExceptionStringRep(ex) {\r
+ if (ex) {\r
+ var exStr = "Exception: " + getExceptionMessage(ex);\r
+ try {\r
+ if (ex.lineNumber) {\r
+ exStr += " on line number " + ex.lineNumber;\r
+ }\r
+ if (ex.fileName) {\r
+ exStr += " in file " + getUrlFileName(ex.fileName);\r
+ }\r
+ } catch (localEx) {\r
+ }\r
+ if (showStackTraces && ex.stack) {\r
+ exStr += newLine + "Stack trace:" + newLine + ex.stack;\r
+ }\r
+ return exStr;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function isError(err) {\r
+ return (err instanceof Error);\r
+ }\r
+\r
+ function bool(obj) {\r
+ return Boolean(obj);\r
+ }\r
+\r
+ var enabled = (typeof log4javascript_disabled != "undefined") &&\r
+ log4javascript_disabled ? false : true;\r
+\r
+ log4javascript.setEnabled = function(enable) {\r
+ enabled = bool(enable);\r
+ };\r
+\r
+ log4javascript.isEnabled = function() {\r
+ return enabled;\r
+ };\r
+\r
+ var showStackTraces = false;\r
+\r
+ log4javascript.setShowStackTraces = function(show) {\r
+ showStackTraces = bool(show);\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Levels\r
+\r
+ var Level = function(level, name) {\r
+ this.level = level;\r
+ this.name = name;\r
+ };\r
+\r
+ Level.prototype = {\r
+ toString: function() {\r
+ return this.name;\r
+ },\r
+ equals: function(level) {\r
+ return this.level == level.level;\r
+ },\r
+ isGreaterOrEqual: function(level) {\r
+ return this.level >= level.level;\r
+ }\r
+ };\r
+\r
+ Level.ALL = new Level(Number.MIN_VALUE, "ALL");\r
+ Level.TRACE = new Level(10000, "TRACE");\r
+ Level.DEBUG = new Level(20000, "DEBUG");\r
+ Level.INFO = new Level(30000, "INFO");\r
+ Level.WARN = new Level(40000, "WARN");\r
+ Level.ERROR = new Level(50000, "ERROR");\r
+ Level.FATAL = new Level(60000, "FATAL");\r
+ Level.OFF = new Level(Number.MAX_VALUE, "OFF");\r
+\r
+ log4javascript.Level = Level;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Appenders\r
+\r
+ function Appender() {\r
+ var getConsoleHtmlLines = function() {\r
+ return [\r
+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',\r
+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',\r
+' <head>',\r
+' <title>log4javascript</title>',\r
+' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',\r
+' <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',\r
+' <meta http-equiv="X-UA-Compatible" content="IE=7" />',\r
+' <script type="text/javascript">',\r
+' //<![CDATA[',\r
+' var loggingEnabled = true;',\r
+' var messagesBeforeDocLoaded = [];',\r
+'',\r
+' function toggleLoggingEnabled() {',\r
+' setLoggingEnabled($("enableLogging").checked);',\r
+' }',\r
+'',\r
+' function setLoggingEnabled(enable) {',\r
+' loggingEnabled = enable;',\r
+' }',\r
+'',\r
+' function scrollToLatestEntry() {',\r
+' var l = getLogContainer();',\r
+' if (typeof l.scrollTop != "undefined") {',\r
+' var latestLogEntry = l.lastChild;',\r
+' if (latestLogEntry) {',\r
+' l.scrollTop = l.scrollHeight;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function log(logLevel, formattedMessage) {',\r
+' if (loggingEnabled) {',\r
+' if (loaded) {',\r
+' doLog(logLevel, formattedMessage);',\r
+' } else {',\r
+' messagesBeforeDocLoaded.push([logLevel, formattedMessage]);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function doLog(logLevel, formattedMessage) {',\r
+' var logEntry = document.createElement("div");',\r
+' logEntry.appendChild(document.createTextNode(formattedMessage));',\r
+' logEntry.className = "logentry " + logLevel.name;',\r
+' getLogContainer().appendChild(logEntry);',\r
+' scrollToLatestEntry();',\r
+' }',\r
+'',\r
+' function mainPageReloaded() {',\r
+' var separator = document.createElement("div");',\r
+' separator.className = "separator";',\r
+' separator.innerHTML = " ";',\r
+' getLogContainer().appendChild(separator);',\r
+' }',\r
+'',\r
+' var loaded = false;',\r
+' var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',\r
+'',\r
+' window.onload = function() {',\r
+' setLogContainerHeight();',\r
+' toggleLoggingEnabled();',\r
+' for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {',\r
+' doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);',\r
+' }',\r
+' messagesBeforeDocLoaded = [];',\r
+' loaded = true;',\r
+'',\r
+' // Workaround to make sure log div starts at the correct size',\r
+' setTimeout(setLogContainerHeight, 20);',\r
+' };',\r
+'',\r
+' function getLogContainer() {',\r
+' return $("log");',\r
+' }',\r
+'',\r
+' function clearLog() {',\r
+' getLogContainer().innerHTML = "";',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // Other utility functions',\r
+'',\r
+' // Syntax borrowed from Prototype library',\r
+' function $(id) {',\r
+' return document.getElementById(id);',\r
+' }',\r
+'',\r
+' function getWindowHeight() {',\r
+' if (window.innerHeight) {',\r
+' return window.innerHeight;',\r
+' } else if (document.documentElement && document.documentElement.clientHeight) {',\r
+' return document.documentElement.clientHeight;',\r
+' } else if (document.body) {',\r
+' return document.body.clientHeight;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getChromeHeight() {',\r
+' return $("toolbar").offsetHeight;',\r
+' }',\r
+'',\r
+' function setLogContainerHeight() {',\r
+' var windowHeight = getWindowHeight();',\r
+' $("body").style.height = getWindowHeight() + "px";',\r
+' getLogContainer().style.height = "" +',\r
+' Math.max(0, windowHeight - getChromeHeight()) + "px";',\r
+' }',\r
+'',\r
+' window.onresize = function() {',\r
+' setLogContainerHeight();',\r
+' };',\r
+'',\r
+' //]]>',\r
+' </script>',\r
+' <style type="text/css">',\r
+' body {',\r
+' background-color: white;',\r
+' color: black;',\r
+' padding: 0;',\r
+' margin: 0;',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' overflow: hidden;',\r
+' }',\r
+' ',\r
+' div#toolbar {',\r
+' border-top: solid #ffffff 1px;',\r
+' border-bottom: solid #aca899 1px;',\r
+' background-color: #f1efe7;',\r
+' padding: 3px 5px;',\r
+' font-size: 68.75%;',\r
+' }',\r
+'',\r
+' div#toolbar input.button {',\r
+' padding: 0 5px;',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div#log {',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 75%;',\r
+' width: 100%;',\r
+' overflow: auto;',\r
+' clear: both;',\r
+' }',\r
+'',\r
+' *.logentry {',\r
+' overflow: visible;',\r
+' white-space: pre;',\r
+' }',\r
+'',\r
+' *.TRACE {',\r
+' color: #666666;',\r
+' }',\r
+'',\r
+' *.DEBUG {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' *.INFO {',\r
+' color: #000099;',\r
+' }',\r
+'',\r
+' *.WARN {',\r
+' color: #999900;',\r
+' }',\r
+'',\r
+' *.ERROR {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' *.FATAL {',\r
+' color: #660066;',\r
+' }',\r
+'',\r
+' div#log div.separator {',\r
+' background-color: #cccccc;',\r
+' margin: 5px 0;',\r
+' line-height: 1px;',\r
+' }',\r
+' </style>',\r
+' </head>',\r
+'',\r
+' <body id="body">',\r
+' <div id="toolbar">',\r
+' Options:',\r
+' <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>',\r
+' <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages" />',\r
+' <input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />',\r
+' </div>',\r
+' <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',\r
+' </body>',\r
+'</html>'\r
+];\r
+ };\r
+\r
+ var popUp = null;\r
+ var popUpsBlocked = false;\r
+ var popUpClosed = false;\r
+ var popUpLoaded = false;\r
+ var complainAboutPopUpBlocking = true;\r
+ var initialized = false;\r
+ var isSupported = true;\r
+ var width = 600;\r
+ var height = 400;\r
+ var focusPopUp = false;\r
+ var queuedLoggingEvents = new Array();\r
+\r
+ function isLoaded(win) {\r
+ try {\r
+ return bool(win.loaded);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function finalInit() {\r
+ popUpLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ }\r
+\r
+ function writeHtml(doc) {\r
+ var lines = getConsoleHtmlLines();\r
+ doc.open();\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ doc.writeln(lines[i]);\r
+ }\r
+ doc.close();\r
+ }\r
+\r
+ function pollConsoleWindow() {\r
+ function pollConsoleWindowLoaded() {\r
+ if (popUpLoaded) {\r
+ clearInterval(poll);\r
+ } else if (bool(popUp) && isLoaded(popUp)) {\r
+ clearInterval(poll);\r
+ finalInit();\r
+ }\r
+ }\r
+\r
+ // Poll the pop-up since the onload event is not reliable\r
+ var poll = setInterval(pollConsoleWindowLoaded, 100);\r
+ }\r
+\r
+ function init() {\r
+ var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";\r
+ var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_");\r
+\r
+ popUp = window.open("", windowName, windowProperties);\r
+ popUpClosed = false;\r
+ if (popUp) {\r
+ if (isLoaded(popUp)) {\r
+ popUp.mainPageReloaded();\r
+ finalInit();\r
+ } else {\r
+ writeHtml(popUp.document);\r
+\r
+ // Check if the pop-up window object is available\r
+ if (isLoaded(popUp)) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow();\r
+ }\r
+ }\r
+ } else {\r
+ isSupported = false;\r
+ if (complainAboutPopUpBlocking) {\r
+ alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");\r
+ }\r
+ }\r
+ initialized = true;\r
+ }\r
+\r
+ function safeToAppend() {\r
+ if (!popUpsBlocked && !popUpClosed) {\r
+ if (popUp.closed) {\r
+ popUpClosed = true;\r
+ return false;\r
+ }\r
+ if (!popUpLoaded && popUp.loaded) {\r
+ popUpLoaded = true;\r
+ }\r
+ }\r
+ return !popUpsBlocked && popUpLoaded && !popUpClosed;\r
+ }\r
+\r
+ function padWithZeroes(num, len) {\r
+ var str = "" + num;\r
+ while (str.length < len) {\r
+ str = "0" + str;\r
+ }\r
+ return str;\r
+ }\r
+\r
+ function padWithSpaces(str, len) {\r
+ while (str.length < len) {\r
+ str += " ";\r
+ }\r
+ return str;\r
+ }\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (!initialized) {\r
+ init();\r
+ }\r
+ queuedLoggingEvents.push(loggingEvent);\r
+ if (safeToAppend()) {\r
+ appendQueuedLoggingEvents();\r
+ }\r
+ };\r
+\r
+ function appendQueuedLoggingEvents() {\r
+ if (safeToAppend()) {\r
+ while (queuedLoggingEvents.length > 0) {\r
+ var currentLoggingEvent = queuedLoggingEvents.shift();\r
+ var date = currentLoggingEvent.timeStamp;\r
+ var formattedDate = padWithZeroes(date.getHours(), 2) + ":" +\r
+ padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2);\r
+ var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) +\r
+ " - " + currentLoggingEvent.getCombinedMessages();\r
+ var throwableStringRep = currentLoggingEvent.getThrowableStrRep();\r
+ if (throwableStringRep) {\r
+ formattedMessage += newLine + throwableStringRep;\r
+ }\r
+ popUp.log(currentLoggingEvent.level, formattedMessage);\r
+ }\r
+ if (focusPopUp) {\r
+ popUp.focus();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ log4javascript.Appender = Appender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Loggers\r
+\r
+ function Logger() {\r
+ var appender = new Appender();\r
+ var loggerLevel = Level.ALL;\r
+\r
+ this.log = function(level, params) {\r
+ if (enabled && level.isGreaterOrEqual(this.getLevel())) {\r
+ // Check whether last param is an exception\r
+ var exception;\r
+ var finalParamIndex = params.length - 1;\r
+ var lastParam = params[params.length - 1];\r
+ if (params.length > 1 && isError(lastParam)) {\r
+ exception = lastParam;\r
+ finalParamIndex--;\r
+ }\r
+\r
+ // Construct genuine array for the params\r
+ var messages = [];\r
+ for (var i = 0; i <= finalParamIndex; i++) {\r
+ messages[i] = params[i];\r
+ }\r
+\r
+ var loggingEvent = new LoggingEvent(\r
+ this, new Date(), level, messages, exception);\r
+\r
+ appender.append(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.setLevel = function(level) {\r
+ loggerLevel = level;\r
+ };\r
+\r
+ this.getLevel = function() {\r
+ return loggerLevel;\r
+ };\r
+ }\r
+\r
+ Logger.prototype = {\r
+ trace: function() {\r
+ this.log(Level.TRACE, arguments);\r
+ },\r
+\r
+ debug: function() {\r
+ this.log(Level.DEBUG, arguments);\r
+ },\r
+\r
+ info: function() {\r
+ this.log(Level.INFO, arguments);\r
+ },\r
+\r
+ warn: function() {\r
+ this.log(Level.WARN, arguments);\r
+ },\r
+\r
+ error: function() {\r
+ this.log(Level.ERROR, arguments);\r
+ },\r
+\r
+ fatal: function() {\r
+ this.log(Level.FATAL, arguments);\r
+ },\r
+\r
+ isEnabledFor: function(level) {\r
+ return level.isGreaterOrEqual(this.getLevel());\r
+ },\r
+\r
+ isTraceEnabled: function() {\r
+ return this.isEnabledFor(Level.TRACE);\r
+ },\r
+\r
+ isDebugEnabled: function() {\r
+ return this.isEnabledFor(Level.DEBUG);\r
+ },\r
+\r
+ isInfoEnabled: function() {\r
+ return this.isEnabledFor(Level.INFO);\r
+ },\r
+\r
+ isWarnEnabled: function() {\r
+ return this.isEnabledFor(Level.WARN);\r
+ },\r
+\r
+ isErrorEnabled: function() {\r
+ return this.isEnabledFor(Level.ERROR);\r
+ },\r
+\r
+ isFatalEnabled: function() {\r
+ return this.isEnabledFor(Level.FATAL);\r
+ }\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logger access methods\r
+\r
+ var defaultLogger = null;\r
+ log4javascript.getDefaultLogger = function() {\r
+ if (!defaultLogger) {\r
+ defaultLogger = new Logger();\r
+ }\r
+ return defaultLogger;\r
+ };\r
+\r
+ log4javascript.getLogger = log4javascript.getDefaultLogger;\r
+\r
+ var nullLogger = null;\r
+ log4javascript.getNullLogger = function() {\r
+ if (!nullLogger) {\r
+ nullLogger = new Logger();\r
+ nullLogger.setLevel(Level.OFF);\r
+ }\r
+ return nullLogger;\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logging events\r
+\r
+ var LoggingEvent = function(logger, timeStamp, level, messages,\r
+ exception) {\r
+ this.logger = logger;\r
+ this.timeStamp = timeStamp;\r
+ this.level = level;\r
+ this.messages = messages;\r
+ this.exception = exception;\r
+ };\r
+\r
+ LoggingEvent.prototype = {\r
+ getThrowableStrRep: function() {\r
+ return this.exception ?\r
+ getExceptionStringRep(this.exception) : "";\r
+ },\r
+\r
+ getCombinedMessages: function() {\r
+ return (this.messages.length === 1) ? this.messages[0] :\r
+ this.messages.join(newLine);\r
+ }\r
+ };\r
+\r
+ log4javascript.LoggingEvent = LoggingEvent;\r
+\r
+ // Ensure that the log4javascript object is available in the window. This\r
+ // is necessary for log4javascript to be available in IE if loaded using\r
+ // Dojo's module system\r
+ window.log4javascript = log4javascript;\r
+})();
\ No newline at end of file