diff --git a/.project b/.project
new file mode 100644
index 0000000..8f0a85e
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+
+
+ log4js
+
+
+
+
+
+
+
+
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644
index 0000000..b5772bd
--- /dev/null
+++ b/CHANGELOG.txt
@@ -0,0 +1,26 @@
+VERSION 0.1.5
+-Changed the way log levels are modeled to mirror Log4j conventions.
+-Change Log4js.LogLevel to Log4js.Level (Log4j has a LogLevel class and a Level class, LogLevel is actually part of the LogFactor5 3rd party package) to match Log4j naming conventions
+-Created static objects representing each log level.
+-Added OFF and ALL levels to mirror Log4j levels.
+-Renamed Log4js.LogEntry to Log4js.LoggingEvent to mirror Log4j naming conventions.
+
+VERSION 0.1.4
+-Combined HtmlConsoleAppender and WindowAppender into a single appender since they are really the same thing (a console) just in different locations
+-New appender is called ConsoleAppender, you indicate whether the console should run inline during construction (default is to launch in new window)
+
+VERSION 0.1.3
+-created an Log4js.LogEntry object to model a log entry, has category, level, and message properties, it has a method to return a formatted string representing the message (need to replace this with actual Layouts)
+-logs entries stored in central log entry array
+-appenders are notified of new log entries through event notificiation and use of Log4js.Event objects
+-when a new log entry appears all appenders automatically notified.
+-when log entries are cleared all appenders are notified and cleared.
+-added HtmlConsoleAppender that writes log messages to a hidden "console" that can be toggled with "Alt-d" - thanks to Corey Johnson whose Lumberjack (http://gleepglop.com/javascripts/logger/) code was adapted for this appender
+
+VERSION 0.1.2
+-pulled LogLevel and Logger under a main "class" called Log4js, updated all documentation an test functions to reflect changes.
+-changed version to 0.1.2 (not sure how version number should change?)
+-fixed "clear" and "close" buttons on WindowAppender
+-fixed scrolling issues in WindowAppender
+-fixed IE javascript bug if user chooses "no" on ActiveX dialouge
+-updated all tests and comments to reflect above changes
\ No newline at end of file
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 0000000..0c43c1c
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,54 @@
+
+============
+Using log4js
+============
+
+1) First untar or unzip the distribution file.
+
+2) Assuming you chose to extract the distribution in to the
+ PATH_OF_YOUR_CHOICE, untarring the distribution file should create
+ a logging-log4js-VERSION directory, where VERSION is the log4js
+ version number, under PATH_OF_YOUR_CHOICE. We will refer to the
+ directory PATH_OF_YOUR_CHOICE/logging-log4j-VERSION/ as $LOG4JS_HOME/.
+
+@TODO
+
+==================
+log4js dependencies
+==================
+
+Log4js is based on EMCA Script (JavaScript) with the following additional
+requirements:
+
+ ----------------------------
+ JSDoc
+ ----------------------------
+
+ JSDoc is a Perl implementation to generate API documentation for JavaScripts.
+ It is available at http://jsdoc.sf.net
+
+ ----------------------------
+ Package ANT
+ ----------------------------
+
+ ANT is a Java based make tool to generate the releases. It is availabel
+ at http://ant.apache.org
+
+ ----------------------------
+ Package log4j.jar
+ ----------------------------
+
+ log4j.jar is the logging API for Java. It is only required for the
+ AJAXAppender example to log the messages on server side.
+
+
+==============
+Building log4js
+==============
+
+Like most java appilicatios today, log4js relies on ANT as its build
+tool. ANT is availale from "http://ant.apache.org/". ANT
+requires a build file called build.xml which is part of this
+distribution. Required components from other projects are specified in
+the build.properties and example of which is supplied in the
+build.properties.sample file.
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..35fb908
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,4 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes source code based on ...
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..e69de29
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..2997079
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Logging library for JavaScript which is using almost same API than log4j
+
+
+
+
+ generate complete distribution archive: ${dist.dir}/log4js-${version}.zip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generate example web archive: ${dist.dir}/${example.war.name}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generate documentation archive: ${dist.dir}/log4js-doc-${version}.zip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gererate JSDoc to ${apidoc.dir}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To use this Maven-like freedom with respect to dependency setup,
+ do the following:
+
+ - run ant as you normally would, but add the following target to the command
+ line:
+
+ download-dependencies
+
+ For example:
+ C:>myproject\ant download-dependencies dist
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/WEB-INF/classes/log4j.properties b/examples/WEB-INF/classes/log4j.properties
new file mode 100644
index 0000000..8678725
--- /dev/null
+++ b/examples/WEB-INF/classes/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootLogger=DEBUG, ConsoleAppender
+
+log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
+log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c: %m%n
\ No newline at end of file
diff --git a/examples/WEB-INF/web.xml b/examples/WEB-INF/web.xml
new file mode 100644
index 0000000..4dae129
--- /dev/null
+++ b/examples/WEB-INF/web.xml
@@ -0,0 +1,11 @@
+
+
+
+ Log4js
+
+ Log4js Example
+
+
diff --git a/examples/WEB-INF/web.xml.bak b/examples/WEB-INF/web.xml.bak
new file mode 100644
index 0000000..7a26bf6
--- /dev/null
+++ b/examples/WEB-INF/web.xml.bak
@@ -0,0 +1,11 @@
+
+
+
+ Tomcat Documentation
+
+ Tomcat Documentation.
+
+
diff --git a/examples/index.html b/examples/index.html
new file mode 100644
index 0000000..69c5545
--- /dev/null
+++ b/examples/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Log4js tests
+
+
+
+
+
+
Log4js Tests
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/log4j.jsp b/examples/log4j.jsp
new file mode 100644
index 0000000..d443c85
--- /dev/null
+++ b/examples/log4j.jsp
@@ -0,0 +1,20 @@
+<%@ page import="org.apache.log4j.Logger" %>
+<%
+// Log4J
+ String category = request.getParameter("log4js.category");
+ String message = request.getParameter("log4js.msg");
+ String level = request.getParameter("log4js.level");
+ String client = request.getParameter("log4js.client");
+
+ Logger logger = Logger.getLogger( category);
+ String msg = request.getRemoteAddr() + " - " + client + ": " + message;
+ System.out.println(msg);
+ if("debug".equals(level))
+ {
+ logger.debug(msg);
+ } else {
+ logger.error(msg);
+ }
+ //System.out.println(msg);
+%>
+
\ No newline at end of file
diff --git a/src/js/log4js.js b/src/js/log4js.js
new file mode 100644
index 0000000..66cc6a1
--- /dev/null
+++ b/src/js/log4js.js
@@ -0,0 +1,1096 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview log4js is a helper to log in JavaScript in simmilar manner than in log4j
+ * for Java. The API should be nearly the same.
+ *
Example:
+ *
+ * //logging see log4js
+ * var log = new Log4js.Logger("some-category-name");
+ * log.setLevel(Log4js.Level.TRACE); //set the Level
+ * log.addAppender(new ConsoleAppender(log, false)); // console that launches in new window
+
+ * // if multiple appenders are set all will log
+ * log.addAppender(new ConsoleAppender(log, true)); // console that is inline in the page
+ * log.addAppender(new FileAppender("C:\\somefile.log")); // file appender logs to C:\\somefile.log
+ * ...
+ * //call the log
+ * log.trace("trace me" );
+ *
+ *
+ * @author Stephan Strittmatter - http://jroller.com/page/stritti
+ * @author Seth Chisamore - http://www.chisamore.com
+ * @author Corey Johnson - some parts inspired by Lumberjack (http://gleepglop.com/javascripts/logger/)
+ * @author S?bastien LECACHEUR - JSAlertAppender
+ */
+
+var Log4js = {
+ /**
+ * current version of log4js
+ * @static
+ */
+ version: "0.1.5",
+
+ /**
+ * @param element
+ * @param name
+ * @param observer
+ */
+ attachEvent: function (element, name, observer) {
+ if (element.addEventListener) {
+ element.addEventListener(name, observer, false);
+ } else if (element.attachEvent) {
+ element.attachEvent('on' + name, observer);
+ }
+ }
+}
+
+/**
+ * Log4js.Level Enumeration
+ * @constructor
+ * @private
+ * @param {Number} level
+ * @param {String} levelString
+ */
+Log4js.Level = function(level, levelStr) {
+ this.level = level;
+ this.levelStr = levelStr;
+};
+
+Log4js.Level.prototype = {
+ /**
+ * converts given String to Level
+ * @param {String} sArg String value of Level
+ * @param {Log4js.Level} defaultLevel default Level, if no String representation
+ * @return Level object
+ * @type Log4js.Level
+ */
+ toLevel: function(sArg, defaultLevel) {
+
+ if(sArg == null)
+ return defaultLevel;
+
+ if(typeof sArg == "string") {
+ var s = sArg.toUpperCase();
+ if(s == "ALL") return Log4js.Level.ALL;
+ if(s == "DEBUG") return Log4js.Level.DEBUG;
+ if(s == "INFO") return Log4js.Level.INFO;
+ if(s == "WARN") return Log4js.Level.WARN;
+ if(s == "ERROR") return Log4js.Level.ERROR;
+ if(s == "FATAL") return Log4js.Level.FATAL;
+ if(s == "OFF") return Log4js.Level.OFF;
+ if(s == "TRACE") return Log4js.Level.TRACE;
+ return defaultLevel;
+ } else if(typeof sArg == "number") {
+ switch(sArg) {
+ case ALL_INT: return Log4js.Level.ALL;
+ case DEBUG_INT: return Log4js.Level.DEBUG;
+ case INFO_INT: return Log4js.Level.INFO;
+ case WARN_INT: return Log4js.Level.WARN;
+ case ERROR_INT: return Log4js.Level.ERROR;
+ case FATAL_INT: return Log4js.Level.FATAL;
+ case OFF_INT: return Log4js.Level.OFF;
+ case TRACE_INT: return Log4js.Level.TRACE;
+ default: return defaultLevel;
+ }
+ } else {
+ return defaultLevel;
+ }
+ },
+ /**
+ * @return converted Level to String
+ * @type String
+ */
+ toString: function() {
+ return this.levelStr;
+ },
+ /**
+ * @return internal Number value of Level
+ * @type Number
+ */
+ valueOf: function() {
+ return this.level;
+ }
+}
+
+// Static variables
+/**
+ * @private
+ */
+Log4js.Level.OFF_INT = Number.MAX_VALUE;
+/**
+ * @private
+ */
+Log4js.Level.FATAL_INT = 50000;
+/**
+ * @private
+ */
+Log4js.Level.ERROR_INT = 40000;
+/**
+ * @private
+ */
+Log4js.Level.WARN_INT = 30000;
+/**
+ * @private
+ */
+Log4js.Level.INFO_INT = 20000;
+/**
+ * @private
+ */
+Log4js.Level.DEBUG_INT = 10000;
+/**
+ * @private
+ */
+Log4js.Level.TRACE_INT = 5000;
+/**
+ * @private
+ */
+Log4js.Level.ALL_INT = Number.MIN_VALUE;
+
+/**
+ * Logging Level OFF - all disabled
+ * @type Log4js.Level
+ */
+Log4js.Level.OFF = new Log4js.Level(Log4js.Level.OFF_INT, "OFF");
+Log4js.Level.FATAL = new Log4js.Level(Log4js.Level.FATAL_INT, "FATAL");
+Log4js.Level.ERROR = new Log4js.Level(Log4js.Level.ERROR_INT, "ERROR");
+Log4js.Level.WARN = new Log4js.Level(Log4js.Level.WARN_INT, "WARN");
+Log4js.Level.INFO = new Log4js.Level(Log4js.Level.INFO_INT, "INFO");
+Log4js.Level.DEBUG = new Log4js.Level(Log4js.Level.DEBUG_INT, "DEBUG");
+Log4js.Level.TRACE = new Log4js.Level(Log4js.Level.TRACE_INT, "TRACE");
+Log4js.Level.ALL = new Log4js.Level(Log4js.Level.ALL_INT, "ALL");
+
+/**
+ * Log4js CustomEvent
+ * @constructor
+ * @author Corey Johnson - original code in Lumberjack (http://gleepglop.com/javascripts/logger/)
+ * @author Seth Chisamore - adapted for Log4js
+ */
+Log4js.CustomEvent = function() {
+ this.listeners = [];
+}
+
+Log4js.CustomEvent.prototype = {
+
+ /**
+ * @param method method to be added
+ */
+ addListener : function(method) {
+ this.listeners.push(method)
+ },
+
+ /**
+ * @param method method to be removed
+ */
+ removeListener : function(method) {
+ var foundIndexes = this._findListenerIndexes(method)
+
+ for(var i = 0; i < foundIndexes.length; i++) {
+ this.listeners.splice(foundIndexes[i], 1)
+ }
+ },
+
+ /**
+ * @param handler
+ */
+ dispatch : function(handler) {
+ for(var i = 0; i < this.listeners.length; i++) {
+ try {
+ this.listeners[i](handler)
+ }
+ catch (e) {
+ alert("Could not run the listener " + this.listeners[i] + ". " + e.message)
+ }
+ }
+ },
+
+ /**
+ * @private
+ * @param method
+ */
+ _findListenerIndexes : function(method) {
+ var indexes = []
+ for(var i = 0; i < this.listeners.length; i++) {
+ if (this.listeners[i] == method) {
+ indexes.push(i)
+ }
+ }
+
+ return indexes
+ }
+}
+/**
+ * Models a logging event
+ * @constructor
+ * @param {String} categoryName name of category
+ * @param {Log4js.Level} level level of message
+ * @param {String} message message to log
+ * @param {Log4js.Logger} logger the logger
+ * @author Seth Chisamore
+ */
+Log4js.LoggingEvent = function(categoryName, level, message, logger) {
+ /**
+ * @type Date
+ * @private
+ */
+ this.startTime = new Date();
+ /**
+ * @type String
+ * @private
+ */
+ this.categoryName = categoryName || ".";
+ /**
+ * @type String
+ * @private
+ */
+ this.message = message || "";
+ /**
+ * @type Log4js.Level
+ * @private
+ */
+ this.level = level || Log4js.Level.TRACE;
+ /**
+ * @type Log4js.Logger
+ * @private
+ */
+ this.logger = logger;
+}
+Log4js.LoggingEvent.prototype = {
+ // TODO: Need to add support Layouts
+ /**
+ * Returns the layouted message line
+ * @return layouted Message
+ * @type String
+ */
+ getRenderedMessage: function() {
+ return this.categoryName + "~" + this.startTime.toLocaleString() + " [" + this.level.toString() + "] " + this.message;
+ }
+}
+
+/**
+ * Logger to log messages to the defined appender.
+ * Default appender is Appender, which is ignoring all messages. Please
+ * use setAppender() to set a specific appender (e.g. WindowAppender).
+ * @constructor
+ * @param name name of category to log to
+ * @author Stephan Strittmatter
+ */
+Log4js.Logger = function(name) {
+ this.loggingEvents = [];
+ this.appenders = [];
+ /** category of logger */
+ this.category = name || "";
+ /** level to be logged */
+ this.level = Log4js.Level.FATAL;
+
+ this.onlog = new Log4js.CustomEvent();
+ this.onclear = new Log4js.CustomEvent();
+
+ /** appender to write in */
+ this.appenders.push(new Appender(this));
+
+ // if multiple log objects are instanciated this will only log to the log object that is declared last
+ // can't seem to get the attachEvent method to work correctly
+ window.onerror = this.windowError.bind(this);
+}
+
+Log4js.Logger.prototype = {
+ /**
+ * Get a logger instance
+ * @param name name of category to log to
+ * @todo probably cache the logger here?
+ */
+ getLogger: function(name) {
+ return new Logger(name);
+ },
+ /**
+ * add additional appender. DefaultAppender always is there.
+ * @param appender additional wanted appender
+ */
+ addAppender: function(appender) {
+ this.appenders.push(appender);
+ },
+
+ /**
+ * Set the Loglevel default is LogLEvel.TRACE
+ * @param level wanted logging level
+ */
+ setLevel: function(level) {
+ this.level = level;
+ },
+
+ /** main log method logging to all available appenders */
+ log: function(message, logLevel) {
+ var loggingEvent = new Log4js.LoggingEvent(this.category, logLevel, message, this);
+ this.loggingEvents.push(loggingEvent);
+ this.onlog.dispatch(loggingEvent);
+ },
+
+ /** clear logging */
+ clear : function () {
+ this.loggingEvents = [];
+ this.onclear.dispatch();
+ },
+
+ /** checks if Level Trace is enabled */
+ isTraceEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.TRACE.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+ /** logging trace messages */
+ trace: function(message) {
+ if (this.isTraceEnabled()) {
+ this.log(message, Log4js.Level.TRACE);
+ }
+ },
+ /** checks if Level Debug is enabled */
+ isDebugEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.DEBUG.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+ /** logging debug messages */
+ debug: function(message) {
+ if (this.isDebugEnabled()) {
+ this.log(message, Log4js.Level.DEBUG);
+ }
+ },
+ /** checks if Level Info is enabled */
+ isInfoEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.INFO.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+ /** logging info messages */
+ info: function(message) {
+ if (this.isInfoEnabled()) {
+ this.log(message, Log4js.Level.INFO);
+ }
+ },
+ /** checks if Level Warn is enabled */
+ isWarnEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.WARN.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+
+ /** logging warn messages */
+ warn: function(message) {
+ if (this.isWarnEnabled()) {
+ this.log(message, Log4js.Level.WARN);
+ }
+ },
+ /** checks if Level Error is enabled */
+ isErrorEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.ERROR.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+ /** logging error messages */
+ error: function(message) {
+ if (this.isErrorEnabled()) {
+ this.log(message, Log4js.Level.ERROR);
+ }
+ },
+ /** checks if Level Fatal is enabled */
+ isFatalEnabled: function() {
+ if (this.level.valueOf() <= Log4js.Level.FATAL.valueOf()) {
+ return true;
+ }
+ return false;
+ },
+ /** logging fatal messages */
+ fatal: function(message) {
+ if (this.isFatalEnabled()) {
+ this.log(message, Log4js.Level.FATAL);
+ }
+ },
+
+ /** capture main window errors and log as fatal */
+ windowError: function(msg, url, line){
+ var message = "Error in (" + (url || window.location) + ") on line "+ line +" with message (" + msg + ")";
+ this.log(message, Log4js.Level.FATAL);
+ }
+}
+
+/**
+ * Interface for Appender.
+ * Use this appender as "interface" for other appenders. It is doing nothing.
+ *
+ * @constructor
+ * @param {Log4js.Logger} logger log4js instance this appender is attached to
+ * @author Stephan Strittmatter
+ */
+function Appender(logger) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+}
+Appender.prototype = {
+ /**
+ * appends the given loggingEvent appender specific
+ * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to append
+ */
+ doAppend: function(loggingEvent) {},
+ /**
+ * clears the Appender
+ */
+ doClear: function() {}
+}
+
+/**
+ * Console Appender writes the logs to a console. If "useWindow" is
+ * set to "true" the console launches in another window otherwise
+ * the window is inline on the page and toggled on and off with "Alt-D".
+
+ * @constructor
+ * @extends Appender
+ * @param {Log4js.Logger} logger log4js instance this appender is attached to
+ * @param {boolean} inline boolean value that indicates whether the console be placed inline, default is to launch in new window
+ * @author Corey Johnson - original console code in Lumberjack (http://gleepglop.com/javascripts/logger/)
+ * @author Seth Chisamore - adapted for use as a log4js appender
+ */
+ConsoleAppender = function(logger, inline) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+ this.inline = inline || false;
+
+ if(this.inline) {
+ Log4js.attachEvent(window, 'load', this.initialize.bind(this));
+ }
+}
+
+ConsoleAppender.prototype = {
+
+ commandHistory : [],
+ commandIndex : 0,
+
+ /**
+ * @private
+ */
+ initialize : function() {
+
+ var doc = document;
+ var win = window;
+
+ if(!this.inline) {
+ window.top.consoleWindow = window.open("", "log4jsconsole", "left=0,top=0,width=700,height=700,scrollbars=no,status=no,resizable=no;toolbar=no");
+ window.top.consoleWindow.opener = self;
+ win = window.top.consoleWindow;
+ doc = win.document;
+ doc.open();
+ doc.write("\n\n");
+ doc.write("log4js\n");
+ doc.write("\n");
+ win.blur();
+ win.focus();
+ }
+
+ this.docReference = doc;
+ this.winReference = win;
+
+ this.outputCount = 0;
+ this.tagPattern = ".*";
+
+ // I hate writing javascript in HTML... but what's a better alternative
+ this.logElement = doc.createElement('div');
+ doc.body.appendChild(this.logElement);
+ this.logElement.style.display = 'none';
+
+ this.logElement.style.position = "absolute";
+ this.logElement.style.left = '0px';
+ this.logElement.style.width = '100%';
+
+ this.logElement.style.textAlign = "left";
+ this.logElement.style.fontFamily = "lucida console";
+ this.logElement.style.fontSize = "100%";
+ this.logElement.style.backgroundColor = 'darkgray';
+ this.logElement.style.opacity = 0.9;
+ this.logElement.style.zIndex = 2000;
+
+ // Add toolbarElement
+ this.toolbarElement = doc.createElement('div');
+ this.logElement.appendChild(this.toolbarElement);
+ this.toolbarElement.style.padding = "0 0 0 2px";
+
+ // Add buttons
+ this.buttonsContainerElement = doc.createElement('span');
+ this.toolbarElement.appendChild(this.buttonsContainerElement);
+
+ if(this.inline) {
+ var closeButton = doc.createElement('button');
+ closeButton.style.cssFloat = "right";
+ closeButton.style.styleFloat = "right"; // IE dom bug...doesn't understand cssFloat
+ closeButton.style.color = "black";
+ closeButton.innerHTML = "close";
+ closeButton.onclick = this.toggle.bind(this);
+ this.buttonsContainerElement.appendChild(closeButton);
+ }
+
+ var clearButton = doc.createElement('button');
+ clearButton.style.cssFloat = "right";
+ clearButton.style.styleFloat = "right"; // IE dom bug...doesn't understand cssFloat
+ clearButton.style.color = "black";
+ clearButton.innerHTML = "clear";
+ clearButton.onclick = this.logger.clear.bind(this.logger);
+ this.buttonsContainerElement.appendChild(clearButton);
+
+ //Add Level Filter
+ this.tagFilterContainerElement = doc.createElement('span');
+ this.toolbarElement.appendChild(this.tagFilterContainerElement);
+ this.tagFilterContainerElement.style.cssFloat = 'left';
+ this.tagFilterContainerElement.appendChild(doc.createTextNode("Level Filter"));
+
+ this.tagFilterElement = doc.createElement('input');
+ this.tagFilterContainerElement.appendChild(this.tagFilterElement);
+ this.tagFilterElement.style.width = '200px';
+ this.tagFilterElement.value = this.tagPattern;
+ this.tagFilterElement.setAttribute('autocomplete', 'off'); // So Firefox doesn't flip out
+
+ Log4js.attachEvent(this.tagFilterElement, 'keyup', this.updateTags.bind(this));
+ Log4js.attachEvent(this.tagFilterElement, 'click', function() {this.tagFilterElement.select()}.bind(this));
+
+ // Add outputElement
+ this.outputElement = doc.createElement('div');
+ this.logElement.appendChild(this.outputElement);
+ this.outputElement.style.overflow = "auto";
+ this.outputElement.style.clear = "both";
+ this.outputElement.style.height = (this.inline) ? ("200px"):("650px");
+ this.outputElement.style.width = "100%";
+ this.outputElement.style.backgroundColor = 'black';
+
+ this.inputContainerElement = doc.createElement('div');
+ this.inputContainerElement.style.width = "100%";
+ this.logElement.appendChild(this.inputContainerElement);
+
+ this.inputElement = doc.createElement('input');
+ this.inputContainerElement.appendChild(this.inputElement);
+ this.inputElement.style.width = '100%';
+ this.inputElement.style.borderWidth = '0px'; // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0
+ this.inputElement.style.margin = '0px';
+ this.inputElement.style.padding = '0px';
+ this.inputElement.value = 'Type command here';
+ this.inputElement.setAttribute('autocomplete', 'off'); // So Firefox doesn't flip out
+
+ Log4js.attachEvent(this.inputElement, 'keyup', this.handleInput.bind(this));
+ Log4js.attachEvent(this.inputElement, 'click', function() {this.inputElement.select()}.bind(this));
+
+ if(this.inline){
+ window.setInterval(this.repositionWindow.bind(this), 500);
+ this.repositionWindow();
+ // Allow acess key link
+ var accessElement = doc.createElement('button');
+ accessElement.style.position = "absolute";
+ accessElement.style.top = "-100px";
+ accessElement.accessKey = "d";
+ accessElement.onclick = this.toggle.bind(this);
+ doc.body.appendChild(accessElement);
+ } else {
+ this.show();
+ }
+ },
+ /**
+ * shows/hide an element
+ * @private
+ */
+ toggle : function() {
+ if (this.logElement.style.display == 'none') {
+ this.show();
+ } else {
+ this.hide();
+ }
+ },
+ /**
+ * @private
+ */
+ show : function() {
+ this.logElement.style.display = '';
+ this.outputElement.scrollTop = this.outputElement.scrollHeight; // Scroll to bottom when toggled
+ this.inputElement.select();
+ },
+ /**
+ * @private
+ */
+ hide : function() {
+ this.logElement.style.display = 'none';
+ },
+ /**
+ * @private
+ * @param message
+ * @style
+ */
+ output : function(message, style) {
+
+ // If we are at the bottom of the window, then keep scrolling with the output
+ var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight;
+
+ this.outputCount++;
+ style = (style ? style += ';' : '');
+ style += 'padding:1px;margin:0 0 5px 0';
+
+ if (this.outputCount % 2 == 0) style += ";background-color:#101010";
+
+ message = message || "undefined";
+ message = message.toString();
+
+ this.outputElement.innerHTML += "
" + message + "
";
+
+ if (shouldScroll) {
+ this.outputElement.scrollTop = this.outputElement.scrollHeight;
+ }
+ },
+
+ /**
+ * @private
+ */
+ updateTags : function() {
+
+ var pattern = this.tagFilterElement.value;
+
+ if (this.tagPattern == pattern) return;
+
+ try {
+ new RegExp(pattern);
+ } catch (e) {
+ return;
+ }
+
+ this.tagPattern = pattern;
+
+ this.outputElement.innerHTML = "";
+
+ // Go through each log entry again
+ this.outputCount = 0;
+ for (var i = 0; i < this.logger.loggingEvents.length; i++) {
+ this.doAppend(this.logger.loggingEvents[i]);
+ }
+ },
+
+ /**
+ * @private
+ */
+ repositionWindow : function() {
+ var offset = window.pageYOffset || this.docReference.documentElement.scrollTop || this.docReference.body.scrollTop;
+ var pageHeight = self.innerHeight || this.docReference.documentElement.clientHeight || this.docReference.body.clientHeight;
+ this.logElement.style.top = (offset + pageHeight - this.logElement.offsetHeight) + "px";
+ },
+
+ /**
+ * @param loggingEvent event to be logged
+ * @see Appender#doAppend
+ */
+ doAppend : function(loggingEvent) {
+
+ if ((!this.inline) && (!this.winReference || this.winReference.closed)) {
+ this.initialize();
+ }
+
+ if (loggingEvent.level.toString().search(new RegExp(this.tagPattern, 'igm')) == -1)
+ return;
+
+ var style = '';
+
+ if (loggingEvent.level.toString().search(/ERROR/) != -1) {
+ style += 'color:red';
+ } else if (loggingEvent.level.toString().search(/FATAL/) != -1) {
+ style += 'color:red';
+ } else if (loggingEvent.level.toString().search(/WARN/) != -1) {
+ style += 'color:orange';
+ } else if (loggingEvent.level.toString().search(/DEBUG/) != -1) {
+ style += 'color:green';
+ } else if (loggingEvent.level.toString().search(/INFO/) != -1) {
+ style += 'color:white';
+ } else {
+ style += 'color:yellow';
+ }
+
+ this.output(loggingEvent.getRenderedMessage(), style);
+ },
+
+ /**
+ * @see Appender#doClear
+ */
+ doClear : function() {
+ this.outputElement.innerHTML = "";
+ },
+ /**
+ * @private
+ * @param e
+ */
+ handleInput : function(e) {
+ if (e.keyCode == 13 ) {
+ var command = this.inputElement.value
+
+ switch(command) {
+ case "clear":
+ this.logger.clear();
+ break;
+
+ default:
+ var consoleOutput = "" ;
+
+ try {
+ consoleOutput = eval(this.inputElement.value);
+ } catch (e) {
+ this.logger.error("Problem parsing input <" + command + ">" + e.message);
+ break;
+ }
+
+ this.logger.trace(consoleOutput);
+ break;
+ }
+
+ if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
+ this.commandHistory.unshift(this.inputElement.value);
+ }
+
+ this.commandIndex = 0;
+ this.inputElement.value = "";
+ } else if (e.keyCode == 38 && this.commandHistory.length > 0) {
+ this.inputElement.value = this.commandHistory[this.commandIndex];
+
+ if (this.commandIndex < this.commandHistory.length - 1) {
+ this.commandIndex += 1;
+ }
+ } else if (e.keyCode == 40 && this.commandHistory.length > 0) {
+ if (this.commandIndex > 0) {
+ this.commandIndex -= 1;
+ }
+
+ this.inputElement.value = this.commandHistory[this.commandIndex];
+ } else {
+ this.commandIndex = 0;
+ }
+ }
+}
+
+/**
+ * Metatag Appender writing the logs to meta tags
+ *
+ * @extends Appender
+ * @constructor
+ * @param logger log4js instance this appender is attached to
+ * @author Stephan Strittmatter
+ */
+function MetatagAppender(logger) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+}
+
+MetatagAppender.prototype = {
+ /**
+ * @param loggingEvent event to be logged
+ * @see Appender#doAppend
+ */
+ doAppend: function(loggingEvent) {
+ var now = new Date();
+ var lines = loggingEvent.message.split("\n");
+ var headTag = document.getElementsByTagName("head")[0];
+
+ for (var i = 1; i <= lines.length; i++) {
+ var value = lines[i - 1];
+ if (i == 1) {
+ value = loggingEvent.level.toString() + ": " + value;
+ } else {
+ value = "> " + value;
+ }
+
+ var metaTag = document.createElement("meta");
+ metaTag.setAttribute("name", "X-log4js:" + this.logger.currentLine++);
+ metaTag.setAttribute("content", value);
+ headTag.appendChild(metaTag);
+ }
+ },
+ /**
+ * do nothing
+ * @see Appender#doClear
+ */
+ doClear: function() {}
+};
+
+/**
+ * AJAX Appender sending logging messages asynchron via XMLHttpREquest to server
+ *
+ * @extends Appender
+ * @constructor
+ * @param {Log4js.Logger} logger log4js instance this appender is attached to
+ * @param {String} loggingUrl url where appender will post log messages to
+ * @author Stephan Strittmatter
+ */
+function AjaxAppender(logger, loggingUrl) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+ /**
+ * @type XMLHttpRequest
+ */
+ this.httpRequest = false;
+ this.loggingUrl = loggingUrl || "log4js.jsp";
+
+ if (window.XMLHttpRequest) { // Mozilla, Safari,...
+ this.httpRequest = new XMLHttpRequest();
+ if (this.httpRequest.overrideMimeType) {
+ this.httpRequest.overrideMimeType('text/xml');
+ }
+ } else if (window.ActiveXObject) { // IE
+ try {
+ this.httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {
+ this.httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ }
+ if (!this.httpRequest) {
+ alert('Unfortunatelly you browser doesn\'t support AJAX appender for log4js!');
+ }else{
+ // this.httpRequest.onreadystatechange = this.logged;
+ }
+};
+
+AjaxAppender.prototype = {
+ /**
+ * sends the logs to the server
+ * @param loggingEvent event to be logged
+ * @see Appender#doAppend
+ */
+ doAppend: function(loggingEvent) {
+ var msg = "log4js.client=" + navigator.userAgent
+ + "&log4js.category=" + loggingEvent.categoryName
+ + "&log4js.level=" + loggingEvent.level.toString()
+ + "&log4js.msg=" + loggingEvent.message;
+
+ this.httpRequest.open("POST", this.loggingUrl + "?" + msg , true);
+ this.httpRequest.send("" + loggingEvent.categoryName + ""
+ + loggingEvent.level.toString() + ""
+ + navigator.userAgent + ""
+ + loggingEvent.message + "");
+ },
+ /**
+ * callback method only to verify if sending was successful
+ */
+ logged: function() {
+ if (this.httpRequest.readyState == 4) {
+ if (this.httpRequest.status != 200 ) {
+ alert('There was a problem with the log4js AjaxAppender: ' + this.httpRequest.responseText );
+ }
+ }
+ },
+ /**
+ * @see Appender#doClear
+ */
+ doClear: function() {}
+};
+
+/**
+ * File Appender writing the logs to a text file.
+ * PLEASE NOTE - Only works in IE..uses ActiveX to write file
+ *
+ * @extends Appender
+ * @constructor
+ * @param logger log4js instance this appender is attached to
+ * @param file file log messages will be written to
+ * @author Seth Chisamore
+ */
+function FileAppender(logger, file) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+
+ this.file = file || "C:\\log4js.log";
+ try{
+ this.fso = new ActiveXObject("Scripting.FileSystemObject");
+ } catch(e){}
+};
+
+FileAppender.prototype = {
+ /**
+ * @param loggingEvent event to be logged
+ * @see Appender#doAppend
+ */
+ doAppend: function(loggingEvent) {
+ try {
+ // try opening existing file, create if needed
+ var fileHandle = this.fso.OpenTextFile(this.file, 8, true);
+ // write out our data
+ fileHandle.WriteLine(loggingEvent.getRenderedMessage());
+ fileHandle.close();
+ } catch (e) {}
+ },
+ /*
+ * @see Appender#doClear
+ */
+ doClear: function() {
+ try {
+ var fileHandle = this.fso.GetFile(this.file);
+ fileHandle.Delete();
+ } catch (e) {
+
+ }
+ }
+};
+
+/**
+ * Windows Event Appender writes the logs to the Windows Event log.
+ * PLEASE NOTE - Only works in IE..uses ActiveX to write to Windows Event log
+ *
+ * @extends Appender
+ * @constructor
+ * @param logger log4js instance this appender is attached to
+ * @author Seth Chisamore
+ */
+function WindowsEventAppender(logger) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+
+ try {
+ this.shell = new ActiveXObject("WScript.Shell");
+ } catch(e) {}
+};
+
+WindowsEventAppender.prototype = {
+ /**
+ * @param loggingEvent event to be logged
+ * @see Appender#doAppend
+ */
+ doAppend: function(loggingEvent) {
+ var winLevel = 4;
+
+ // Map log level to windows event log level.
+ // Windows events: - SUCCESS: 0, ERROR: 1, WARNING: 2, INFORMATION: 4, AUDIT_SUCCESS: 8, AUDIT_FAILURE: 16
+ switch (loggingEvent.level) {
+ case Log4js.Level.FATAL:
+ winLevel = 1;
+ break;
+ case Log4js.Level.ERROR:
+ winLevel = 1;
+ break;
+ case Log4js.Level.WARN:
+ winLevel = 2;
+ break;
+ default:
+ winLevel = 4;
+ break;
+ }
+
+ try {
+ this.shell.LogEvent(winLevel, loggingEvent.getRenderedMessage());
+ } catch(e) {
+
+ }
+ },
+ /**
+ * @see Appender#doClear
+ */
+ doClear: function() {}
+};
+
+/**
+ * JS Alert Appender writes the logs to the JavaScript alert dialog box
+ * @constructor
+ * @extends Appender
+ * @param logger log4js instance this appender is attached to
+ * @author S?bastien LECACHEUR
+ */
+function JSAlertAppender(logger) {
+ // add listener to the logger methods
+ logger.onlog.addListener(this.doAppend.bind(this));
+ logger.onclear.addListener(this.doClear.bind(this));
+ /**
+ * set reference to calling logger
+ * @type Log4js.Logger
+ */
+ this.logger = logger;
+};
+
+JSAlertAppender.prototype = {
+ /**
+ * @see Appender#doAppend
+ */
+ doAppend: function(category, message, level) {
+ var now = new Date();
+ alert(category + " " + now.toLocaleString() + " [" + LogLevel.valueOf(level) + "] " + message);
+ },
+ /**
+ * @see Appender#doClear
+ */
+ doClear: function() {}
+};
+
+/**
+ * Functions taken from Prototype library,
+ * didn't want to require for just few functions
+ * More info at {@link http://prototype.conio.net/}
+ */
+if (!Array.prototype.push) {
+ Array.prototype.push = function() {
+ var startLength = this.length;
+ for (var i = 0; i < arguments.length; i++)
+ this[startLength + i] = arguments[i];
+ return this.length;
+ }
+}
+
+if(!Function.prototype.bind) {
+ /**
+ * Functions taken from Prototype library,
+ * didn't want to require for just few functions
+ * More info at {@link http://prototype.conio.net/}
+ */
+ Function.prototype.bind = function(object) {
+ var __method = this;
+ return function() {
+ return __method.apply(object, arguments);
+ }
+ }
+}
\ No newline at end of file