Siobhan Tully | e18b344 | 2014-02-23 14:23:34 -0500 | [diff] [blame] | 1 | /**
|
| 2 | * Copyright 2013 Tim Down.
|
| 3 | *
|
| 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 | * you may not use this file except in compliance with the License.
|
| 6 | * You may obtain a copy of the License at
|
| 7 | *
|
| 8 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 9 | *
|
| 10 | * Unless required by applicable law or agreed to in writing, software
|
| 11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 | * See the License for the specific language governing permissions and
|
| 14 | * limitations under the License.
|
| 15 | */
|
| 16 |
|
| 17 | /**
|
| 18 | * log4javascript
|
| 19 | *
|
| 20 | * log4javascript is a logging framework for JavaScript based on log4j
|
| 21 | * for Java. This file contains all core log4javascript code and is the only
|
| 22 | * file required to use log4javascript, unless you require support for
|
| 23 | * document.domain, in which case you will also need console.html, which must be
|
| 24 | * stored in the same directory as the main log4javascript.js file.
|
| 25 | *
|
| 26 | * Author: Tim Down <tim@log4javascript.org>
|
| 27 | * Version: 1.4.6
|
| 28 | * Edition: log4javascript
|
| 29 | * Build date: 19 March 2013
|
| 30 | * Website: http://log4javascript.org
|
| 31 | */
|
| 32 |
|
| 33 | /* -------------------------------------------------------------------------- */
|
| 34 | // Array-related stuff
|
| 35 |
|
| 36 | // Next three methods are solely for IE5, which is missing them
|
| 37 | if (!Array.prototype.push) {
|
| 38 | Array.prototype.push = function() {
|
| 39 | for (var i = 0, len = arguments.length; i < len; i++){
|
| 40 | this[this.length] = arguments[i];
|
| 41 | }
|
| 42 | return this.length;
|
| 43 | };
|
| 44 | }
|
| 45 |
|
| 46 | if (!Array.prototype.shift) {
|
| 47 | Array.prototype.shift = function() {
|
| 48 | if (this.length > 0) {
|
| 49 | var firstItem = this[0];
|
| 50 | for (var i = 0, len = this.length - 1; i < len; i++) {
|
| 51 | this[i] = this[i + 1];
|
| 52 | }
|
| 53 | this.length = this.length - 1;
|
| 54 | return firstItem;
|
| 55 | }
|
| 56 | };
|
| 57 | }
|
| 58 |
|
| 59 | if (!Array.prototype.splice) {
|
| 60 | Array.prototype.splice = function(startIndex, deleteCount) {
|
| 61 | var itemsAfterDeleted = this.slice(startIndex + deleteCount);
|
| 62 | var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);
|
| 63 | this.length = startIndex;
|
| 64 | // Copy the arguments into a proper Array object
|
| 65 | var argumentsArray = [];
|
| 66 | for (var i = 0, len = arguments.length; i < len; i++) {
|
| 67 | argumentsArray[i] = arguments[i];
|
| 68 | }
|
| 69 | var itemsToAppend = (argumentsArray.length > 2) ?
|
| 70 | itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;
|
| 71 | for (i = 0, len = itemsToAppend.length; i < len; i++) {
|
| 72 | this.push(itemsToAppend[i]);
|
| 73 | }
|
| 74 | return itemsDeleted;
|
| 75 | };
|
| 76 | }
|
| 77 |
|
| 78 | /* -------------------------------------------------------------------------- */
|
| 79 |
|
| 80 | var log4javascript = (function() {
|
| 81 |
|
| 82 | function isUndefined(obj) {
|
| 83 | return typeof obj == "undefined";
|
| 84 | }
|
| 85 |
|
| 86 | /* ---------------------------------------------------------------------- */
|
| 87 | // Custom event support
|
| 88 |
|
| 89 | function EventSupport() {}
|
| 90 |
|
| 91 | EventSupport.prototype = {
|
| 92 | eventTypes: [],
|
| 93 | eventListeners: {},
|
| 94 | setEventTypes: function(eventTypesParam) {
|
| 95 | if (eventTypesParam instanceof Array) {
|
| 96 | this.eventTypes = eventTypesParam;
|
| 97 | this.eventListeners = {};
|
| 98 | for (var i = 0, len = this.eventTypes.length; i < len; i++) {
|
| 99 | this.eventListeners[this.eventTypes[i]] = [];
|
| 100 | }
|
| 101 | } else {
|
| 102 | handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");
|
| 103 | }
|
| 104 | },
|
| 105 |
|
| 106 | addEventListener: function(eventType, listener) {
|
| 107 | if (typeof listener == "function") {
|
| 108 | if (!array_contains(this.eventTypes, eventType)) {
|
| 109 | handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");
|
| 110 | }
|
| 111 | this.eventListeners[eventType].push(listener);
|
| 112 | } else {
|
| 113 | handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");
|
| 114 | }
|
| 115 | },
|
| 116 |
|
| 117 | removeEventListener: function(eventType, listener) {
|
| 118 | if (typeof listener == "function") {
|
| 119 | if (!array_contains(this.eventTypes, eventType)) {
|
| 120 | handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");
|
| 121 | }
|
| 122 | array_remove(this.eventListeners[eventType], listener);
|
| 123 | } else {
|
| 124 | handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");
|
| 125 | }
|
| 126 | },
|
| 127 |
|
| 128 | dispatchEvent: function(eventType, eventArgs) {
|
| 129 | if (array_contains(this.eventTypes, eventType)) {
|
| 130 | var listeners = this.eventListeners[eventType];
|
| 131 | for (var i = 0, len = listeners.length; i < len; i++) {
|
| 132 | listeners[i](this, eventType, eventArgs);
|
| 133 | }
|
| 134 | } else {
|
| 135 | handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");
|
| 136 | }
|
| 137 | }
|
| 138 | };
|
| 139 |
|
| 140 | /* -------------------------------------------------------------------------- */
|
| 141 |
|
| 142 | var applicationStartDate = new Date();
|
| 143 | var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +
|
| 144 | Math.floor(Math.random() * 100000000);
|
| 145 | var emptyFunction = function() {};
|
| 146 | var newLine = "\r\n";
|
| 147 | var pageLoaded = false;
|
| 148 |
|
| 149 | // Create main log4javascript object; this will be assigned public properties
|
| 150 | function Log4JavaScript() {}
|
| 151 | Log4JavaScript.prototype = new EventSupport();
|
| 152 |
|
| 153 | log4javascript = new Log4JavaScript();
|
| 154 | log4javascript.version = "1.4.6";
|
| 155 | log4javascript.edition = "log4javascript";
|
| 156 |
|
| 157 | /* -------------------------------------------------------------------------- */
|
| 158 | // Utility functions
|
| 159 |
|
| 160 | function toStr(obj) {
|
| 161 | if (obj && obj.toString) {
|
| 162 | return obj.toString();
|
| 163 | } else {
|
| 164 | return String(obj);
|
| 165 | }
|
| 166 | }
|
| 167 |
|
| 168 | function getExceptionMessage(ex) {
|
| 169 | if (ex.message) {
|
| 170 | return ex.message;
|
| 171 | } else if (ex.description) {
|
| 172 | return ex.description;
|
| 173 | } else {
|
| 174 | return toStr(ex);
|
| 175 | }
|
| 176 | }
|
| 177 |
|
| 178 | // Gets the portion of the URL after the last slash
|
| 179 | function getUrlFileName(url) {
|
| 180 | var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));
|
| 181 | return url.substr(lastSlashIndex + 1);
|
| 182 | }
|
| 183 |
|
| 184 | // Returns a nicely formatted representation of an error
|
| 185 | function getExceptionStringRep(ex) {
|
| 186 | if (ex) {
|
| 187 | var exStr = "Exception: " + getExceptionMessage(ex);
|
| 188 | try {
|
| 189 | if (ex.lineNumber) {
|
| 190 | exStr += " on line number " + ex.lineNumber;
|
| 191 | }
|
| 192 | if (ex.fileName) {
|
| 193 | exStr += " in file " + getUrlFileName(ex.fileName);
|
| 194 | }
|
| 195 | } catch (localEx) {
|
| 196 | logLog.warn("Unable to obtain file and line information for error");
|
| 197 | }
|
| 198 | if (showStackTraces && ex.stack) {
|
| 199 | exStr += newLine + "Stack trace:" + newLine + ex.stack;
|
| 200 | }
|
| 201 | return exStr;
|
| 202 | }
|
| 203 | return null;
|
| 204 | }
|
| 205 |
|
| 206 | function bool(obj) {
|
| 207 | return Boolean(obj);
|
| 208 | }
|
| 209 |
|
| 210 | function trim(str) {
|
| 211 | return str.replace(/^\s+/, "").replace(/\s+$/, "");
|
| 212 | }
|
| 213 |
|
| 214 | function splitIntoLines(text) {
|
| 215 | // Ensure all line breaks are \n only
|
| 216 | var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
| 217 | return text2.split("\n");
|
| 218 | }
|
| 219 |
|
| 220 | var urlEncode = (typeof window.encodeURIComponent != "undefined") ?
|
| 221 | function(str) {
|
| 222 | return encodeURIComponent(str);
|
| 223 | }:
|
| 224 | function(str) {
|
| 225 | return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");
|
| 226 | };
|
| 227 |
|
| 228 | var urlDecode = (typeof window.decodeURIComponent != "undefined") ?
|
| 229 | function(str) {
|
| 230 | return decodeURIComponent(str);
|
| 231 | }:
|
| 232 | function(str) {
|
| 233 | return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");
|
| 234 | };
|
| 235 |
|
| 236 | function array_remove(arr, val) {
|
| 237 | var index = -1;
|
| 238 | for (var i = 0, len = arr.length; i < len; i++) {
|
| 239 | if (arr[i] === val) {
|
| 240 | index = i;
|
| 241 | break;
|
| 242 | }
|
| 243 | }
|
| 244 | if (index >= 0) {
|
| 245 | arr.splice(index, 1);
|
| 246 | return true;
|
| 247 | } else {
|
| 248 | return false;
|
| 249 | }
|
| 250 | }
|
| 251 |
|
| 252 | function array_contains(arr, val) {
|
| 253 | for(var i = 0, len = arr.length; i < len; i++) {
|
| 254 | if (arr[i] == val) {
|
| 255 | return true;
|
| 256 | }
|
| 257 | }
|
| 258 | return false;
|
| 259 | }
|
| 260 |
|
| 261 | function extractBooleanFromParam(param, defaultValue) {
|
| 262 | if (isUndefined(param)) {
|
| 263 | return defaultValue;
|
| 264 | } else {
|
| 265 | return bool(param);
|
| 266 | }
|
| 267 | }
|
| 268 |
|
| 269 | function extractStringFromParam(param, defaultValue) {
|
| 270 | if (isUndefined(param)) {
|
| 271 | return defaultValue;
|
| 272 | } else {
|
| 273 | return String(param);
|
| 274 | }
|
| 275 | }
|
| 276 |
|
| 277 | function extractIntFromParam(param, defaultValue) {
|
| 278 | if (isUndefined(param)) {
|
| 279 | return defaultValue;
|
| 280 | } else {
|
| 281 | try {
|
| 282 | var value = parseInt(param, 10);
|
| 283 | return isNaN(value) ? defaultValue : value;
|
| 284 | } catch (ex) {
|
| 285 | logLog.warn("Invalid int param " + param, ex);
|
| 286 | return defaultValue;
|
| 287 | }
|
| 288 | }
|
| 289 | }
|
| 290 |
|
| 291 | function extractFunctionFromParam(param, defaultValue) {
|
| 292 | if (typeof param == "function") {
|
| 293 | return param;
|
| 294 | } else {
|
| 295 | return defaultValue;
|
| 296 | }
|
| 297 | }
|
| 298 |
|
| 299 | function isError(err) {
|
| 300 | return (err instanceof Error);
|
| 301 | }
|
| 302 |
|
| 303 | if (!Function.prototype.apply){
|
| 304 | Function.prototype.apply = function(obj, args) {
|
| 305 | var methodName = "__apply__";
|
| 306 | if (typeof obj[methodName] != "undefined") {
|
| 307 | methodName += String(Math.random()).substr(2);
|
| 308 | }
|
| 309 | obj[methodName] = this;
|
| 310 |
|
| 311 | var argsStrings = [];
|
| 312 | for (var i = 0, len = args.length; i < len; i++) {
|
| 313 | argsStrings[i] = "args[" + i + "]";
|
| 314 | }
|
| 315 | var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";
|
| 316 | var returnValue = eval(script);
|
| 317 | delete obj[methodName];
|
| 318 | return returnValue;
|
| 319 | };
|
| 320 | }
|
| 321 |
|
| 322 | if (!Function.prototype.call){
|
| 323 | Function.prototype.call = function(obj) {
|
| 324 | var args = [];
|
| 325 | for (var i = 1, len = arguments.length; i < len; i++) {
|
| 326 | args[i - 1] = arguments[i];
|
| 327 | }
|
| 328 | return this.apply(obj, args);
|
| 329 | };
|
| 330 | }
|
| 331 |
|
| 332 | function getListenersPropertyName(eventName) {
|
| 333 | return "__log4javascript_listeners__" + eventName;
|
| 334 | }
|
| 335 |
|
| 336 | function addEvent(node, eventName, listener, useCapture, win) {
|
| 337 | win = win ? win : window;
|
| 338 | if (node.addEventListener) {
|
| 339 | node.addEventListener(eventName, listener, useCapture);
|
| 340 | } else if (node.attachEvent) {
|
| 341 | node.attachEvent("on" + eventName, listener);
|
| 342 | } else {
|
| 343 | var propertyName = getListenersPropertyName(eventName);
|
| 344 | if (!node[propertyName]) {
|
| 345 | node[propertyName] = [];
|
| 346 | // Set event handler
|
| 347 | node["on" + eventName] = function(evt) {
|
| 348 | evt = getEvent(evt, win);
|
| 349 | var listenersPropertyName = getListenersPropertyName(eventName);
|
| 350 |
|
| 351 | // Clone the array of listeners to leave the original untouched
|
| 352 | var listeners = this[listenersPropertyName].concat([]);
|
| 353 | var currentListener;
|
| 354 |
|
| 355 | // Call each listener in turn
|
| 356 | while ((currentListener = listeners.shift())) {
|
| 357 | currentListener.call(this, evt);
|
| 358 | }
|
| 359 | };
|
| 360 | }
|
| 361 | node[propertyName].push(listener);
|
| 362 | }
|
| 363 | }
|
| 364 |
|
| 365 | function removeEvent(node, eventName, listener, useCapture) {
|
| 366 | if (node.removeEventListener) {
|
| 367 | node.removeEventListener(eventName, listener, useCapture);
|
| 368 | } else if (node.detachEvent) {
|
| 369 | node.detachEvent("on" + eventName, listener);
|
| 370 | } else {
|
| 371 | var propertyName = getListenersPropertyName(eventName);
|
| 372 | if (node[propertyName]) {
|
| 373 | array_remove(node[propertyName], listener);
|
| 374 | }
|
| 375 | }
|
| 376 | }
|
| 377 |
|
| 378 | function getEvent(evt, win) {
|
| 379 | win = win ? win : window;
|
| 380 | return evt ? evt : win.event;
|
| 381 | }
|
| 382 |
|
| 383 | function stopEventPropagation(evt) {
|
| 384 | if (evt.stopPropagation) {
|
| 385 | evt.stopPropagation();
|
| 386 | } else if (typeof evt.cancelBubble != "undefined") {
|
| 387 | evt.cancelBubble = true;
|
| 388 | }
|
| 389 | evt.returnValue = false;
|
| 390 | }
|
| 391 |
|
| 392 | /* ---------------------------------------------------------------------- */
|
| 393 | // Simple logging for log4javascript itself
|
| 394 |
|
| 395 | var logLog = {
|
| 396 | quietMode: false,
|
| 397 |
|
| 398 | debugMessages: [],
|
| 399 |
|
| 400 | setQuietMode: function(quietMode) {
|
| 401 | this.quietMode = bool(quietMode);
|
| 402 | },
|
| 403 |
|
| 404 | numberOfErrors: 0,
|
| 405 |
|
| 406 | alertAllErrors: false,
|
| 407 |
|
| 408 | setAlertAllErrors: function(alertAllErrors) {
|
| 409 | this.alertAllErrors = alertAllErrors;
|
| 410 | },
|
| 411 |
|
| 412 | debug: function(message) {
|
| 413 | this.debugMessages.push(message);
|
| 414 | },
|
| 415 |
|
| 416 | displayDebug: function() {
|
| 417 | alert(this.debugMessages.join(newLine));
|
| 418 | },
|
| 419 |
|
| 420 | warn: function(message, exception) {
|
| 421 | },
|
| 422 |
|
| 423 | error: function(message, exception) {
|
| 424 | if (++this.numberOfErrors == 1 || this.alertAllErrors) {
|
| 425 | if (!this.quietMode) {
|
| 426 | var alertMessage = "log4javascript error: " + message;
|
| 427 | if (exception) {
|
| 428 | alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);
|
| 429 | }
|
| 430 | alert(alertMessage);
|
| 431 | }
|
| 432 | }
|
| 433 | }
|
| 434 | };
|
| 435 | log4javascript.logLog = logLog;
|
| 436 |
|
| 437 | log4javascript.setEventTypes(["load", "error"]);
|
| 438 |
|
| 439 | function handleError(message, exception) {
|
| 440 | logLog.error(message, exception);
|
| 441 | log4javascript.dispatchEvent("error", { "message": message, "exception": exception });
|
| 442 | }
|
| 443 |
|
| 444 | log4javascript.handleError = handleError;
|
| 445 |
|
| 446 | /* ---------------------------------------------------------------------- */
|
| 447 |
|
| 448 | var enabled = !((typeof log4javascript_disabled != "undefined") &&
|
| 449 | log4javascript_disabled);
|
| 450 |
|
| 451 | log4javascript.setEnabled = function(enable) {
|
| 452 | enabled = bool(enable);
|
| 453 | };
|
| 454 |
|
| 455 | log4javascript.isEnabled = function() {
|
| 456 | return enabled;
|
| 457 | };
|
| 458 |
|
| 459 | var useTimeStampsInMilliseconds = true;
|
| 460 |
|
| 461 | log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {
|
| 462 | useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);
|
| 463 | };
|
| 464 |
|
| 465 | log4javascript.isTimeStampsInMilliseconds = function() {
|
| 466 | return useTimeStampsInMilliseconds;
|
| 467 | };
|
| 468 |
|
| 469 |
|
| 470 | // This evaluates the given expression in the current scope, thus allowing
|
| 471 | // scripts to access private variables. Particularly useful for testing
|
| 472 | log4javascript.evalInScope = function(expr) {
|
| 473 | return eval(expr);
|
| 474 | };
|
| 475 |
|
| 476 | var showStackTraces = false;
|
| 477 |
|
| 478 | log4javascript.setShowStackTraces = function(show) {
|
| 479 | showStackTraces = bool(show);
|
| 480 | };
|
| 481 |
|
| 482 | /* ---------------------------------------------------------------------- */
|
| 483 | // Levels
|
| 484 |
|
| 485 | var Level = function(level, name) {
|
| 486 | this.level = level;
|
| 487 | this.name = name;
|
| 488 | };
|
| 489 |
|
| 490 | Level.prototype = {
|
| 491 | toString: function() {
|
| 492 | return this.name;
|
| 493 | },
|
| 494 | equals: function(level) {
|
| 495 | return this.level == level.level;
|
| 496 | },
|
| 497 | isGreaterOrEqual: function(level) {
|
| 498 | return this.level >= level.level;
|
| 499 | }
|
| 500 | };
|
| 501 |
|
| 502 | Level.ALL = new Level(Number.MIN_VALUE, "ALL");
|
| 503 | Level.TRACE = new Level(10000, "TRACE");
|
| 504 | Level.DEBUG = new Level(20000, "DEBUG");
|
| 505 | Level.INFO = new Level(30000, "INFO");
|
| 506 | Level.WARN = new Level(40000, "WARN");
|
| 507 | Level.ERROR = new Level(50000, "ERROR");
|
| 508 | Level.FATAL = new Level(60000, "FATAL");
|
| 509 | Level.OFF = new Level(Number.MAX_VALUE, "OFF");
|
| 510 |
|
| 511 | log4javascript.Level = Level;
|
| 512 |
|
| 513 | /* ---------------------------------------------------------------------- */
|
| 514 | // Timers
|
| 515 |
|
| 516 | function Timer(name, level) {
|
| 517 | this.name = name;
|
| 518 | this.level = isUndefined(level) ? Level.INFO : level;
|
| 519 | this.start = new Date();
|
| 520 | }
|
| 521 |
|
| 522 | Timer.prototype.getElapsedTime = function() {
|
| 523 | return new Date().getTime() - this.start.getTime();
|
| 524 | };
|
| 525 |
|
| 526 | /* ---------------------------------------------------------------------- */
|
| 527 | // Loggers
|
| 528 |
|
| 529 | var anonymousLoggerName = "[anonymous]";
|
| 530 | var defaultLoggerName = "[default]";
|
| 531 | var nullLoggerName = "[null]";
|
| 532 | var rootLoggerName = "root";
|
| 533 |
|
| 534 | function Logger(name) {
|
| 535 | this.name = name;
|
| 536 | this.parent = null;
|
| 537 | this.children = [];
|
| 538 |
|
| 539 | var appenders = [];
|
| 540 | var loggerLevel = null;
|
| 541 | var isRoot = (this.name === rootLoggerName);
|
| 542 | var isNull = (this.name === nullLoggerName);
|
| 543 |
|
| 544 | var appenderCache = null;
|
| 545 | var appenderCacheInvalidated = false;
|
| 546 |
|
| 547 | this.addChild = function(childLogger) {
|
| 548 | this.children.push(childLogger);
|
| 549 | childLogger.parent = this;
|
| 550 | childLogger.invalidateAppenderCache();
|
| 551 | };
|
| 552 |
|
| 553 | // Additivity
|
| 554 | var additive = true;
|
| 555 | this.getAdditivity = function() {
|
| 556 | return additive;
|
| 557 | };
|
| 558 |
|
| 559 | this.setAdditivity = function(additivity) {
|
| 560 | var valueChanged = (additive != additivity);
|
| 561 | additive = additivity;
|
| 562 | if (valueChanged) {
|
| 563 | this.invalidateAppenderCache();
|
| 564 | }
|
| 565 | };
|
| 566 |
|
| 567 | // Create methods that use the appenders variable in this scope
|
| 568 | this.addAppender = function(appender) {
|
| 569 | if (isNull) {
|
| 570 | handleError("Logger.addAppender: you may not add an appender to the null logger");
|
| 571 | } else {
|
| 572 | if (appender instanceof log4javascript.Appender) {
|
| 573 | if (!array_contains(appenders, appender)) {
|
| 574 | appenders.push(appender);
|
| 575 | appender.setAddedToLogger(this);
|
| 576 | this.invalidateAppenderCache();
|
| 577 | }
|
| 578 | } else {
|
| 579 | handleError("Logger.addAppender: appender supplied ('" +
|
| 580 | toStr(appender) + "') is not a subclass of Appender");
|
| 581 | }
|
| 582 | }
|
| 583 | };
|
| 584 |
|
| 585 | this.removeAppender = function(appender) {
|
| 586 | array_remove(appenders, appender);
|
| 587 | appender.setRemovedFromLogger(this);
|
| 588 | this.invalidateAppenderCache();
|
| 589 | };
|
| 590 |
|
| 591 | this.removeAllAppenders = function() {
|
| 592 | var appenderCount = appenders.length;
|
| 593 | if (appenderCount > 0) {
|
| 594 | for (var i = 0; i < appenderCount; i++) {
|
| 595 | appenders[i].setRemovedFromLogger(this);
|
| 596 | }
|
| 597 | appenders.length = 0;
|
| 598 | this.invalidateAppenderCache();
|
| 599 | }
|
| 600 | };
|
| 601 |
|
| 602 | this.getEffectiveAppenders = function() {
|
| 603 | if (appenderCache === null || appenderCacheInvalidated) {
|
| 604 | // Build appender cache
|
| 605 | var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?
|
| 606 | [] : this.parent.getEffectiveAppenders();
|
| 607 | appenderCache = parentEffectiveAppenders.concat(appenders);
|
| 608 | appenderCacheInvalidated = false;
|
| 609 | }
|
| 610 | return appenderCache;
|
| 611 | };
|
| 612 |
|
| 613 | this.invalidateAppenderCache = function() {
|
| 614 | appenderCacheInvalidated = true;
|
| 615 | for (var i = 0, len = this.children.length; i < len; i++) {
|
| 616 | this.children[i].invalidateAppenderCache();
|
| 617 | }
|
| 618 | };
|
| 619 |
|
| 620 | this.log = function(level, params) {
|
| 621 | if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {
|
| 622 | // Check whether last param is an exception
|
| 623 | var exception;
|
| 624 | var finalParamIndex = params.length - 1;
|
| 625 | var lastParam = params[finalParamIndex];
|
| 626 | if (params.length > 1 && isError(lastParam)) {
|
| 627 | exception = lastParam;
|
| 628 | finalParamIndex--;
|
| 629 | }
|
| 630 |
|
| 631 | // Construct genuine array for the params
|
| 632 | var messages = [];
|
| 633 | for (var i = 0; i <= finalParamIndex; i++) {
|
| 634 | messages[i] = params[i];
|
| 635 | }
|
| 636 |
|
| 637 | var loggingEvent = new LoggingEvent(
|
| 638 | this, new Date(), level, messages, exception);
|
| 639 |
|
| 640 | this.callAppenders(loggingEvent);
|
| 641 | }
|
| 642 | };
|
| 643 |
|
| 644 | this.callAppenders = function(loggingEvent) {
|
| 645 | var effectiveAppenders = this.getEffectiveAppenders();
|
| 646 | for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
|
| 647 | effectiveAppenders[i].doAppend(loggingEvent);
|
| 648 | }
|
| 649 | };
|
| 650 |
|
| 651 | this.setLevel = function(level) {
|
| 652 | // Having a level of null on the root logger would be very bad.
|
| 653 | if (isRoot && level === null) {
|
| 654 | handleError("Logger.setLevel: you cannot set the level of the root logger to null");
|
| 655 | } else if (level instanceof Level) {
|
| 656 | loggerLevel = level;
|
| 657 | } else {
|
| 658 | handleError("Logger.setLevel: level supplied to logger " +
|
| 659 | this.name + " is not an instance of log4javascript.Level");
|
| 660 | }
|
| 661 | };
|
| 662 |
|
| 663 | this.getLevel = function() {
|
| 664 | return loggerLevel;
|
| 665 | };
|
| 666 |
|
| 667 | this.getEffectiveLevel = function() {
|
| 668 | for (var logger = this; logger !== null; logger = logger.parent) {
|
| 669 | var level = logger.getLevel();
|
| 670 | if (level !== null) {
|
| 671 | return level;
|
| 672 | }
|
| 673 | }
|
| 674 | };
|
| 675 |
|
| 676 | this.group = function(name, initiallyExpanded) {
|
| 677 | if (enabled) {
|
| 678 | var effectiveAppenders = this.getEffectiveAppenders();
|
| 679 | for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
|
| 680 | effectiveAppenders[i].group(name, initiallyExpanded);
|
| 681 | }
|
| 682 | }
|
| 683 | };
|
| 684 |
|
| 685 | this.groupEnd = function() {
|
| 686 | if (enabled) {
|
| 687 | var effectiveAppenders = this.getEffectiveAppenders();
|
| 688 | for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
|
| 689 | effectiveAppenders[i].groupEnd();
|
| 690 | }
|
| 691 | }
|
| 692 | };
|
| 693 |
|
| 694 | var timers = {};
|
| 695 |
|
| 696 | this.time = function(name, level) {
|
| 697 | if (enabled) {
|
| 698 | if (isUndefined(name)) {
|
| 699 | handleError("Logger.time: a name for the timer must be supplied");
|
| 700 | } else if (level && !(level instanceof Level)) {
|
| 701 | handleError("Logger.time: level supplied to timer " +
|
| 702 | name + " is not an instance of log4javascript.Level");
|
| 703 | } else {
|
| 704 | timers[name] = new Timer(name, level);
|
| 705 | }
|
| 706 | }
|
| 707 | };
|
| 708 |
|
| 709 | this.timeEnd = function(name) {
|
| 710 | if (enabled) {
|
| 711 | if (isUndefined(name)) {
|
| 712 | handleError("Logger.timeEnd: a name for the timer must be supplied");
|
| 713 | } else if (timers[name]) {
|
| 714 | var timer = timers[name];
|
| 715 | var milliseconds = timer.getElapsedTime();
|
| 716 | this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);
|
| 717 | delete timers[name];
|
| 718 | } else {
|
| 719 | logLog.warn("Logger.timeEnd: no timer found with name " + name);
|
| 720 | }
|
| 721 | }
|
| 722 | };
|
| 723 |
|
| 724 | this.assert = function(expr) {
|
| 725 | if (enabled && !expr) {
|
| 726 | var args = [];
|
| 727 | for (var i = 1, len = arguments.length; i < len; i++) {
|
| 728 | args.push(arguments[i]);
|
| 729 | }
|
| 730 | args = (args.length > 0) ? args : ["Assertion Failure"];
|
| 731 | args.push(newLine);
|
| 732 | args.push(expr);
|
| 733 | this.log(Level.ERROR, args);
|
| 734 | }
|
| 735 | };
|
| 736 |
|
| 737 | this.toString = function() {
|
| 738 | return "Logger[" + this.name + "]";
|
| 739 | };
|
| 740 | }
|
| 741 |
|
| 742 | Logger.prototype = {
|
| 743 | trace: function() {
|
| 744 | this.log(Level.TRACE, arguments);
|
| 745 | },
|
| 746 |
|
| 747 | debug: function() {
|
| 748 | this.log(Level.DEBUG, arguments);
|
| 749 | },
|
| 750 |
|
| 751 | info: function() {
|
| 752 | this.log(Level.INFO, arguments);
|
| 753 | },
|
| 754 |
|
| 755 | warn: function() {
|
| 756 | this.log(Level.WARN, arguments);
|
| 757 | },
|
| 758 |
|
| 759 | error: function() {
|
| 760 | this.log(Level.ERROR, arguments);
|
| 761 | },
|
| 762 |
|
| 763 | fatal: function() {
|
| 764 | this.log(Level.FATAL, arguments);
|
| 765 | },
|
| 766 |
|
| 767 | isEnabledFor: function(level) {
|
| 768 | return level.isGreaterOrEqual(this.getEffectiveLevel());
|
| 769 | },
|
| 770 |
|
| 771 | isTraceEnabled: function() {
|
| 772 | return this.isEnabledFor(Level.TRACE);
|
| 773 | },
|
| 774 |
|
| 775 | isDebugEnabled: function() {
|
| 776 | return this.isEnabledFor(Level.DEBUG);
|
| 777 | },
|
| 778 |
|
| 779 | isInfoEnabled: function() {
|
| 780 | return this.isEnabledFor(Level.INFO);
|
| 781 | },
|
| 782 |
|
| 783 | isWarnEnabled: function() {
|
| 784 | return this.isEnabledFor(Level.WARN);
|
| 785 | },
|
| 786 |
|
| 787 | isErrorEnabled: function() {
|
| 788 | return this.isEnabledFor(Level.ERROR);
|
| 789 | },
|
| 790 |
|
| 791 | isFatalEnabled: function() {
|
| 792 | return this.isEnabledFor(Level.FATAL);
|
| 793 | }
|
| 794 | };
|
| 795 |
|
| 796 | Logger.prototype.trace.isEntryPoint = true;
|
| 797 | Logger.prototype.debug.isEntryPoint = true;
|
| 798 | Logger.prototype.info.isEntryPoint = true;
|
| 799 | Logger.prototype.warn.isEntryPoint = true;
|
| 800 | Logger.prototype.error.isEntryPoint = true;
|
| 801 | Logger.prototype.fatal.isEntryPoint = true;
|
| 802 |
|
| 803 | /* ---------------------------------------------------------------------- */
|
| 804 | // Logger access methods
|
| 805 |
|
| 806 | // Hashtable of loggers keyed by logger name
|
| 807 | var loggers = {};
|
| 808 | var loggerNames = [];
|
| 809 |
|
| 810 | var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;
|
| 811 | var rootLogger = new Logger(rootLoggerName);
|
| 812 | rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);
|
| 813 |
|
| 814 | log4javascript.getRootLogger = function() {
|
| 815 | return rootLogger;
|
| 816 | };
|
| 817 |
|
| 818 | log4javascript.getLogger = function(loggerName) {
|
| 819 | // Use default logger if loggerName is not specified or invalid
|
| 820 | if (!(typeof loggerName == "string")) {
|
| 821 | loggerName = anonymousLoggerName;
|
| 822 | logLog.warn("log4javascript.getLogger: non-string logger name " +
|
| 823 | toStr(loggerName) + " supplied, returning anonymous logger");
|
| 824 | }
|
| 825 |
|
| 826 | // Do not allow retrieval of the root logger by name
|
| 827 | if (loggerName == rootLoggerName) {
|
| 828 | handleError("log4javascript.getLogger: root logger may not be obtained by name");
|
| 829 | }
|
| 830 |
|
| 831 | // Create the logger for this name if it doesn't already exist
|
| 832 | if (!loggers[loggerName]) {
|
| 833 | var logger = new Logger(loggerName);
|
| 834 | loggers[loggerName] = logger;
|
| 835 | loggerNames.push(loggerName);
|
| 836 |
|
| 837 | // Set up parent logger, if it doesn't exist
|
| 838 | var lastDotIndex = loggerName.lastIndexOf(".");
|
| 839 | var parentLogger;
|
| 840 | if (lastDotIndex > -1) {
|
| 841 | var parentLoggerName = loggerName.substring(0, lastDotIndex);
|
| 842 | parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.
|
| 843 | } else {
|
| 844 | parentLogger = rootLogger;
|
| 845 | }
|
| 846 | parentLogger.addChild(logger);
|
| 847 | }
|
| 848 | return loggers[loggerName];
|
| 849 | };
|
| 850 |
|
| 851 | var defaultLogger = null;
|
| 852 | log4javascript.getDefaultLogger = function() {
|
| 853 | if (!defaultLogger) {
|
| 854 | defaultLogger = log4javascript.getLogger(defaultLoggerName);
|
| 855 | var a = new log4javascript.PopUpAppender();
|
| 856 | defaultLogger.addAppender(a);
|
| 857 | }
|
| 858 | return defaultLogger;
|
| 859 | };
|
| 860 |
|
| 861 | var nullLogger = null;
|
| 862 | log4javascript.getNullLogger = function() {
|
| 863 | if (!nullLogger) {
|
| 864 | nullLogger = new Logger(nullLoggerName);
|
| 865 | nullLogger.setLevel(Level.OFF);
|
| 866 | }
|
| 867 | return nullLogger;
|
| 868 | };
|
| 869 |
|
| 870 | // Destroys all loggers
|
| 871 | log4javascript.resetConfiguration = function() {
|
| 872 | rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);
|
| 873 | loggers = {};
|
| 874 | };
|
| 875 |
|
| 876 | /* ---------------------------------------------------------------------- */
|
| 877 | // Logging events
|
| 878 |
|
| 879 | var LoggingEvent = function(logger, timeStamp, level, messages,
|
| 880 | exception) {
|
| 881 | this.logger = logger;
|
| 882 | this.timeStamp = timeStamp;
|
| 883 | this.timeStampInMilliseconds = timeStamp.getTime();
|
| 884 | this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);
|
| 885 | this.milliseconds = this.timeStamp.getMilliseconds();
|
| 886 | this.level = level;
|
| 887 | this.messages = messages;
|
| 888 | this.exception = exception;
|
| 889 | };
|
| 890 |
|
| 891 | LoggingEvent.prototype = {
|
| 892 | getThrowableStrRep: function() {
|
| 893 | return this.exception ?
|
| 894 | getExceptionStringRep(this.exception) : "";
|
| 895 | },
|
| 896 | getCombinedMessages: function() {
|
| 897 | return (this.messages.length == 1) ? this.messages[0] :
|
| 898 | this.messages.join(newLine);
|
| 899 | },
|
| 900 | toString: function() {
|
| 901 | return "LoggingEvent[" + this.level + "]";
|
| 902 | }
|
| 903 | };
|
| 904 |
|
| 905 | log4javascript.LoggingEvent = LoggingEvent;
|
| 906 |
|
| 907 | /* ---------------------------------------------------------------------- */
|
| 908 | // Layout prototype
|
| 909 |
|
| 910 | var Layout = function() {
|
| 911 | };
|
| 912 |
|
| 913 | Layout.prototype = {
|
| 914 | defaults: {
|
| 915 | loggerKey: "logger",
|
| 916 | timeStampKey: "timestamp",
|
| 917 | millisecondsKey: "milliseconds",
|
| 918 | levelKey: "level",
|
| 919 | messageKey: "message",
|
| 920 | exceptionKey: "exception",
|
| 921 | urlKey: "url"
|
| 922 | },
|
| 923 | loggerKey: "logger",
|
| 924 | timeStampKey: "timestamp",
|
| 925 | millisecondsKey: "milliseconds",
|
| 926 | levelKey: "level",
|
| 927 | messageKey: "message",
|
| 928 | exceptionKey: "exception",
|
| 929 | urlKey: "url",
|
| 930 | batchHeader: "",
|
| 931 | batchFooter: "",
|
| 932 | batchSeparator: "",
|
| 933 | returnsPostData: false,
|
| 934 | overrideTimeStampsSetting: false,
|
| 935 | useTimeStampsInMilliseconds: null,
|
| 936 |
|
| 937 | format: function() {
|
| 938 | handleError("Layout.format: layout supplied has no format() method");
|
| 939 | },
|
| 940 |
|
| 941 | ignoresThrowable: function() {
|
| 942 | handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");
|
| 943 | },
|
| 944 |
|
| 945 | getContentType: function() {
|
| 946 | return "text/plain";
|
| 947 | },
|
| 948 |
|
| 949 | allowBatching: function() {
|
| 950 | return true;
|
| 951 | },
|
| 952 |
|
| 953 | setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {
|
| 954 | this.overrideTimeStampsSetting = true;
|
| 955 | this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);
|
| 956 | },
|
| 957 |
|
| 958 | isTimeStampsInMilliseconds: function() {
|
| 959 | return this.overrideTimeStampsSetting ?
|
| 960 | this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;
|
| 961 | },
|
| 962 |
|
| 963 | getTimeStampValue: function(loggingEvent) {
|
| 964 | return this.isTimeStampsInMilliseconds() ?
|
| 965 | loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;
|
| 966 | },
|
| 967 |
|
| 968 | getDataValues: function(loggingEvent, combineMessages) {
|
| 969 | var dataValues = [
|
| 970 | [this.loggerKey, loggingEvent.logger.name],
|
| 971 | [this.timeStampKey, this.getTimeStampValue(loggingEvent)],
|
| 972 | [this.levelKey, loggingEvent.level.name],
|
| 973 | [this.urlKey, window.location.href],
|
| 974 | [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]
|
| 975 | ];
|
| 976 | if (!this.isTimeStampsInMilliseconds()) {
|
| 977 | dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);
|
| 978 | }
|
| 979 | if (loggingEvent.exception) {
|
| 980 | dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);
|
| 981 | }
|
| 982 | if (this.hasCustomFields()) {
|
| 983 | for (var i = 0, len = this.customFields.length; i < len; i++) {
|
| 984 | var val = this.customFields[i].value;
|
| 985 |
|
| 986 | // Check if the value is a function. If so, execute it, passing it the
|
| 987 | // current layout and the logging event
|
| 988 | if (typeof val === "function") {
|
| 989 | val = val(this, loggingEvent);
|
| 990 | }
|
| 991 | dataValues.push([this.customFields[i].name, val]);
|
| 992 | }
|
| 993 | }
|
| 994 | return dataValues;
|
| 995 | },
|
| 996 |
|
| 997 | setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,
|
| 998 | exceptionKey, urlKey, millisecondsKey) {
|
| 999 | this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);
|
| 1000 | this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);
|
| 1001 | this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);
|
| 1002 | this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);
|
| 1003 | this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);
|
| 1004 | this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);
|
| 1005 | this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);
|
| 1006 | },
|
| 1007 |
|
| 1008 | setCustomField: function(name, value) {
|
| 1009 | var fieldUpdated = false;
|
| 1010 | for (var i = 0, len = this.customFields.length; i < len; i++) {
|
| 1011 | if (this.customFields[i].name === name) {
|
| 1012 | this.customFields[i].value = value;
|
| 1013 | fieldUpdated = true;
|
| 1014 | }
|
| 1015 | }
|
| 1016 | if (!fieldUpdated) {
|
| 1017 | this.customFields.push({"name": name, "value": value});
|
| 1018 | }
|
| 1019 | },
|
| 1020 |
|
| 1021 | hasCustomFields: function() {
|
| 1022 | return (this.customFields.length > 0);
|
| 1023 | },
|
| 1024 |
|
| 1025 | toString: function() {
|
| 1026 | handleError("Layout.toString: all layouts must override this method");
|
| 1027 | }
|
| 1028 | };
|
| 1029 |
|
| 1030 | log4javascript.Layout = Layout;
|
| 1031 |
|
| 1032 | /* ---------------------------------------------------------------------- */
|
| 1033 | // Appender prototype
|
| 1034 |
|
| 1035 | var Appender = function() {};
|
| 1036 |
|
| 1037 | Appender.prototype = new EventSupport();
|
| 1038 |
|
| 1039 | Appender.prototype.layout = new PatternLayout();
|
| 1040 | Appender.prototype.threshold = Level.ALL;
|
| 1041 | Appender.prototype.loggers = [];
|
| 1042 |
|
| 1043 | // Performs threshold checks before delegating actual logging to the
|
| 1044 | // subclass's specific append method.
|
| 1045 | Appender.prototype.doAppend = function(loggingEvent) {
|
| 1046 | if (enabled && loggingEvent.level.level >= this.threshold.level) {
|
| 1047 | this.append(loggingEvent);
|
| 1048 | }
|
| 1049 | };
|
| 1050 |
|
| 1051 | Appender.prototype.append = function(loggingEvent) {};
|
| 1052 |
|
| 1053 | Appender.prototype.setLayout = function(layout) {
|
| 1054 | if (layout instanceof Layout) {
|
| 1055 | this.layout = layout;
|
| 1056 | } else {
|
| 1057 | handleError("Appender.setLayout: layout supplied to " +
|
| 1058 | this.toString() + " is not a subclass of Layout");
|
| 1059 | }
|
| 1060 | };
|
| 1061 |
|
| 1062 | Appender.prototype.getLayout = function() {
|
| 1063 | return this.layout;
|
| 1064 | };
|
| 1065 |
|
| 1066 | Appender.prototype.setThreshold = function(threshold) {
|
| 1067 | if (threshold instanceof Level) {
|
| 1068 | this.threshold = threshold;
|
| 1069 | } else {
|
| 1070 | handleError("Appender.setThreshold: threshold supplied to " +
|
| 1071 | this.toString() + " is not a subclass of Level");
|
| 1072 | }
|
| 1073 | };
|
| 1074 |
|
| 1075 | Appender.prototype.getThreshold = function() {
|
| 1076 | return this.threshold;
|
| 1077 | };
|
| 1078 |
|
| 1079 | Appender.prototype.setAddedToLogger = function(logger) {
|
| 1080 | this.loggers.push(logger);
|
| 1081 | };
|
| 1082 |
|
| 1083 | Appender.prototype.setRemovedFromLogger = function(logger) {
|
| 1084 | array_remove(this.loggers, logger);
|
| 1085 | };
|
| 1086 |
|
| 1087 | Appender.prototype.group = emptyFunction;
|
| 1088 | Appender.prototype.groupEnd = emptyFunction;
|
| 1089 |
|
| 1090 | Appender.prototype.toString = function() {
|
| 1091 | handleError("Appender.toString: all appenders must override this method");
|
| 1092 | };
|
| 1093 |
|
| 1094 | log4javascript.Appender = Appender;
|
| 1095 |
|
| 1096 | /* ---------------------------------------------------------------------- */
|
| 1097 | // SimpleLayout
|
| 1098 |
|
| 1099 | function SimpleLayout() {
|
| 1100 | this.customFields = [];
|
| 1101 | }
|
| 1102 |
|
| 1103 | SimpleLayout.prototype = new Layout();
|
| 1104 |
|
| 1105 | SimpleLayout.prototype.format = function(loggingEvent) {
|
| 1106 | return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();
|
| 1107 | };
|
| 1108 |
|
| 1109 | SimpleLayout.prototype.ignoresThrowable = function() {
|
| 1110 | return true;
|
| 1111 | };
|
| 1112 |
|
| 1113 | SimpleLayout.prototype.toString = function() {
|
| 1114 | return "SimpleLayout";
|
| 1115 | };
|
| 1116 |
|
| 1117 | log4javascript.SimpleLayout = SimpleLayout;
|
| 1118 | /* ----------------------------------------------------------------------- */
|
| 1119 | // NullLayout
|
| 1120 |
|
| 1121 | function NullLayout() {
|
| 1122 | this.customFields = [];
|
| 1123 | }
|
| 1124 |
|
| 1125 | NullLayout.prototype = new Layout();
|
| 1126 |
|
| 1127 | NullLayout.prototype.format = function(loggingEvent) {
|
| 1128 | return loggingEvent.messages;
|
| 1129 | };
|
| 1130 |
|
| 1131 | NullLayout.prototype.ignoresThrowable = function() {
|
| 1132 | return true;
|
| 1133 | };
|
| 1134 |
|
| 1135 | NullLayout.prototype.toString = function() {
|
| 1136 | return "NullLayout";
|
| 1137 | };
|
| 1138 |
|
| 1139 | log4javascript.NullLayout = NullLayout;
|
| 1140 | /* ---------------------------------------------------------------------- */
|
| 1141 | // XmlLayout
|
| 1142 |
|
| 1143 | function XmlLayout(combineMessages) {
|
| 1144 | this.combineMessages = extractBooleanFromParam(combineMessages, true);
|
| 1145 | this.customFields = [];
|
| 1146 | }
|
| 1147 |
|
| 1148 | XmlLayout.prototype = new Layout();
|
| 1149 |
|
| 1150 | XmlLayout.prototype.isCombinedMessages = function() {
|
| 1151 | return this.combineMessages;
|
| 1152 | };
|
| 1153 |
|
| 1154 | XmlLayout.prototype.getContentType = function() {
|
| 1155 | return "text/xml";
|
| 1156 | };
|
| 1157 |
|
| 1158 | XmlLayout.prototype.escapeCdata = function(str) {
|
| 1159 | return str.replace(/\]\]>/, "]]>]]><![CDATA[");
|
| 1160 | };
|
| 1161 |
|
| 1162 | XmlLayout.prototype.format = function(loggingEvent) {
|
| 1163 | var layout = this;
|
| 1164 | var i, len;
|
| 1165 | function formatMessage(message) {
|
| 1166 | message = (typeof message === "string") ? message : toStr(message);
|
| 1167 | return "<log4javascript:message><![CDATA[" +
|
| 1168 | layout.escapeCdata(message) + "]]></log4javascript:message>";
|
| 1169 | }
|
| 1170 |
|
| 1171 | var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +
|
| 1172 | "\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";
|
| 1173 | if (!this.isTimeStampsInMilliseconds()) {
|
| 1174 | str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";
|
| 1175 | }
|
| 1176 | str += " level=\"" + loggingEvent.level.name + "\">" + newLine;
|
| 1177 | if (this.combineMessages) {
|
| 1178 | str += formatMessage(loggingEvent.getCombinedMessages());
|
| 1179 | } else {
|
| 1180 | str += "<log4javascript:messages>" + newLine;
|
| 1181 | for (i = 0, len = loggingEvent.messages.length; i < len; i++) {
|
| 1182 | str += formatMessage(loggingEvent.messages[i]) + newLine;
|
| 1183 | }
|
| 1184 | str += "</log4javascript:messages>" + newLine;
|
| 1185 | }
|
| 1186 | if (this.hasCustomFields()) {
|
| 1187 | for (i = 0, len = this.customFields.length; i < len; i++) {
|
| 1188 | str += "<log4javascript:customfield name=\"" +
|
| 1189 | this.customFields[i].name + "\"><![CDATA[" +
|
| 1190 | this.customFields[i].value.toString() +
|
| 1191 | "]]></log4javascript:customfield>" + newLine;
|
| 1192 | }
|
| 1193 | }
|
| 1194 | if (loggingEvent.exception) {
|
| 1195 | str += "<log4javascript:exception><![CDATA[" +
|
| 1196 | getExceptionStringRep(loggingEvent.exception) +
|
| 1197 | "]]></log4javascript:exception>" + newLine;
|
| 1198 | }
|
| 1199 | str += "</log4javascript:event>" + newLine + newLine;
|
| 1200 | return str;
|
| 1201 | };
|
| 1202 |
|
| 1203 | XmlLayout.prototype.ignoresThrowable = function() {
|
| 1204 | return false;
|
| 1205 | };
|
| 1206 |
|
| 1207 | XmlLayout.prototype.toString = function() {
|
| 1208 | return "XmlLayout";
|
| 1209 | };
|
| 1210 |
|
| 1211 | log4javascript.XmlLayout = XmlLayout;
|
| 1212 | /* ---------------------------------------------------------------------- */
|
| 1213 | // JsonLayout related
|
| 1214 |
|
| 1215 | function escapeNewLines(str) {
|
| 1216 | return str.replace(/\r\n|\r|\n/g, "\\r\\n");
|
| 1217 | }
|
| 1218 |
|
| 1219 | function JsonLayout(readable, combineMessages) {
|
| 1220 | this.readable = extractBooleanFromParam(readable, false);
|
| 1221 | this.combineMessages = extractBooleanFromParam(combineMessages, true);
|
| 1222 | this.batchHeader = this.readable ? "[" + newLine : "[";
|
| 1223 | this.batchFooter = this.readable ? "]" + newLine : "]";
|
| 1224 | this.batchSeparator = this.readable ? "," + newLine : ",";
|
| 1225 | this.setKeys();
|
| 1226 | this.colon = this.readable ? ": " : ":";
|
| 1227 | this.tab = this.readable ? "\t" : "";
|
| 1228 | this.lineBreak = this.readable ? newLine : "";
|
| 1229 | this.customFields = [];
|
| 1230 | }
|
| 1231 |
|
| 1232 | /* ---------------------------------------------------------------------- */
|
| 1233 | // JsonLayout
|
| 1234 |
|
| 1235 | JsonLayout.prototype = new Layout();
|
| 1236 |
|
| 1237 | JsonLayout.prototype.isReadable = function() {
|
| 1238 | return this.readable;
|
| 1239 | };
|
| 1240 |
|
| 1241 | JsonLayout.prototype.isCombinedMessages = function() {
|
| 1242 | return this.combineMessages;
|
| 1243 | };
|
| 1244 |
|
| 1245 | JsonLayout.prototype.format = function(loggingEvent) {
|
| 1246 | var layout = this;
|
| 1247 | var dataValues = this.getDataValues(loggingEvent, this.combineMessages);
|
| 1248 | var str = "{" + this.lineBreak;
|
| 1249 | var i, len;
|
| 1250 |
|
| 1251 | function formatValue(val, prefix, expand) {
|
| 1252 | // Check the type of the data value to decide whether quotation marks
|
| 1253 | // or expansion are required
|
| 1254 | var formattedValue;
|
| 1255 | var valType = typeof val;
|
| 1256 | if (val instanceof Date) {
|
| 1257 | formattedValue = String(val.getTime());
|
| 1258 | } else if (expand && (val instanceof Array)) {
|
| 1259 | formattedValue = "[" + layout.lineBreak;
|
| 1260 | for (var i = 0, len = val.length; i < len; i++) {
|
| 1261 | var childPrefix = prefix + layout.tab;
|
| 1262 | formattedValue += childPrefix + formatValue(val[i], childPrefix, false);
|
| 1263 | if (i < val.length - 1) {
|
| 1264 | formattedValue += ",";
|
| 1265 | }
|
| 1266 | formattedValue += layout.lineBreak;
|
| 1267 | }
|
| 1268 | formattedValue += prefix + "]";
|
| 1269 | } else if (valType !== "number" && valType !== "boolean") {
|
| 1270 | formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";
|
| 1271 | } else {
|
| 1272 | formattedValue = val;
|
| 1273 | }
|
| 1274 | return formattedValue;
|
| 1275 | }
|
| 1276 |
|
| 1277 | for (i = 0, len = dataValues.length - 1; i <= len; i++) {
|
| 1278 | str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);
|
| 1279 | if (i < len) {
|
| 1280 | str += ",";
|
| 1281 | }
|
| 1282 | str += this.lineBreak;
|
| 1283 | }
|
| 1284 |
|
| 1285 | str += "}" + this.lineBreak;
|
| 1286 | return str;
|
| 1287 | };
|
| 1288 |
|
| 1289 | JsonLayout.prototype.ignoresThrowable = function() {
|
| 1290 | return false;
|
| 1291 | };
|
| 1292 |
|
| 1293 | JsonLayout.prototype.toString = function() {
|
| 1294 | return "JsonLayout";
|
| 1295 | };
|
| 1296 |
|
| 1297 | JsonLayout.prototype.getContentType = function() {
|
| 1298 | return "application/json";
|
| 1299 | };
|
| 1300 |
|
| 1301 | log4javascript.JsonLayout = JsonLayout;
|
| 1302 | /* ---------------------------------------------------------------------- */
|
| 1303 | // HttpPostDataLayout
|
| 1304 |
|
| 1305 | function HttpPostDataLayout() {
|
| 1306 | this.setKeys();
|
| 1307 | this.customFields = [];
|
| 1308 | this.returnsPostData = true;
|
| 1309 | }
|
| 1310 |
|
| 1311 | HttpPostDataLayout.prototype = new Layout();
|
| 1312 |
|
| 1313 | // Disable batching
|
| 1314 | HttpPostDataLayout.prototype.allowBatching = function() {
|
| 1315 | return false;
|
| 1316 | };
|
| 1317 |
|
| 1318 | HttpPostDataLayout.prototype.format = function(loggingEvent) {
|
| 1319 | var dataValues = this.getDataValues(loggingEvent);
|
| 1320 | var queryBits = [];
|
| 1321 | for (var i = 0, len = dataValues.length; i < len; i++) {
|
| 1322 | var val = (dataValues[i][1] instanceof Date) ?
|
| 1323 | String(dataValues[i][1].getTime()) : dataValues[i][1];
|
| 1324 | queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));
|
| 1325 | }
|
| 1326 | return queryBits.join("&");
|
| 1327 | };
|
| 1328 |
|
| 1329 | HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {
|
| 1330 | return false;
|
| 1331 | };
|
| 1332 |
|
| 1333 | HttpPostDataLayout.prototype.toString = function() {
|
| 1334 | return "HttpPostDataLayout";
|
| 1335 | };
|
| 1336 |
|
| 1337 | log4javascript.HttpPostDataLayout = HttpPostDataLayout;
|
| 1338 | /* ---------------------------------------------------------------------- */
|
| 1339 | // formatObjectExpansion
|
| 1340 |
|
| 1341 | function formatObjectExpansion(obj, depth, indentation) {
|
| 1342 | var objectsExpanded = [];
|
| 1343 |
|
| 1344 | function doFormat(obj, depth, indentation) {
|
| 1345 | var i, j, len, childDepth, childIndentation, childLines, expansion,
|
| 1346 | childExpansion;
|
| 1347 |
|
| 1348 | if (!indentation) {
|
| 1349 | indentation = "";
|
| 1350 | }
|
| 1351 |
|
| 1352 | function formatString(text) {
|
| 1353 | var lines = splitIntoLines(text);
|
| 1354 | for (var j = 1, jLen = lines.length; j < jLen; j++) {
|
| 1355 | lines[j] = indentation + lines[j];
|
| 1356 | }
|
| 1357 | return lines.join(newLine);
|
| 1358 | }
|
| 1359 |
|
| 1360 | if (obj === null) {
|
| 1361 | return "null";
|
| 1362 | } else if (typeof obj == "undefined") {
|
| 1363 | return "undefined";
|
| 1364 | } else if (typeof obj == "string") {
|
| 1365 | return formatString(obj);
|
| 1366 | } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {
|
| 1367 | try {
|
| 1368 | expansion = toStr(obj);
|
| 1369 | } catch (ex) {
|
| 1370 | expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);
|
| 1371 | }
|
| 1372 | return expansion + " [already expanded]";
|
| 1373 | } else if ((obj instanceof Array) && depth > 0) {
|
| 1374 | objectsExpanded.push(obj);
|
| 1375 | expansion = "[" + newLine;
|
| 1376 | childDepth = depth - 1;
|
| 1377 | childIndentation = indentation + " ";
|
| 1378 | childLines = [];
|
| 1379 | for (i = 0, len = obj.length; i < len; i++) {
|
| 1380 | try {
|
| 1381 | childExpansion = doFormat(obj[i], childDepth, childIndentation);
|
| 1382 | childLines.push(childIndentation + childExpansion);
|
| 1383 | } catch (ex) {
|
| 1384 | childLines.push(childIndentation + "Error formatting array member. Details: " +
|
| 1385 | getExceptionStringRep(ex) + "");
|
| 1386 | }
|
| 1387 | }
|
| 1388 | expansion += childLines.join("," + newLine) + newLine + indentation + "]";
|
| 1389 | return expansion;
|
| 1390 | } else if (Object.prototype.toString.call(obj) == "[object Date]") {
|
| 1391 | return obj.toString();
|
| 1392 | } else if (typeof obj == "object" && depth > 0) {
|
| 1393 | objectsExpanded.push(obj);
|
| 1394 | expansion = "{" + newLine;
|
| 1395 | childDepth = depth - 1;
|
| 1396 | childIndentation = indentation + " ";
|
| 1397 | childLines = [];
|
| 1398 | for (i in obj) {
|
| 1399 | try {
|
| 1400 | childExpansion = doFormat(obj[i], childDepth, childIndentation);
|
| 1401 | childLines.push(childIndentation + i + ": " + childExpansion);
|
| 1402 | } catch (ex) {
|
| 1403 | childLines.push(childIndentation + i + ": Error formatting property. Details: " +
|
| 1404 | getExceptionStringRep(ex));
|
| 1405 | }
|
| 1406 | }
|
| 1407 | expansion += childLines.join("," + newLine) + newLine + indentation + "}";
|
| 1408 | return expansion;
|
| 1409 | } else {
|
| 1410 | return formatString(toStr(obj));
|
| 1411 | }
|
| 1412 | }
|
| 1413 | return doFormat(obj, depth, indentation);
|
| 1414 | }
|
| 1415 | /* ---------------------------------------------------------------------- */
|
| 1416 | // Date-related stuff
|
| 1417 |
|
| 1418 | var SimpleDateFormat;
|
| 1419 |
|
| 1420 | (function() {
|
| 1421 | var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;
|
| 1422 | var monthNames = ["January", "February", "March", "April", "May", "June",
|
| 1423 | "July", "August", "September", "October", "November", "December"];
|
| 1424 | var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
| 1425 | var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;
|
| 1426 | var types = {
|
| 1427 | G : TEXT2,
|
| 1428 | y : YEAR,
|
| 1429 | M : MONTH,
|
| 1430 | w : NUMBER,
|
| 1431 | W : NUMBER,
|
| 1432 | D : NUMBER,
|
| 1433 | d : NUMBER,
|
| 1434 | F : NUMBER,
|
| 1435 | E : TEXT3,
|
| 1436 | a : TEXT2,
|
| 1437 | H : NUMBER,
|
| 1438 | k : NUMBER,
|
| 1439 | K : NUMBER,
|
| 1440 | h : NUMBER,
|
| 1441 | m : NUMBER,
|
| 1442 | s : NUMBER,
|
| 1443 | S : NUMBER,
|
| 1444 | Z : TIMEZONE
|
| 1445 | };
|
| 1446 | var ONE_DAY = 24 * 60 * 60 * 1000;
|
| 1447 | var ONE_WEEK = 7 * ONE_DAY;
|
| 1448 | var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;
|
| 1449 |
|
| 1450 | var newDateAtMidnight = function(year, month, day) {
|
| 1451 | var d = new Date(year, month, day, 0, 0, 0);
|
| 1452 | d.setMilliseconds(0);
|
| 1453 | return d;
|
| 1454 | };
|
| 1455 |
|
| 1456 | Date.prototype.getDifference = function(date) {
|
| 1457 | return this.getTime() - date.getTime();
|
| 1458 | };
|
| 1459 |
|
| 1460 | Date.prototype.isBefore = function(d) {
|
| 1461 | return this.getTime() < d.getTime();
|
| 1462 | };
|
| 1463 |
|
| 1464 | Date.prototype.getUTCTime = function() {
|
| 1465 | return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),
|
| 1466 | this.getSeconds(), this.getMilliseconds());
|
| 1467 | };
|
| 1468 |
|
| 1469 | Date.prototype.getTimeSince = function(d) {
|
| 1470 | return this.getUTCTime() - d.getUTCTime();
|
| 1471 | };
|
| 1472 |
|
| 1473 | Date.prototype.getPreviousSunday = function() {
|
| 1474 | // Using midday avoids any possibility of DST messing things up
|
| 1475 | var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);
|
| 1476 | var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);
|
| 1477 | return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),
|
| 1478 | previousSunday.getDate());
|
| 1479 | };
|
| 1480 |
|
| 1481 | Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {
|
| 1482 | if (isUndefined(this.minimalDaysInFirstWeek)) {
|
| 1483 | minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;
|
| 1484 | }
|
| 1485 | var previousSunday = this.getPreviousSunday();
|
| 1486 | var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);
|
| 1487 | var numberOfSundays = previousSunday.isBefore(startOfYear) ?
|
| 1488 | 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);
|
| 1489 | var numberOfDaysInFirstWeek = 7 - startOfYear.getDay();
|
| 1490 | var weekInYear = numberOfSundays;
|
| 1491 | if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {
|
| 1492 | weekInYear--;
|
| 1493 | }
|
| 1494 | return weekInYear;
|
| 1495 | };
|
| 1496 |
|
| 1497 | Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {
|
| 1498 | if (isUndefined(this.minimalDaysInFirstWeek)) {
|
| 1499 | minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;
|
| 1500 | }
|
| 1501 | var previousSunday = this.getPreviousSunday();
|
| 1502 | var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);
|
| 1503 | var numberOfSundays = previousSunday.isBefore(startOfMonth) ?
|
| 1504 | 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);
|
| 1505 | var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay();
|
| 1506 | var weekInMonth = numberOfSundays;
|
| 1507 | if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {
|
| 1508 | weekInMonth++;
|
| 1509 | }
|
| 1510 | return weekInMonth;
|
| 1511 | };
|
| 1512 |
|
| 1513 | Date.prototype.getDayInYear = function() {
|
| 1514 | var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);
|
| 1515 | return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);
|
| 1516 | };
|
| 1517 |
|
| 1518 | /* ------------------------------------------------------------------ */
|
| 1519 |
|
| 1520 | SimpleDateFormat = function(formatString) {
|
| 1521 | this.formatString = formatString;
|
| 1522 | };
|
| 1523 |
|
| 1524 | /**
|
| 1525 | * Sets the minimum number of days in a week in order for that week to
|
| 1526 | * be considered as belonging to a particular month or year
|
| 1527 | */
|
| 1528 | SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {
|
| 1529 | this.minimalDaysInFirstWeek = days;
|
| 1530 | };
|
| 1531 |
|
| 1532 | SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {
|
| 1533 | return isUndefined(this.minimalDaysInFirstWeek) ?
|
| 1534 | DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;
|
| 1535 | };
|
| 1536 |
|
| 1537 | var padWithZeroes = function(str, len) {
|
| 1538 | while (str.length < len) {
|
| 1539 | str = "0" + str;
|
| 1540 | }
|
| 1541 | return str;
|
| 1542 | };
|
| 1543 |
|
| 1544 | var formatText = function(data, numberOfLetters, minLength) {
|
| 1545 | return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));
|
| 1546 | };
|
| 1547 |
|
| 1548 | var formatNumber = function(data, numberOfLetters) {
|
| 1549 | var dataString = "" + data;
|
| 1550 | // Pad with 0s as necessary
|
| 1551 | return padWithZeroes(dataString, numberOfLetters);
|
| 1552 | };
|
| 1553 |
|
| 1554 | SimpleDateFormat.prototype.format = function(date) {
|
| 1555 | var formattedString = "";
|
| 1556 | var result;
|
| 1557 | var searchString = this.formatString;
|
| 1558 | while ((result = regex.exec(searchString))) {
|
| 1559 | var quotedString = result[1];
|
| 1560 | var patternLetters = result[2];
|
| 1561 | var otherLetters = result[3];
|
| 1562 | var otherCharacters = result[4];
|
| 1563 |
|
| 1564 | // If the pattern matched is quoted string, output the text between the quotes
|
| 1565 | if (quotedString) {
|
| 1566 | if (quotedString == "''") {
|
| 1567 | formattedString += "'";
|
| 1568 | } else {
|
| 1569 | formattedString += quotedString.substring(1, quotedString.length - 1);
|
| 1570 | }
|
| 1571 | } else if (otherLetters) {
|
| 1572 | // Swallow non-pattern letters by doing nothing here
|
| 1573 | } else if (otherCharacters) {
|
| 1574 | // Simply output other characters
|
| 1575 | formattedString += otherCharacters;
|
| 1576 | } else if (patternLetters) {
|
| 1577 | // Replace pattern letters
|
| 1578 | var patternLetter = patternLetters.charAt(0);
|
| 1579 | var numberOfLetters = patternLetters.length;
|
| 1580 | var rawData = "";
|
| 1581 | switch(patternLetter) {
|
| 1582 | case "G":
|
| 1583 | rawData = "AD";
|
| 1584 | break;
|
| 1585 | case "y":
|
| 1586 | rawData = date.getFullYear();
|
| 1587 | break;
|
| 1588 | case "M":
|
| 1589 | rawData = date.getMonth();
|
| 1590 | break;
|
| 1591 | case "w":
|
| 1592 | rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());
|
| 1593 | break;
|
| 1594 | case "W":
|
| 1595 | rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());
|
| 1596 | break;
|
| 1597 | case "D":
|
| 1598 | rawData = date.getDayInYear();
|
| 1599 | break;
|
| 1600 | case "d":
|
| 1601 | rawData = date.getDate();
|
| 1602 | break;
|
| 1603 | case "F":
|
| 1604 | rawData = 1 + Math.floor((date.getDate() - 1) / 7);
|
| 1605 | break;
|
| 1606 | case "E":
|
| 1607 | rawData = dayNames[date.getDay()];
|
| 1608 | break;
|
| 1609 | case "a":
|
| 1610 | rawData = (date.getHours() >= 12) ? "PM" : "AM";
|
| 1611 | break;
|
| 1612 | case "H":
|
| 1613 | rawData = date.getHours();
|
| 1614 | break;
|
| 1615 | case "k":
|
| 1616 | rawData = date.getHours() || 24;
|
| 1617 | break;
|
| 1618 | case "K":
|
| 1619 | rawData = date.getHours() % 12;
|
| 1620 | break;
|
| 1621 | case "h":
|
| 1622 | rawData = (date.getHours() % 12) || 12;
|
| 1623 | break;
|
| 1624 | case "m":
|
| 1625 | rawData = date.getMinutes();
|
| 1626 | break;
|
| 1627 | case "s":
|
| 1628 | rawData = date.getSeconds();
|
| 1629 | break;
|
| 1630 | case "S":
|
| 1631 | rawData = date.getMilliseconds();
|
| 1632 | break;
|
| 1633 | case "Z":
|
| 1634 | rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.
|
| 1635 | break;
|
| 1636 | }
|
| 1637 | // Format the raw data depending on the type
|
| 1638 | switch(types[patternLetter]) {
|
| 1639 | case TEXT2:
|
| 1640 | formattedString += formatText(rawData, numberOfLetters, 2);
|
| 1641 | break;
|
| 1642 | case TEXT3:
|
| 1643 | formattedString += formatText(rawData, numberOfLetters, 3);
|
| 1644 | break;
|
| 1645 | case NUMBER:
|
| 1646 | formattedString += formatNumber(rawData, numberOfLetters);
|
| 1647 | break;
|
| 1648 | case YEAR:
|
| 1649 | if (numberOfLetters <= 3) {
|
| 1650 | // Output a 2-digit year
|
| 1651 | var dataString = "" + rawData;
|
| 1652 | formattedString += dataString.substr(2, 2);
|
| 1653 | } else {
|
| 1654 | formattedString += formatNumber(rawData, numberOfLetters);
|
| 1655 | }
|
| 1656 | break;
|
| 1657 | case MONTH:
|
| 1658 | if (numberOfLetters >= 3) {
|
| 1659 | formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);
|
| 1660 | } else {
|
| 1661 | // NB. Months returned by getMonth are zero-based
|
| 1662 | formattedString += formatNumber(rawData + 1, numberOfLetters);
|
| 1663 | }
|
| 1664 | break;
|
| 1665 | case TIMEZONE:
|
| 1666 | var isPositive = (rawData > 0);
|
| 1667 | // The following line looks like a mistake but isn't
|
| 1668 | // because of the way getTimezoneOffset measures.
|
| 1669 | var prefix = isPositive ? "-" : "+";
|
| 1670 | var absData = Math.abs(rawData);
|
| 1671 |
|
| 1672 | // Hours
|
| 1673 | var hours = "" + Math.floor(absData / 60);
|
| 1674 | hours = padWithZeroes(hours, 2);
|
| 1675 | // Minutes
|
| 1676 | var minutes = "" + (absData % 60);
|
| 1677 | minutes = padWithZeroes(minutes, 2);
|
| 1678 |
|
| 1679 | formattedString += prefix + hours + minutes;
|
| 1680 | break;
|
| 1681 | }
|
| 1682 | }
|
| 1683 | searchString = searchString.substr(result.index + result[0].length);
|
| 1684 | }
|
| 1685 | return formattedString;
|
| 1686 | };
|
| 1687 | })();
|
| 1688 |
|
| 1689 | log4javascript.SimpleDateFormat = SimpleDateFormat;
|
| 1690 |
|
| 1691 | /* ---------------------------------------------------------------------- */
|
| 1692 | // PatternLayout
|
| 1693 |
|
| 1694 | function PatternLayout(pattern) {
|
| 1695 | if (pattern) {
|
| 1696 | this.pattern = pattern;
|
| 1697 | } else {
|
| 1698 | this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
|
| 1699 | }
|
| 1700 | this.customFields = [];
|
| 1701 | }
|
| 1702 |
|
| 1703 | PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";
|
| 1704 | PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";
|
| 1705 | PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";
|
| 1706 | PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";
|
| 1707 | PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";
|
| 1708 |
|
| 1709 | PatternLayout.prototype = new Layout();
|
| 1710 |
|
| 1711 | PatternLayout.prototype.format = function(loggingEvent) {
|
| 1712 | var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;
|
| 1713 | var formattedString = "";
|
| 1714 | var result;
|
| 1715 | var searchString = this.pattern;
|
| 1716 |
|
| 1717 | // Cannot use regex global flag since it doesn't work with exec in IE5
|
| 1718 | while ((result = regex.exec(searchString))) {
|
| 1719 | var matchedString = result[0];
|
| 1720 | var padding = result[1];
|
| 1721 | var truncation = result[2];
|
| 1722 | var conversionCharacter = result[3];
|
| 1723 | var specifier = result[5];
|
| 1724 | var text = result[6];
|
| 1725 |
|
| 1726 | // Check if the pattern matched was just normal text
|
| 1727 | if (text) {
|
| 1728 | formattedString += "" + text;
|
| 1729 | } else {
|
| 1730 | // Create a raw replacement string based on the conversion
|
| 1731 | // character and specifier
|
| 1732 | var replacement = "";
|
| 1733 | switch(conversionCharacter) {
|
| 1734 | case "a": // Array of messages
|
| 1735 | case "m": // Message
|
| 1736 | var depth = 0;
|
| 1737 | if (specifier) {
|
| 1738 | depth = parseInt(specifier, 10);
|
| 1739 | if (isNaN(depth)) {
|
| 1740 | handleError("PatternLayout.format: invalid specifier '" +
|
| 1741 | specifier + "' for conversion character '" + conversionCharacter +
|
| 1742 | "' - should be a number");
|
| 1743 | depth = 0;
|
| 1744 | }
|
| 1745 | }
|
| 1746 | var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;
|
| 1747 | for (var i = 0, len = messages.length; i < len; i++) {
|
| 1748 | if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {
|
| 1749 | replacement += " ";
|
| 1750 | }
|
| 1751 | if (depth === 0) {
|
| 1752 | replacement += messages[i];
|
| 1753 | } else {
|
| 1754 | replacement += formatObjectExpansion(messages[i], depth);
|
| 1755 | }
|
| 1756 | }
|
| 1757 | break;
|
| 1758 | case "c": // Logger name
|
| 1759 | var loggerName = loggingEvent.logger.name;
|
| 1760 | if (specifier) {
|
| 1761 | var precision = parseInt(specifier, 10);
|
| 1762 | var loggerNameBits = loggingEvent.logger.name.split(".");
|
| 1763 | if (precision >= loggerNameBits.length) {
|
| 1764 | replacement = loggerName;
|
| 1765 | } else {
|
| 1766 | replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
|
| 1767 | }
|
| 1768 | } else {
|
| 1769 | replacement = loggerName;
|
| 1770 | }
|
| 1771 | break;
|
| 1772 | case "d": // Date
|
| 1773 | var dateFormat = PatternLayout.ISO8601_DATEFORMAT;
|
| 1774 | if (specifier) {
|
| 1775 | dateFormat = specifier;
|
| 1776 | // Pick up special cases
|
| 1777 | if (dateFormat == "ISO8601") {
|
| 1778 | dateFormat = PatternLayout.ISO8601_DATEFORMAT;
|
| 1779 | } else if (dateFormat == "ABSOLUTE") {
|
| 1780 | dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;
|
| 1781 | } else if (dateFormat == "DATE") {
|
| 1782 | dateFormat = PatternLayout.DATETIME_DATEFORMAT;
|
| 1783 | }
|
| 1784 | }
|
| 1785 | // Format the date
|
| 1786 | replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);
|
| 1787 | break;
|
| 1788 | case "f": // Custom field
|
| 1789 | if (this.hasCustomFields()) {
|
| 1790 | var fieldIndex = 0;
|
| 1791 | if (specifier) {
|
| 1792 | fieldIndex = parseInt(specifier, 10);
|
| 1793 | if (isNaN(fieldIndex)) {
|
| 1794 | handleError("PatternLayout.format: invalid specifier '" +
|
| 1795 | specifier + "' for conversion character 'f' - should be a number");
|
| 1796 | } else if (fieldIndex === 0) {
|
| 1797 | handleError("PatternLayout.format: invalid specifier '" +
|
| 1798 | specifier + "' for conversion character 'f' - must be greater than zero");
|
| 1799 | } else if (fieldIndex > this.customFields.length) {
|
| 1800 | handleError("PatternLayout.format: invalid specifier '" +
|
| 1801 | specifier + "' for conversion character 'f' - there aren't that many custom fields");
|
| 1802 | } else {
|
| 1803 | fieldIndex = fieldIndex - 1;
|
| 1804 | }
|
| 1805 | }
|
| 1806 | var val = this.customFields[fieldIndex].value;
|
| 1807 | if (typeof val == "function") {
|
| 1808 | val = val(this, loggingEvent);
|
| 1809 | }
|
| 1810 | replacement = val;
|
| 1811 | }
|
| 1812 | break;
|
| 1813 | case "n": // New line
|
| 1814 | replacement = newLine;
|
| 1815 | break;
|
| 1816 | case "p": // Level
|
| 1817 | replacement = loggingEvent.level.name;
|
| 1818 | break;
|
| 1819 | case "r": // Milliseconds since log4javascript startup
|
| 1820 | replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);
|
| 1821 | break;
|
| 1822 | case "%": // Literal % sign
|
| 1823 | replacement = "%";
|
| 1824 | break;
|
| 1825 | default:
|
| 1826 | replacement = matchedString;
|
| 1827 | break;
|
| 1828 | }
|
| 1829 | // Format the replacement according to any padding or
|
| 1830 | // truncation specified
|
| 1831 | var l;
|
| 1832 |
|
| 1833 | // First, truncation
|
| 1834 | if (truncation) {
|
| 1835 | l = parseInt(truncation.substr(1), 10);
|
| 1836 | var strLen = replacement.length;
|
| 1837 | if (l < strLen) {
|
| 1838 | replacement = replacement.substring(strLen - l, strLen);
|
| 1839 | }
|
| 1840 | }
|
| 1841 | // Next, padding
|
| 1842 | if (padding) {
|
| 1843 | if (padding.charAt(0) == "-") {
|
| 1844 | l = parseInt(padding.substr(1), 10);
|
| 1845 | // Right pad with spaces
|
| 1846 | while (replacement.length < l) {
|
| 1847 | replacement += " ";
|
| 1848 | }
|
| 1849 | } else {
|
| 1850 | l = parseInt(padding, 10);
|
| 1851 | // Left pad with spaces
|
| 1852 | while (replacement.length < l) {
|
| 1853 | replacement = " " + replacement;
|
| 1854 | }
|
| 1855 | }
|
| 1856 | }
|
| 1857 | formattedString += replacement;
|
| 1858 | }
|
| 1859 | searchString = searchString.substr(result.index + result[0].length);
|
| 1860 | }
|
| 1861 | return formattedString;
|
| 1862 | };
|
| 1863 |
|
| 1864 | PatternLayout.prototype.ignoresThrowable = function() {
|
| 1865 | return true;
|
| 1866 | };
|
| 1867 |
|
| 1868 | PatternLayout.prototype.toString = function() {
|
| 1869 | return "PatternLayout";
|
| 1870 | };
|
| 1871 |
|
| 1872 | log4javascript.PatternLayout = PatternLayout;
|
| 1873 | /* ---------------------------------------------------------------------- */
|
| 1874 | // AlertAppender
|
| 1875 |
|
| 1876 | function AlertAppender() {}
|
| 1877 |
|
| 1878 | AlertAppender.prototype = new Appender();
|
| 1879 |
|
| 1880 | AlertAppender.prototype.layout = new SimpleLayout();
|
| 1881 |
|
| 1882 | AlertAppender.prototype.append = function(loggingEvent) {
|
| 1883 | var formattedMessage = this.getLayout().format(loggingEvent);
|
| 1884 | if (this.getLayout().ignoresThrowable()) {
|
| 1885 | formattedMessage += loggingEvent.getThrowableStrRep();
|
| 1886 | }
|
| 1887 | alert(formattedMessage);
|
| 1888 | };
|
| 1889 |
|
| 1890 | AlertAppender.prototype.toString = function() {
|
| 1891 | return "AlertAppender";
|
| 1892 | };
|
| 1893 |
|
| 1894 | log4javascript.AlertAppender = AlertAppender;
|
| 1895 | /* ---------------------------------------------------------------------- */
|
| 1896 | // BrowserConsoleAppender (only works in Opera and Safari and Firefox with
|
| 1897 | // Firebug extension)
|
| 1898 |
|
| 1899 | function BrowserConsoleAppender() {}
|
| 1900 |
|
| 1901 | BrowserConsoleAppender.prototype = new log4javascript.Appender();
|
| 1902 | BrowserConsoleAppender.prototype.layout = new NullLayout();
|
| 1903 | BrowserConsoleAppender.prototype.threshold = Level.DEBUG;
|
| 1904 |
|
| 1905 | BrowserConsoleAppender.prototype.append = function(loggingEvent) {
|
| 1906 | var appender = this;
|
| 1907 |
|
| 1908 | var getFormattedMessage = function() {
|
| 1909 | var layout = appender.getLayout();
|
| 1910 | var formattedMessage = layout.format(loggingEvent);
|
| 1911 | if (layout.ignoresThrowable() && loggingEvent.exception) {
|
| 1912 | formattedMessage += loggingEvent.getThrowableStrRep();
|
| 1913 | }
|
| 1914 | return formattedMessage;
|
| 1915 | };
|
| 1916 |
|
| 1917 | if ((typeof opera != "undefined") && opera.postError) { // Opera
|
| 1918 | opera.postError(getFormattedMessage());
|
| 1919 | } else if (window.console && window.console.log) { // Safari and Firebug
|
| 1920 | var formattedMesage = getFormattedMessage();
|
| 1921 | // Log to Firebug using its logging methods or revert to the console.log
|
| 1922 | // method in Safari
|
| 1923 | if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {
|
| 1924 | window.console.debug(formattedMesage);
|
| 1925 | } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {
|
| 1926 | window.console.info(formattedMesage);
|
| 1927 | } else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {
|
| 1928 | window.console.warn(formattedMesage);
|
| 1929 | } else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {
|
| 1930 | window.console.error(formattedMesage);
|
| 1931 | } else {
|
| 1932 | window.console.log(formattedMesage);
|
| 1933 | }
|
| 1934 | }
|
| 1935 | };
|
| 1936 |
|
| 1937 | BrowserConsoleAppender.prototype.group = function(name) {
|
| 1938 | if (window.console && window.console.group) {
|
| 1939 | window.console.group(name);
|
| 1940 | }
|
| 1941 | };
|
| 1942 |
|
| 1943 | BrowserConsoleAppender.prototype.groupEnd = function() {
|
| 1944 | if (window.console && window.console.groupEnd) {
|
| 1945 | window.console.groupEnd();
|
| 1946 | }
|
| 1947 | };
|
| 1948 |
|
| 1949 | BrowserConsoleAppender.prototype.toString = function() {
|
| 1950 | return "BrowserConsoleAppender";
|
| 1951 | };
|
| 1952 |
|
| 1953 | log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;
|
| 1954 | /* ---------------------------------------------------------------------- */
|
| 1955 | // AjaxAppender related
|
| 1956 |
|
| 1957 | var xmlHttpFactories = [
|
| 1958 | function() { return new XMLHttpRequest(); },
|
| 1959 | function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
|
| 1960 | function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
|
| 1961 | ];
|
| 1962 |
|
| 1963 | var getXmlHttp = function(errorHandler) {
|
| 1964 | // This is only run the first time; the value of getXmlHttp gets
|
| 1965 | // replaced with the factory that succeeds on the first run
|
| 1966 | var xmlHttp = null, factory;
|
| 1967 | for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {
|
| 1968 | factory = xmlHttpFactories[i];
|
| 1969 | try {
|
| 1970 | xmlHttp = factory();
|
| 1971 | getXmlHttp = factory;
|
| 1972 | return xmlHttp;
|
| 1973 | } catch (e) {
|
| 1974 | }
|
| 1975 | }
|
| 1976 | // If we're here, all factories have failed, so throw an error
|
| 1977 | if (errorHandler) {
|
| 1978 | errorHandler();
|
| 1979 | } else {
|
| 1980 | handleError("getXmlHttp: unable to obtain XMLHttpRequest object");
|
| 1981 | }
|
| 1982 | };
|
| 1983 |
|
| 1984 | function isHttpRequestSuccessful(xmlHttp) {
|
| 1985 | return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||
|
| 1986 | (xmlHttp.status >= 200 && xmlHttp.status < 300) ||
|
| 1987 | xmlHttp.status == 1223 /* Fix for IE */;
|
| 1988 | }
|
| 1989 |
|
| 1990 | /* ---------------------------------------------------------------------- */
|
| 1991 | // AjaxAppender
|
| 1992 |
|
| 1993 | function AjaxAppender(url) {
|
| 1994 | var appender = this;
|
| 1995 | var isSupported = true;
|
| 1996 | if (!url) {
|
| 1997 | handleError("AjaxAppender: URL must be specified in constructor");
|
| 1998 | isSupported = false;
|
| 1999 | }
|
| 2000 |
|
| 2001 | var timed = this.defaults.timed;
|
| 2002 | var waitForResponse = this.defaults.waitForResponse;
|
| 2003 | var batchSize = this.defaults.batchSize;
|
| 2004 | var timerInterval = this.defaults.timerInterval;
|
| 2005 | var requestSuccessCallback = this.defaults.requestSuccessCallback;
|
| 2006 | var failCallback = this.defaults.failCallback;
|
| 2007 | var postVarName = this.defaults.postVarName;
|
| 2008 | var sendAllOnUnload = this.defaults.sendAllOnUnload;
|
| 2009 | var contentType = this.defaults.contentType;
|
| 2010 | var sessionId = null;
|
| 2011 |
|
| 2012 | var queuedLoggingEvents = [];
|
| 2013 | var queuedRequests = [];
|
| 2014 | var headers = [];
|
| 2015 | var sending = false;
|
| 2016 | var initialized = false;
|
| 2017 |
|
| 2018 | // Configuration methods. The function scope is used to prevent
|
| 2019 | // direct alteration to the appender configuration properties.
|
| 2020 | function checkCanConfigure(configOptionName) {
|
| 2021 | if (initialized) {
|
| 2022 | handleError("AjaxAppender: configuration option '" +
|
| 2023 | configOptionName +
|
| 2024 | "' may not be set after the appender has been initialized");
|
| 2025 | return false;
|
| 2026 | }
|
| 2027 | return true;
|
| 2028 | }
|
| 2029 |
|
| 2030 | this.getSessionId = function() { return sessionId; };
|
| 2031 | this.setSessionId = function(sessionIdParam) {
|
| 2032 | sessionId = extractStringFromParam(sessionIdParam, null);
|
| 2033 | this.layout.setCustomField("sessionid", sessionId);
|
| 2034 | };
|
| 2035 |
|
| 2036 | this.setLayout = function(layoutParam) {
|
| 2037 | if (checkCanConfigure("layout")) {
|
| 2038 | this.layout = layoutParam;
|
| 2039 | // Set the session id as a custom field on the layout, if not already present
|
| 2040 | if (sessionId !== null) {
|
| 2041 | this.setSessionId(sessionId);
|
| 2042 | }
|
| 2043 | }
|
| 2044 | };
|
| 2045 |
|
| 2046 | this.isTimed = function() { return timed; };
|
| 2047 | this.setTimed = function(timedParam) {
|
| 2048 | if (checkCanConfigure("timed")) {
|
| 2049 | timed = bool(timedParam);
|
| 2050 | }
|
| 2051 | };
|
| 2052 |
|
| 2053 | this.getTimerInterval = function() { return timerInterval; };
|
| 2054 | this.setTimerInterval = function(timerIntervalParam) {
|
| 2055 | if (checkCanConfigure("timerInterval")) {
|
| 2056 | timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);
|
| 2057 | }
|
| 2058 | };
|
| 2059 |
|
| 2060 | this.isWaitForResponse = function() { return waitForResponse; };
|
| 2061 | this.setWaitForResponse = function(waitForResponseParam) {
|
| 2062 | if (checkCanConfigure("waitForResponse")) {
|
| 2063 | waitForResponse = bool(waitForResponseParam);
|
| 2064 | }
|
| 2065 | };
|
| 2066 |
|
| 2067 | this.getBatchSize = function() { return batchSize; };
|
| 2068 | this.setBatchSize = function(batchSizeParam) {
|
| 2069 | if (checkCanConfigure("batchSize")) {
|
| 2070 | batchSize = extractIntFromParam(batchSizeParam, batchSize);
|
| 2071 | }
|
| 2072 | };
|
| 2073 |
|
| 2074 | this.isSendAllOnUnload = function() { return sendAllOnUnload; };
|
| 2075 | this.setSendAllOnUnload = function(sendAllOnUnloadParam) {
|
| 2076 | if (checkCanConfigure("sendAllOnUnload")) {
|
| 2077 | sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);
|
| 2078 | }
|
| 2079 | };
|
| 2080 |
|
| 2081 | this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {
|
| 2082 | requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);
|
| 2083 | };
|
| 2084 |
|
| 2085 | this.setFailCallback = function(failCallbackParam) {
|
| 2086 | failCallback = extractFunctionFromParam(failCallbackParam, failCallback);
|
| 2087 | };
|
| 2088 |
|
| 2089 | this.getPostVarName = function() { return postVarName; };
|
| 2090 | this.setPostVarName = function(postVarNameParam) {
|
| 2091 | if (checkCanConfigure("postVarName")) {
|
| 2092 | postVarName = extractStringFromParam(postVarNameParam, postVarName);
|
| 2093 | }
|
| 2094 | };
|
| 2095 |
|
| 2096 | this.getHeaders = function() { return headers; };
|
| 2097 | this.addHeader = function(name, value) {
|
| 2098 | if (name.toLowerCase() == "content-type") {
|
| 2099 | contentType = value;
|
| 2100 | } else {
|
| 2101 | headers.push( { name: name, value: value } );
|
| 2102 | }
|
| 2103 | };
|
| 2104 |
|
| 2105 | // Internal functions
|
| 2106 | function sendAll() {
|
| 2107 | if (isSupported && enabled) {
|
| 2108 | sending = true;
|
| 2109 | var currentRequestBatch;
|
| 2110 | if (waitForResponse) {
|
| 2111 | // Send the first request then use this function as the callback once
|
| 2112 | // the response comes back
|
| 2113 | if (queuedRequests.length > 0) {
|
| 2114 | currentRequestBatch = queuedRequests.shift();
|
| 2115 | sendRequest(preparePostData(currentRequestBatch), sendAll);
|
| 2116 | } else {
|
| 2117 | sending = false;
|
| 2118 | if (timed) {
|
| 2119 | scheduleSending();
|
| 2120 | }
|
| 2121 | }
|
| 2122 | } else {
|
| 2123 | // Rattle off all the requests without waiting to see the response
|
| 2124 | while ((currentRequestBatch = queuedRequests.shift())) {
|
| 2125 | sendRequest(preparePostData(currentRequestBatch));
|
| 2126 | }
|
| 2127 | sending = false;
|
| 2128 | if (timed) {
|
| 2129 | scheduleSending();
|
| 2130 | }
|
| 2131 | }
|
| 2132 | }
|
| 2133 | }
|
| 2134 |
|
| 2135 | this.sendAll = sendAll;
|
| 2136 |
|
| 2137 | // Called when the window unloads. At this point we're past caring about
|
| 2138 | // waiting for responses or timers or incomplete batches - everything
|
| 2139 | // must go, now
|
| 2140 | function sendAllRemaining() {
|
| 2141 | var sendingAnything = false;
|
| 2142 | if (isSupported && enabled) {
|
| 2143 | // Create requests for everything left over, batched as normal
|
| 2144 | var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;
|
| 2145 | var currentLoggingEvent;
|
| 2146 | var batchedLoggingEvents = [];
|
| 2147 | while ((currentLoggingEvent = queuedLoggingEvents.shift())) {
|
| 2148 | batchedLoggingEvents.push(currentLoggingEvent);
|
| 2149 | if (queuedLoggingEvents.length >= actualBatchSize) {
|
| 2150 | // Queue this batch of log entries
|
| 2151 | queuedRequests.push(batchedLoggingEvents);
|
| 2152 | batchedLoggingEvents = [];
|
| 2153 | }
|
| 2154 | }
|
| 2155 | // If there's a partially completed batch, add it
|
| 2156 | if (batchedLoggingEvents.length > 0) {
|
| 2157 | queuedRequests.push(batchedLoggingEvents);
|
| 2158 | }
|
| 2159 | sendingAnything = (queuedRequests.length > 0);
|
| 2160 | waitForResponse = false;
|
| 2161 | timed = false;
|
| 2162 | sendAll();
|
| 2163 | }
|
| 2164 | return sendingAnything;
|
| 2165 | }
|
| 2166 |
|
| 2167 | this.sendAllRemaining = sendAllRemaining;
|
| 2168 |
|
| 2169 | function preparePostData(batchedLoggingEvents) {
|
| 2170 | // Format the logging events
|
| 2171 | var formattedMessages = [];
|
| 2172 | var currentLoggingEvent;
|
| 2173 | var postData = "";
|
| 2174 | while ((currentLoggingEvent = batchedLoggingEvents.shift())) {
|
| 2175 | var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);
|
| 2176 | if (appender.getLayout().ignoresThrowable()) {
|
| 2177 | currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();
|
| 2178 | }
|
| 2179 | formattedMessages.push(currentFormattedMessage);
|
| 2180 | }
|
| 2181 | // Create the post data string
|
| 2182 | if (batchedLoggingEvents.length == 1) {
|
| 2183 | postData = formattedMessages.join("");
|
| 2184 | } else {
|
| 2185 | postData = appender.getLayout().batchHeader +
|
| 2186 | formattedMessages.join(appender.getLayout().batchSeparator) +
|
| 2187 | appender.getLayout().batchFooter;
|
| 2188 | }
|
| 2189 | if (contentType == appender.defaults.contentType) {
|
| 2190 | postData = appender.getLayout().returnsPostData ? postData :
|
| 2191 | urlEncode(postVarName) + "=" + urlEncode(postData);
|
| 2192 | // Add the layout name to the post data
|
| 2193 | if (postData.length > 0) {
|
| 2194 | postData += "&";
|
| 2195 | }
|
| 2196 | postData += "layout=" + urlEncode(appender.getLayout().toString());
|
| 2197 | }
|
| 2198 | return postData;
|
| 2199 | }
|
| 2200 |
|
| 2201 | function scheduleSending() {
|
| 2202 | window.setTimeout(sendAll, timerInterval);
|
| 2203 | }
|
| 2204 |
|
| 2205 | function xmlHttpErrorHandler() {
|
| 2206 | var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";
|
| 2207 | handleError(msg);
|
| 2208 | isSupported = false;
|
| 2209 | if (failCallback) {
|
| 2210 | failCallback(msg);
|
| 2211 | }
|
| 2212 | }
|
| 2213 |
|
| 2214 | function sendRequest(postData, successCallback) {
|
| 2215 | try {
|
| 2216 | var xmlHttp = getXmlHttp(xmlHttpErrorHandler);
|
| 2217 | if (isSupported) {
|
| 2218 | if (xmlHttp.overrideMimeType) {
|
| 2219 | xmlHttp.overrideMimeType(appender.getLayout().getContentType());
|
| 2220 | }
|
| 2221 | xmlHttp.onreadystatechange = function() {
|
| 2222 | if (xmlHttp.readyState == 4) {
|
| 2223 | if (isHttpRequestSuccessful(xmlHttp)) {
|
| 2224 | if (requestSuccessCallback) {
|
| 2225 | requestSuccessCallback(xmlHttp);
|
| 2226 | }
|
| 2227 | if (successCallback) {
|
| 2228 | successCallback(xmlHttp);
|
| 2229 | }
|
| 2230 | } else {
|
| 2231 | var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +
|
| 2232 | url + " returned status code " + xmlHttp.status;
|
| 2233 | handleError(msg);
|
| 2234 | if (failCallback) {
|
| 2235 | failCallback(msg);
|
| 2236 | }
|
| 2237 | }
|
| 2238 | xmlHttp.onreadystatechange = emptyFunction;
|
| 2239 | xmlHttp = null;
|
| 2240 | }
|
| 2241 | };
|
| 2242 | xmlHttp.open("POST", url, true);
|
| 2243 | try {
|
| 2244 | for (var i = 0, header; header = headers[i++]; ) {
|
| 2245 | xmlHttp.setRequestHeader(header.name, header.value);
|
| 2246 | }
|
| 2247 | xmlHttp.setRequestHeader("Content-Type", contentType);
|
| 2248 | } catch (headerEx) {
|
| 2249 | var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +
|
| 2250 | " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";
|
| 2251 | handleError(msg);
|
| 2252 | isSupported = false;
|
| 2253 | if (failCallback) {
|
| 2254 | failCallback(msg);
|
| 2255 | }
|
| 2256 | return;
|
| 2257 | }
|
| 2258 | xmlHttp.send(postData);
|
| 2259 | }
|
| 2260 | } catch (ex) {
|
| 2261 | var errMsg = "AjaxAppender.append: error sending log message to " + url;
|
| 2262 | handleError(errMsg, ex);
|
| 2263 | isSupported = false;
|
| 2264 | if (failCallback) {
|
| 2265 | failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));
|
| 2266 | }
|
| 2267 | }
|
| 2268 | }
|
| 2269 |
|
| 2270 | this.append = function(loggingEvent) {
|
| 2271 | if (isSupported) {
|
| 2272 | if (!initialized) {
|
| 2273 | init();
|
| 2274 | }
|
| 2275 | queuedLoggingEvents.push(loggingEvent);
|
| 2276 | var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;
|
| 2277 |
|
| 2278 | if (queuedLoggingEvents.length >= actualBatchSize) {
|
| 2279 | var currentLoggingEvent;
|
| 2280 | var batchedLoggingEvents = [];
|
| 2281 | while ((currentLoggingEvent = queuedLoggingEvents.shift())) {
|
| 2282 | batchedLoggingEvents.push(currentLoggingEvent);
|
| 2283 | }
|
| 2284 | // Queue this batch of log entries
|
| 2285 | queuedRequests.push(batchedLoggingEvents);
|
| 2286 |
|
| 2287 | // If using a timer, the queue of requests will be processed by the
|
| 2288 | // timer function, so nothing needs to be done here.
|
| 2289 | if (!timed && (!waitForResponse || (waitForResponse && !sending))) {
|
| 2290 | sendAll();
|
| 2291 | }
|
| 2292 | }
|
| 2293 | }
|
| 2294 | };
|
| 2295 |
|
| 2296 | function init() {
|
| 2297 | initialized = true;
|
| 2298 | // Add unload event to send outstanding messages
|
| 2299 | if (sendAllOnUnload) {
|
| 2300 | var oldBeforeUnload = window.onbeforeunload;
|
| 2301 | window.onbeforeunload = function() {
|
| 2302 | if (oldBeforeUnload) {
|
| 2303 | oldBeforeUnload();
|
| 2304 | }
|
| 2305 | if (sendAllRemaining()) {
|
| 2306 | return "Sending log messages";
|
| 2307 | }
|
| 2308 | };
|
| 2309 | }
|
| 2310 | // Start timer
|
| 2311 | if (timed) {
|
| 2312 | scheduleSending();
|
| 2313 | }
|
| 2314 | }
|
| 2315 | }
|
| 2316 |
|
| 2317 | AjaxAppender.prototype = new Appender();
|
| 2318 |
|
| 2319 | AjaxAppender.prototype.defaults = {
|
| 2320 | waitForResponse: false,
|
| 2321 | timed: false,
|
| 2322 | timerInterval: 1000,
|
| 2323 | batchSize: 1,
|
| 2324 | sendAllOnUnload: false,
|
| 2325 | requestSuccessCallback: null,
|
| 2326 | failCallback: null,
|
| 2327 | postVarName: "data",
|
| 2328 | contentType: "application/x-www-form-urlencoded"
|
| 2329 | };
|
| 2330 |
|
| 2331 | AjaxAppender.prototype.layout = new HttpPostDataLayout();
|
| 2332 |
|
| 2333 | AjaxAppender.prototype.toString = function() {
|
| 2334 | return "AjaxAppender";
|
| 2335 | };
|
| 2336 |
|
| 2337 | log4javascript.AjaxAppender = AjaxAppender;
|
| 2338 | /* ---------------------------------------------------------------------- */
|
| 2339 | // PopUpAppender and InPageAppender related
|
| 2340 |
|
| 2341 | function setCookie(name, value, days, path) {
|
| 2342 | var expires;
|
| 2343 | path = path ? "; path=" + path : "";
|
| 2344 | if (days) {
|
| 2345 | var date = new Date();
|
| 2346 | date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
| 2347 | expires = "; expires=" + date.toGMTString();
|
| 2348 | } else {
|
| 2349 | expires = "";
|
| 2350 | }
|
| 2351 | document.cookie = escape(name) + "=" + escape(value) + expires + path;
|
| 2352 | }
|
| 2353 |
|
| 2354 | function getCookie(name) {
|
| 2355 | var nameEquals = escape(name) + "=";
|
| 2356 | var ca = document.cookie.split(";");
|
| 2357 | for (var i = 0, len = ca.length; i < len; i++) {
|
| 2358 | var c = ca[i];
|
| 2359 | while (c.charAt(0) === " ") {
|
| 2360 | c = c.substring(1, c.length);
|
| 2361 | }
|
| 2362 | if (c.indexOf(nameEquals) === 0) {
|
| 2363 | return unescape(c.substring(nameEquals.length, c.length));
|
| 2364 | }
|
| 2365 | }
|
| 2366 | return null;
|
| 2367 | }
|
| 2368 |
|
| 2369 | // Gets the base URL of the location of the log4javascript script.
|
| 2370 | // This is far from infallible.
|
| 2371 | function getBaseUrl() {
|
| 2372 | var scripts = document.getElementsByTagName("script");
|
| 2373 | for (var i = 0, len = scripts.length; i < len; ++i) {
|
| 2374 | if (scripts[i].src.indexOf("log4javascript") != -1) {
|
| 2375 | var lastSlash = scripts[i].src.lastIndexOf("/");
|
| 2376 | return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);
|
| 2377 | }
|
| 2378 | }
|
| 2379 | return null;
|
| 2380 | }
|
| 2381 |
|
| 2382 | function isLoaded(win) {
|
| 2383 | try {
|
| 2384 | return bool(win.loaded);
|
| 2385 | } catch (ex) {
|
| 2386 | return false;
|
| 2387 | }
|
| 2388 | }
|
| 2389 |
|
| 2390 | /* ---------------------------------------------------------------------- */
|
| 2391 | // ConsoleAppender (prototype for PopUpAppender and InPageAppender)
|
| 2392 |
|
| 2393 | var ConsoleAppender;
|
| 2394 |
|
| 2395 | // Create an anonymous function to protect base console methods
|
| 2396 | (function() {
|
| 2397 | var getConsoleHtmlLines = function() {
|
| 2398 | return [
|
| 2399 | '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
| 2400 | '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',
|
| 2401 | ' <head>',
|
| 2402 | ' <title>log4javascript</title>',
|
| 2403 | ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
|
| 2404 | ' <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',
|
| 2405 | ' <meta http-equiv="X-UA-Compatible" content="IE=7" />',
|
| 2406 | ' <script type="text/javascript">var isIe = false, isIePre7 = false;</script>',
|
| 2407 | ' <!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',
|
| 2408 | ' <!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',
|
| 2409 | ' <script type="text/javascript">',
|
| 2410 | ' //<![CDATA[',
|
| 2411 | ' var loggingEnabled = true;',
|
| 2412 | ' var logQueuedEventsTimer = null;',
|
| 2413 | ' var logEntries = [];',
|
| 2414 | ' var logEntriesAndSeparators = [];',
|
| 2415 | ' var logItems = [];',
|
| 2416 | ' var renderDelay = 100;',
|
| 2417 | ' var unrenderedLogItemsExist = false;',
|
| 2418 | ' var rootGroup, currentGroup = null;',
|
| 2419 | ' var loaded = false;',
|
| 2420 | ' var currentLogItem = null;',
|
| 2421 | ' var logMainContainer;',
|
| 2422 | '',
|
| 2423 | ' function copyProperties(obj, props) {',
|
| 2424 | ' for (var i in props) {',
|
| 2425 | ' obj[i] = props[i];',
|
| 2426 | ' }',
|
| 2427 | ' }',
|
| 2428 | '',
|
| 2429 | ' /*----------------------------------------------------------------*/',
|
| 2430 | '',
|
| 2431 | ' function LogItem() {',
|
| 2432 | ' }',
|
| 2433 | '',
|
| 2434 | ' LogItem.prototype = {',
|
| 2435 | ' mainContainer: null,',
|
| 2436 | ' wrappedContainer: null,',
|
| 2437 | ' unwrappedContainer: null,',
|
| 2438 | ' group: null,',
|
| 2439 | '',
|
| 2440 | ' appendToLog: function() {',
|
| 2441 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2442 | ' this.elementContainers[i].appendToLog();',
|
| 2443 | ' }',
|
| 2444 | ' this.group.update();',
|
| 2445 | ' },',
|
| 2446 | '',
|
| 2447 | ' doRemove: function(doUpdate, removeFromGroup) {',
|
| 2448 | ' if (this.rendered) {',
|
| 2449 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2450 | ' this.elementContainers[i].remove();',
|
| 2451 | ' }',
|
| 2452 | ' this.unwrappedElementContainer = null;',
|
| 2453 | ' this.wrappedElementContainer = null;',
|
| 2454 | ' this.mainElementContainer = null;',
|
| 2455 | ' }',
|
| 2456 | ' if (this.group && removeFromGroup) {',
|
| 2457 | ' this.group.removeChild(this, doUpdate);',
|
| 2458 | ' }',
|
| 2459 | ' if (this === currentLogItem) {',
|
| 2460 | ' currentLogItem = null;',
|
| 2461 | ' }',
|
| 2462 | ' },',
|
| 2463 | '',
|
| 2464 | ' remove: function(doUpdate, removeFromGroup) {',
|
| 2465 | ' this.doRemove(doUpdate, removeFromGroup);',
|
| 2466 | ' },',
|
| 2467 | '',
|
| 2468 | ' render: function() {},',
|
| 2469 | '',
|
| 2470 | ' accept: function(visitor) {',
|
| 2471 | ' visitor.visit(this);',
|
| 2472 | ' },',
|
| 2473 | '',
|
| 2474 | ' getUnwrappedDomContainer: function() {',
|
| 2475 | ' return this.group.unwrappedElementContainer.contentDiv;',
|
| 2476 | ' },',
|
| 2477 | '',
|
| 2478 | ' getWrappedDomContainer: function() {',
|
| 2479 | ' return this.group.wrappedElementContainer.contentDiv;',
|
| 2480 | ' },',
|
| 2481 | '',
|
| 2482 | ' getMainDomContainer: function() {',
|
| 2483 | ' return this.group.mainElementContainer.contentDiv;',
|
| 2484 | ' }',
|
| 2485 | ' };',
|
| 2486 | '',
|
| 2487 | ' LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',
|
| 2488 | '',
|
| 2489 | ' /*----------------------------------------------------------------*/',
|
| 2490 | '',
|
| 2491 | ' function LogItemContainerElement() {',
|
| 2492 | ' }',
|
| 2493 | '',
|
| 2494 | ' LogItemContainerElement.prototype = {',
|
| 2495 | ' appendToLog: function() {',
|
| 2496 | ' var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',
|
| 2497 | ' if (insertBeforeFirst) {',
|
| 2498 | ' this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',
|
| 2499 | ' } else {',
|
| 2500 | ' this.containerDomNode.appendChild(this.mainDiv);',
|
| 2501 | ' }',
|
| 2502 | ' }',
|
| 2503 | ' };',
|
| 2504 | '',
|
| 2505 | ' /*----------------------------------------------------------------*/',
|
| 2506 | '',
|
| 2507 | ' function SeparatorElementContainer(containerDomNode) {',
|
| 2508 | ' this.containerDomNode = containerDomNode;',
|
| 2509 | ' this.mainDiv = document.createElement("div");',
|
| 2510 | ' this.mainDiv.className = "separator";',
|
| 2511 | ' this.mainDiv.innerHTML = " ";',
|
| 2512 | ' }',
|
| 2513 | '',
|
| 2514 | ' SeparatorElementContainer.prototype = new LogItemContainerElement();',
|
| 2515 | '',
|
| 2516 | ' SeparatorElementContainer.prototype.remove = function() {',
|
| 2517 | ' this.mainDiv.parentNode.removeChild(this.mainDiv);',
|
| 2518 | ' this.mainDiv = null;',
|
| 2519 | ' };',
|
| 2520 | '',
|
| 2521 | ' /*----------------------------------------------------------------*/',
|
| 2522 | '',
|
| 2523 | ' function Separator() {',
|
| 2524 | ' this.rendered = false;',
|
| 2525 | ' }',
|
| 2526 | '',
|
| 2527 | ' Separator.prototype = new LogItem();',
|
| 2528 | '',
|
| 2529 | ' copyProperties(Separator.prototype, {',
|
| 2530 | ' render: function() {',
|
| 2531 | ' var containerDomNode = this.group.contentDiv;',
|
| 2532 | ' if (isIe) {',
|
| 2533 | ' this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',
|
| 2534 | ' this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',
|
| 2535 | ' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',
|
| 2536 | ' } else {',
|
| 2537 | ' this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',
|
| 2538 | ' this.elementContainers = [this.mainElementContainer];',
|
| 2539 | ' }',
|
| 2540 | ' this.content = this.formattedMessage;',
|
| 2541 | ' this.rendered = true;',
|
| 2542 | ' }',
|
| 2543 | ' });',
|
| 2544 | '',
|
| 2545 | ' /*----------------------------------------------------------------*/',
|
| 2546 | '',
|
| 2547 | ' function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',
|
| 2548 | ' this.group = group;',
|
| 2549 | ' this.containerDomNode = containerDomNode;',
|
| 2550 | ' this.isRoot = isRoot;',
|
| 2551 | ' this.isWrapped = isWrapped;',
|
| 2552 | ' this.expandable = false;',
|
| 2553 | '',
|
| 2554 | ' if (this.isRoot) {',
|
| 2555 | ' if (isIe) {',
|
| 2556 | ' this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',
|
| 2557 | ' this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',
|
| 2558 | ' } else {',
|
| 2559 | ' this.contentDiv = logMainContainer;',
|
| 2560 | ' }',
|
| 2561 | ' } else {',
|
| 2562 | ' var groupElementContainer = this;',
|
| 2563 | ' ',
|
| 2564 | ' this.mainDiv = document.createElement("div");',
|
| 2565 | ' this.mainDiv.className = "group";',
|
| 2566 | '',
|
| 2567 | ' this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',
|
| 2568 | ' this.headingDiv.className = "groupheading";',
|
| 2569 | '',
|
| 2570 | ' this.expander = this.headingDiv.appendChild(document.createElement("span"));',
|
| 2571 | ' this.expander.className = "expander unselectable greyedout";',
|
| 2572 | ' this.expander.unselectable = true;',
|
| 2573 | ' var expanderText = this.group.expanded ? "-" : "+";',
|
| 2574 | ' this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',
|
| 2575 | ' ',
|
| 2576 | ' this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',
|
| 2577 | '',
|
| 2578 | ' this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',
|
| 2579 | ' var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',
|
| 2580 | ' this.contentDiv.className = "groupcontent " + contentCssClass;',
|
| 2581 | '',
|
| 2582 | ' this.expander.onclick = function() {',
|
| 2583 | ' if (groupElementContainer.group.expandable) {',
|
| 2584 | ' groupElementContainer.group.toggleExpanded();',
|
| 2585 | ' }',
|
| 2586 | ' };',
|
| 2587 | ' }',
|
| 2588 | ' }',
|
| 2589 | '',
|
| 2590 | ' GroupElementContainer.prototype = new LogItemContainerElement();',
|
| 2591 | '',
|
| 2592 | ' copyProperties(GroupElementContainer.prototype, {',
|
| 2593 | ' toggleExpanded: function() {',
|
| 2594 | ' if (!this.isRoot) {',
|
| 2595 | ' var oldCssClass, newCssClass, expanderText;',
|
| 2596 | ' if (this.group.expanded) {',
|
| 2597 | ' newCssClass = "expanded";',
|
| 2598 | ' oldCssClass = "collapsed";',
|
| 2599 | ' expanderText = "-";',
|
| 2600 | ' } else {',
|
| 2601 | ' newCssClass = "collapsed";',
|
| 2602 | ' oldCssClass = "expanded";',
|
| 2603 | ' expanderText = "+";',
|
| 2604 | ' }',
|
| 2605 | ' replaceClass(this.contentDiv, newCssClass, oldCssClass);',
|
| 2606 | ' this.expanderTextNode.nodeValue = expanderText;',
|
| 2607 | ' }',
|
| 2608 | ' },',
|
| 2609 | '',
|
| 2610 | ' remove: function() {',
|
| 2611 | ' if (!this.isRoot) {',
|
| 2612 | ' this.headingDiv = null;',
|
| 2613 | ' this.expander.onclick = null;',
|
| 2614 | ' this.expander = null;',
|
| 2615 | ' this.expanderTextNode = null;',
|
| 2616 | ' this.contentDiv = null;',
|
| 2617 | ' this.containerDomNode = null;',
|
| 2618 | ' this.mainDiv.parentNode.removeChild(this.mainDiv);',
|
| 2619 | ' this.mainDiv = null;',
|
| 2620 | ' }',
|
| 2621 | ' },',
|
| 2622 | '',
|
| 2623 | ' reverseChildren: function() {',
|
| 2624 | ' // Invert the order of the log entries',
|
| 2625 | ' var node = null;',
|
| 2626 | '',
|
| 2627 | ' // Remove all the log container nodes',
|
| 2628 | ' var childDomNodes = [];',
|
| 2629 | ' while ((node = this.contentDiv.firstChild)) {',
|
| 2630 | ' this.contentDiv.removeChild(node);',
|
| 2631 | ' childDomNodes.push(node);',
|
| 2632 | ' }',
|
| 2633 | '',
|
| 2634 | ' // Put them all back in reverse order',
|
| 2635 | ' while ((node = childDomNodes.pop())) {',
|
| 2636 | ' this.contentDiv.appendChild(node);',
|
| 2637 | ' }',
|
| 2638 | ' },',
|
| 2639 | '',
|
| 2640 | ' update: function() {',
|
| 2641 | ' if (!this.isRoot) {',
|
| 2642 | ' if (this.group.expandable) {',
|
| 2643 | ' removeClass(this.expander, "greyedout");',
|
| 2644 | ' } else {',
|
| 2645 | ' addClass(this.expander, "greyedout");',
|
| 2646 | ' }',
|
| 2647 | ' }',
|
| 2648 | ' },',
|
| 2649 | '',
|
| 2650 | ' clear: function() {',
|
| 2651 | ' if (this.isRoot) {',
|
| 2652 | ' this.contentDiv.innerHTML = "";',
|
| 2653 | ' }',
|
| 2654 | ' }',
|
| 2655 | ' });',
|
| 2656 | '',
|
| 2657 | ' /*----------------------------------------------------------------*/',
|
| 2658 | '',
|
| 2659 | ' function Group(name, isRoot, initiallyExpanded) {',
|
| 2660 | ' this.name = name;',
|
| 2661 | ' this.group = null;',
|
| 2662 | ' this.isRoot = isRoot;',
|
| 2663 | ' this.initiallyExpanded = initiallyExpanded;',
|
| 2664 | ' this.elementContainers = [];',
|
| 2665 | ' this.children = [];',
|
| 2666 | ' this.expanded = initiallyExpanded;',
|
| 2667 | ' this.rendered = false;',
|
| 2668 | ' this.expandable = false;',
|
| 2669 | ' }',
|
| 2670 | '',
|
| 2671 | ' Group.prototype = new LogItem();',
|
| 2672 | '',
|
| 2673 | ' copyProperties(Group.prototype, {',
|
| 2674 | ' addChild: function(logItem) {',
|
| 2675 | ' this.children.push(logItem);',
|
| 2676 | ' logItem.group = this;',
|
| 2677 | ' },',
|
| 2678 | '',
|
| 2679 | ' render: function() {',
|
| 2680 | ' if (isIe) {',
|
| 2681 | ' var unwrappedDomContainer, wrappedDomContainer;',
|
| 2682 | ' if (this.isRoot) {',
|
| 2683 | ' unwrappedDomContainer = logMainContainer;',
|
| 2684 | ' wrappedDomContainer = logMainContainer;',
|
| 2685 | ' } else {',
|
| 2686 | ' unwrappedDomContainer = this.getUnwrappedDomContainer();',
|
| 2687 | ' wrappedDomContainer = this.getWrappedDomContainer();',
|
| 2688 | ' }',
|
| 2689 | ' this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',
|
| 2690 | ' this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',
|
| 2691 | ' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',
|
| 2692 | ' } else {',
|
| 2693 | ' var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',
|
| 2694 | ' this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',
|
| 2695 | ' this.elementContainers = [this.mainElementContainer];',
|
| 2696 | ' }',
|
| 2697 | ' this.rendered = true;',
|
| 2698 | ' },',
|
| 2699 | '',
|
| 2700 | ' toggleExpanded: function() {',
|
| 2701 | ' this.expanded = !this.expanded;',
|
| 2702 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2703 | ' this.elementContainers[i].toggleExpanded();',
|
| 2704 | ' }',
|
| 2705 | ' },',
|
| 2706 | '',
|
| 2707 | ' expand: function() {',
|
| 2708 | ' if (!this.expanded) {',
|
| 2709 | ' this.toggleExpanded();',
|
| 2710 | ' }',
|
| 2711 | ' },',
|
| 2712 | '',
|
| 2713 | ' accept: function(visitor) {',
|
| 2714 | ' visitor.visitGroup(this);',
|
| 2715 | ' },',
|
| 2716 | '',
|
| 2717 | ' reverseChildren: function() {',
|
| 2718 | ' if (this.rendered) {',
|
| 2719 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2720 | ' this.elementContainers[i].reverseChildren();',
|
| 2721 | ' }',
|
| 2722 | ' }',
|
| 2723 | ' },',
|
| 2724 | '',
|
| 2725 | ' update: function() {',
|
| 2726 | ' var previouslyExpandable = this.expandable;',
|
| 2727 | ' this.expandable = (this.children.length !== 0);',
|
| 2728 | ' if (this.expandable !== previouslyExpandable) {',
|
| 2729 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2730 | ' this.elementContainers[i].update();',
|
| 2731 | ' }',
|
| 2732 | ' }',
|
| 2733 | ' },',
|
| 2734 | '',
|
| 2735 | ' flatten: function() {',
|
| 2736 | ' var visitor = new GroupFlattener();',
|
| 2737 | ' this.accept(visitor);',
|
| 2738 | ' return visitor.logEntriesAndSeparators;',
|
| 2739 | ' },',
|
| 2740 | '',
|
| 2741 | ' removeChild: function(child, doUpdate) {',
|
| 2742 | ' array_remove(this.children, child);',
|
| 2743 | ' child.group = null;',
|
| 2744 | ' if (doUpdate) {',
|
| 2745 | ' this.update();',
|
| 2746 | ' }',
|
| 2747 | ' },',
|
| 2748 | '',
|
| 2749 | ' remove: function(doUpdate, removeFromGroup) {',
|
| 2750 | ' for (var i = 0, len = this.children.length; i < len; i++) {',
|
| 2751 | ' this.children[i].remove(false, false);',
|
| 2752 | ' }',
|
| 2753 | ' this.children = [];',
|
| 2754 | ' this.update();',
|
| 2755 | ' if (this === currentGroup) {',
|
| 2756 | ' currentGroup = this.group;',
|
| 2757 | ' }',
|
| 2758 | ' this.doRemove(doUpdate, removeFromGroup);',
|
| 2759 | ' },',
|
| 2760 | '',
|
| 2761 | ' serialize: function(items) {',
|
| 2762 | ' items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',
|
| 2763 | ' for (var i = 0, len = this.children.length; i < len; i++) {',
|
| 2764 | ' this.children[i].serialize(items);',
|
| 2765 | ' }',
|
| 2766 | ' if (this !== currentGroup) {',
|
| 2767 | ' items.push([LogItem.serializedItemKeys.GROUP_END]);',
|
| 2768 | ' }',
|
| 2769 | ' },',
|
| 2770 | '',
|
| 2771 | ' clear: function() {',
|
| 2772 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2773 | ' this.elementContainers[i].clear();',
|
| 2774 | ' }',
|
| 2775 | ' }',
|
| 2776 | ' });',
|
| 2777 | '',
|
| 2778 | ' /*----------------------------------------------------------------*/',
|
| 2779 | '',
|
| 2780 | ' function LogEntryElementContainer() {',
|
| 2781 | ' }',
|
| 2782 | '',
|
| 2783 | ' LogEntryElementContainer.prototype = new LogItemContainerElement();',
|
| 2784 | '',
|
| 2785 | ' copyProperties(LogEntryElementContainer.prototype, {',
|
| 2786 | ' remove: function() {',
|
| 2787 | ' this.doRemove();',
|
| 2788 | ' },',
|
| 2789 | '',
|
| 2790 | ' doRemove: function() {',
|
| 2791 | ' this.mainDiv.parentNode.removeChild(this.mainDiv);',
|
| 2792 | ' this.mainDiv = null;',
|
| 2793 | ' this.contentElement = null;',
|
| 2794 | ' this.containerDomNode = null;',
|
| 2795 | ' },',
|
| 2796 | '',
|
| 2797 | ' setContent: function(content, wrappedContent) {',
|
| 2798 | ' if (content === this.formattedMessage) {',
|
| 2799 | ' this.contentElement.innerHTML = "";',
|
| 2800 | ' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',
|
| 2801 | ' } else {',
|
| 2802 | ' this.contentElement.innerHTML = content;',
|
| 2803 | ' }',
|
| 2804 | ' },',
|
| 2805 | '',
|
| 2806 | ' setSearchMatch: function(isMatch) {',
|
| 2807 | ' var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',
|
| 2808 | ' var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',
|
| 2809 | ' replaceClass(this.mainDiv, newCssClass, oldCssClass);',
|
| 2810 | ' },',
|
| 2811 | '',
|
| 2812 | ' clearSearch: function() {',
|
| 2813 | ' removeClass(this.mainDiv, "searchmatch");',
|
| 2814 | ' removeClass(this.mainDiv, "searchnonmatch");',
|
| 2815 | ' }',
|
| 2816 | ' });',
|
| 2817 | '',
|
| 2818 | ' /*----------------------------------------------------------------*/',
|
| 2819 | '',
|
| 2820 | ' function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',
|
| 2821 | ' this.logEntry = logEntry;',
|
| 2822 | ' this.containerDomNode = containerDomNode;',
|
| 2823 | ' this.mainDiv = document.createElement("div");',
|
| 2824 | ' this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',
|
| 2825 | ' this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',
|
| 2826 | ' this.contentElement = this.mainDiv;',
|
| 2827 | ' }',
|
| 2828 | '',
|
| 2829 | ' LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',
|
| 2830 | '',
|
| 2831 | ' LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',
|
| 2832 | ' if (content === this.formattedMessage) {',
|
| 2833 | ' this.contentElement.innerHTML = "";',
|
| 2834 | ' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',
|
| 2835 | ' } else {',
|
| 2836 | ' this.contentElement.innerHTML = wrappedContent;',
|
| 2837 | ' }',
|
| 2838 | ' };',
|
| 2839 | '',
|
| 2840 | ' /*----------------------------------------------------------------*/',
|
| 2841 | '',
|
| 2842 | ' function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',
|
| 2843 | ' this.logEntry = logEntry;',
|
| 2844 | ' this.containerDomNode = containerDomNode;',
|
| 2845 | ' this.mainDiv = document.createElement("div");',
|
| 2846 | ' this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',
|
| 2847 | ' this.pre = this.mainDiv.appendChild(document.createElement("pre"));',
|
| 2848 | ' this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',
|
| 2849 | ' this.pre.className = "unwrapped";',
|
| 2850 | ' this.contentElement = this.pre;',
|
| 2851 | ' }',
|
| 2852 | '',
|
| 2853 | ' LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',
|
| 2854 | '',
|
| 2855 | ' LogEntryUnwrappedElementContainer.prototype.remove = function() {',
|
| 2856 | ' this.doRemove();',
|
| 2857 | ' this.pre = null;',
|
| 2858 | ' };',
|
| 2859 | '',
|
| 2860 | ' /*----------------------------------------------------------------*/',
|
| 2861 | '',
|
| 2862 | ' function LogEntryMainElementContainer(logEntry, containerDomNode) {',
|
| 2863 | ' this.logEntry = logEntry;',
|
| 2864 | ' this.containerDomNode = containerDomNode;',
|
| 2865 | ' this.mainDiv = document.createElement("div");',
|
| 2866 | ' this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',
|
| 2867 | ' this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',
|
| 2868 | ' this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',
|
| 2869 | ' }',
|
| 2870 | '',
|
| 2871 | ' LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',
|
| 2872 | '',
|
| 2873 | ' /*----------------------------------------------------------------*/',
|
| 2874 | '',
|
| 2875 | ' function LogEntry(level, formattedMessage) {',
|
| 2876 | ' this.level = level;',
|
| 2877 | ' this.formattedMessage = formattedMessage;',
|
| 2878 | ' this.rendered = false;',
|
| 2879 | ' }',
|
| 2880 | '',
|
| 2881 | ' LogEntry.prototype = new LogItem();',
|
| 2882 | '',
|
| 2883 | ' copyProperties(LogEntry.prototype, {',
|
| 2884 | ' render: function() {',
|
| 2885 | ' var logEntry = this;',
|
| 2886 | ' var containerDomNode = this.group.contentDiv;',
|
| 2887 | '',
|
| 2888 | ' // Support for the CSS attribute white-space in IE for Windows is',
|
| 2889 | ' // non-existent pre version 6 and slightly odd in 6, so instead',
|
| 2890 | ' // use two different HTML elements',
|
| 2891 | ' if (isIe) {',
|
| 2892 | ' this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',
|
| 2893 | ' this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',
|
| 2894 | ' this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',
|
| 2895 | ' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',
|
| 2896 | ' } else {',
|
| 2897 | ' this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',
|
| 2898 | ' this.elementContainers = [this.mainElementContainer];',
|
| 2899 | ' }',
|
| 2900 | ' this.content = this.formattedMessage;',
|
| 2901 | ' this.rendered = true;',
|
| 2902 | ' },',
|
| 2903 | '',
|
| 2904 | ' setContent: function(content, wrappedContent) {',
|
| 2905 | ' if (content != this.content) {',
|
| 2906 | ' if (isIe && (content !== this.formattedMessage)) {',
|
| 2907 | ' content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',
|
| 2908 | ' }',
|
| 2909 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2910 | ' this.elementContainers[i].setContent(content, wrappedContent);',
|
| 2911 | ' }',
|
| 2912 | ' this.content = content;',
|
| 2913 | ' }',
|
| 2914 | ' },',
|
| 2915 | '',
|
| 2916 | ' getSearchMatches: function() {',
|
| 2917 | ' var matches = [];',
|
| 2918 | ' var i, len;',
|
| 2919 | ' if (isIe) {',
|
| 2920 | ' var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',
|
| 2921 | ' var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',
|
| 2922 | ' for (i = 0, len = unwrappedEls.length; i < len; i++) {',
|
| 2923 | ' matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',
|
| 2924 | ' }',
|
| 2925 | ' } else {',
|
| 2926 | ' var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',
|
| 2927 | ' for (i = 0, len = els.length; i < len; i++) {',
|
| 2928 | ' matches[i] = new Match(this.level, els[i]);',
|
| 2929 | ' }',
|
| 2930 | ' }',
|
| 2931 | ' return matches;',
|
| 2932 | ' },',
|
| 2933 | '',
|
| 2934 | ' setSearchMatch: function(isMatch) {',
|
| 2935 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2936 | ' this.elementContainers[i].setSearchMatch(isMatch);',
|
| 2937 | ' }',
|
| 2938 | ' },',
|
| 2939 | '',
|
| 2940 | ' clearSearch: function() {',
|
| 2941 | ' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',
|
| 2942 | ' this.elementContainers[i].clearSearch();',
|
| 2943 | ' }',
|
| 2944 | ' },',
|
| 2945 | '',
|
| 2946 | ' accept: function(visitor) {',
|
| 2947 | ' visitor.visitLogEntry(this);',
|
| 2948 | ' },',
|
| 2949 | '',
|
| 2950 | ' serialize: function(items) {',
|
| 2951 | ' items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',
|
| 2952 | ' }',
|
| 2953 | ' });',
|
| 2954 | '',
|
| 2955 | ' /*----------------------------------------------------------------*/',
|
| 2956 | '',
|
| 2957 | ' function LogItemVisitor() {',
|
| 2958 | ' }',
|
| 2959 | '',
|
| 2960 | ' LogItemVisitor.prototype = {',
|
| 2961 | ' visit: function(logItem) {',
|
| 2962 | ' },',
|
| 2963 | '',
|
| 2964 | ' visitParent: function(logItem) {',
|
| 2965 | ' if (logItem.group) {',
|
| 2966 | ' logItem.group.accept(this);',
|
| 2967 | ' }',
|
| 2968 | ' },',
|
| 2969 | '',
|
| 2970 | ' visitChildren: function(logItem) {',
|
| 2971 | ' for (var i = 0, len = logItem.children.length; i < len; i++) {',
|
| 2972 | ' logItem.children[i].accept(this);',
|
| 2973 | ' }',
|
| 2974 | ' },',
|
| 2975 | '',
|
| 2976 | ' visitLogEntry: function(logEntry) {',
|
| 2977 | ' this.visit(logEntry);',
|
| 2978 | ' },',
|
| 2979 | '',
|
| 2980 | ' visitSeparator: function(separator) {',
|
| 2981 | ' this.visit(separator);',
|
| 2982 | ' },',
|
| 2983 | '',
|
| 2984 | ' visitGroup: function(group) {',
|
| 2985 | ' this.visit(group);',
|
| 2986 | ' }',
|
| 2987 | ' };',
|
| 2988 | '',
|
| 2989 | ' /*----------------------------------------------------------------*/',
|
| 2990 | '',
|
| 2991 | ' function GroupFlattener() {',
|
| 2992 | ' this.logEntriesAndSeparators = [];',
|
| 2993 | ' }',
|
| 2994 | '',
|
| 2995 | ' GroupFlattener.prototype = new LogItemVisitor();',
|
| 2996 | '',
|
| 2997 | ' GroupFlattener.prototype.visitGroup = function(group) {',
|
| 2998 | ' this.visitChildren(group);',
|
| 2999 | ' };',
|
| 3000 | '',
|
| 3001 | ' GroupFlattener.prototype.visitLogEntry = function(logEntry) {',
|
| 3002 | ' this.logEntriesAndSeparators.push(logEntry);',
|
| 3003 | ' };',
|
| 3004 | '',
|
| 3005 | ' GroupFlattener.prototype.visitSeparator = function(separator) {',
|
| 3006 | ' this.logEntriesAndSeparators.push(separator);',
|
| 3007 | ' };',
|
| 3008 | '',
|
| 3009 | ' /*----------------------------------------------------------------*/',
|
| 3010 | '',
|
| 3011 | ' window.onload = function() {',
|
| 3012 | ' // Sort out document.domain',
|
| 3013 | ' if (location.search) {',
|
| 3014 | ' var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',
|
| 3015 | ' for (var i = 0, len = queryBits.length; i < len; i++) {',
|
| 3016 | ' nameValueBits = queryBits[i].split("=");',
|
| 3017 | ' if (nameValueBits[0] == "log4javascript_domain") {',
|
| 3018 | ' document.domain = nameValueBits[1];',
|
| 3019 | ' break;',
|
| 3020 | ' }',
|
| 3021 | ' }',
|
| 3022 | ' }',
|
| 3023 | '',
|
| 3024 | ' // Create DOM objects',
|
| 3025 | ' logMainContainer = $("log");',
|
| 3026 | ' if (isIePre7) {',
|
| 3027 | ' addClass(logMainContainer, "oldIe");',
|
| 3028 | ' }',
|
| 3029 | '',
|
| 3030 | ' rootGroup = new Group("root", true);',
|
| 3031 | ' rootGroup.render();',
|
| 3032 | ' currentGroup = rootGroup;',
|
| 3033 | ' ',
|
| 3034 | ' setCommandInputWidth();',
|
| 3035 | ' setLogContainerHeight();',
|
| 3036 | ' toggleLoggingEnabled();',
|
| 3037 | ' toggleSearchEnabled();',
|
| 3038 | ' toggleSearchFilter();',
|
| 3039 | ' toggleSearchHighlight();',
|
| 3040 | ' applyFilters();',
|
| 3041 | ' checkAllLevels();',
|
| 3042 | ' toggleWrap();',
|
| 3043 | ' toggleNewestAtTop();',
|
| 3044 | ' toggleScrollToLatest();',
|
| 3045 | ' renderQueuedLogItems();',
|
| 3046 | ' loaded = true;',
|
| 3047 | ' $("command").value = "";',
|
| 3048 | ' $("command").autocomplete = "off";',
|
| 3049 | ' $("command").onkeydown = function(evt) {',
|
| 3050 | ' evt = getEvent(evt);',
|
| 3051 | ' if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',
|
| 3052 | ' evalCommandLine();',
|
| 3053 | ' stopPropagation(evt);',
|
| 3054 | ' } else if (evt.keyCode == 27) { // Escape',
|
| 3055 | ' this.value = "";',
|
| 3056 | ' this.focus();',
|
| 3057 | ' } else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',
|
| 3058 | ' currentCommandIndex = Math.max(0, currentCommandIndex - 1);',
|
| 3059 | ' this.value = commandHistory[currentCommandIndex];',
|
| 3060 | ' moveCaretToEnd(this);',
|
| 3061 | ' } else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',
|
| 3062 | ' currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',
|
| 3063 | ' this.value = commandHistory[currentCommandIndex];',
|
| 3064 | ' moveCaretToEnd(this);',
|
| 3065 | ' }',
|
| 3066 | ' };',
|
| 3067 | '',
|
| 3068 | ' // Prevent the keypress moving the caret in Firefox',
|
| 3069 | ' $("command").onkeypress = function(evt) {',
|
| 3070 | ' evt = getEvent(evt);',
|
| 3071 | ' if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',
|
| 3072 | ' evt.preventDefault();',
|
| 3073 | ' }',
|
| 3074 | ' };',
|
| 3075 | '',
|
| 3076 | ' // Prevent the keyup event blurring the input in Opera',
|
| 3077 | ' $("command").onkeyup = function(evt) {',
|
| 3078 | ' evt = getEvent(evt);',
|
| 3079 | ' if (evt.keyCode == 27 && evt.preventDefault) { // Up',
|
| 3080 | ' evt.preventDefault();',
|
| 3081 | ' this.focus();',
|
| 3082 | ' }',
|
| 3083 | ' };',
|
| 3084 | '',
|
| 3085 | ' // Add document keyboard shortcuts',
|
| 3086 | ' document.onkeydown = function keyEventHandler(evt) {',
|
| 3087 | ' evt = getEvent(evt);',
|
| 3088 | ' switch (evt.keyCode) {',
|
| 3089 | ' case 69: // Ctrl + shift + E: re-execute last command',
|
| 3090 | ' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',
|
| 3091 | ' evalLastCommand();',
|
| 3092 | ' cancelKeyEvent(evt);',
|
| 3093 | ' return false;',
|
| 3094 | ' }',
|
| 3095 | ' break;',
|
| 3096 | ' case 75: // Ctrl + shift + K: focus search',
|
| 3097 | ' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',
|
| 3098 | ' focusSearch();',
|
| 3099 | ' cancelKeyEvent(evt);',
|
| 3100 | ' return false;',
|
| 3101 | ' }',
|
| 3102 | ' break;',
|
| 3103 | ' case 40: // Ctrl + shift + down arrow: focus command line',
|
| 3104 | ' case 76: // Ctrl + shift + L: focus command line',
|
| 3105 | ' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',
|
| 3106 | ' focusCommandLine();',
|
| 3107 | ' cancelKeyEvent(evt);',
|
| 3108 | ' return false;',
|
| 3109 | ' }',
|
| 3110 | ' break;',
|
| 3111 | ' }',
|
| 3112 | ' };',
|
| 3113 | '',
|
| 3114 | ' // Workaround to make sure log div starts at the correct size',
|
| 3115 | ' setTimeout(setLogContainerHeight, 20);',
|
| 3116 | '',
|
| 3117 | ' setShowCommandLine(showCommandLine);',
|
| 3118 | ' doSearch();',
|
| 3119 | ' };',
|
| 3120 | '',
|
| 3121 | ' window.onunload = function() {',
|
| 3122 | ' if (mainWindowExists()) {',
|
| 3123 | ' appender.unload();',
|
| 3124 | ' }',
|
| 3125 | ' appender = null;',
|
| 3126 | ' };',
|
| 3127 | '',
|
| 3128 | ' /*----------------------------------------------------------------*/',
|
| 3129 | '',
|
| 3130 | ' function toggleLoggingEnabled() {',
|
| 3131 | ' setLoggingEnabled($("enableLogging").checked);',
|
| 3132 | ' }',
|
| 3133 | '',
|
| 3134 | ' function setLoggingEnabled(enable) {',
|
| 3135 | ' loggingEnabled = enable;',
|
| 3136 | ' }',
|
| 3137 | '',
|
| 3138 | ' var appender = null;',
|
| 3139 | '',
|
| 3140 | ' function setAppender(appenderParam) {',
|
| 3141 | ' appender = appenderParam;',
|
| 3142 | ' }',
|
| 3143 | '',
|
| 3144 | ' function setShowCloseButton(showCloseButton) {',
|
| 3145 | ' $("closeButton").style.display = showCloseButton ? "inline" : "none";',
|
| 3146 | ' }',
|
| 3147 | '',
|
| 3148 | ' function setShowHideButton(showHideButton) {',
|
| 3149 | ' $("hideButton").style.display = showHideButton ? "inline" : "none";',
|
| 3150 | ' }',
|
| 3151 | '',
|
| 3152 | ' var newestAtTop = false;',
|
| 3153 | '',
|
| 3154 | ' /*----------------------------------------------------------------*/',
|
| 3155 | '',
|
| 3156 | ' function LogItemContentReverser() {',
|
| 3157 | ' }',
|
| 3158 | ' ',
|
| 3159 | ' LogItemContentReverser.prototype = new LogItemVisitor();',
|
| 3160 | ' ',
|
| 3161 | ' LogItemContentReverser.prototype.visitGroup = function(group) {',
|
| 3162 | ' group.reverseChildren();',
|
| 3163 | ' this.visitChildren(group);',
|
| 3164 | ' };',
|
| 3165 | '',
|
| 3166 | ' /*----------------------------------------------------------------*/',
|
| 3167 | '',
|
| 3168 | ' function setNewestAtTop(isNewestAtTop) {',
|
| 3169 | ' var oldNewestAtTop = newestAtTop;',
|
| 3170 | ' var i, iLen, j, jLen;',
|
| 3171 | ' newestAtTop = Boolean(isNewestAtTop);',
|
| 3172 | ' if (oldNewestAtTop != newestAtTop) {',
|
| 3173 | ' var visitor = new LogItemContentReverser();',
|
| 3174 | ' rootGroup.accept(visitor);',
|
| 3175 | '',
|
| 3176 | ' // Reassemble the matches array',
|
| 3177 | ' if (currentSearch) {',
|
| 3178 | ' var currentMatch = currentSearch.matches[currentMatchIndex];',
|
| 3179 | ' var matchIndex = 0;',
|
| 3180 | ' var matches = [];',
|
| 3181 | ' var actOnLogEntry = function(logEntry) {',
|
| 3182 | ' var logEntryMatches = logEntry.getSearchMatches();',
|
| 3183 | ' for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',
|
| 3184 | ' matches[matchIndex] = logEntryMatches[j];',
|
| 3185 | ' if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',
|
| 3186 | ' currentMatchIndex = matchIndex;',
|
| 3187 | ' }',
|
| 3188 | ' matchIndex++;',
|
| 3189 | ' }',
|
| 3190 | ' };',
|
| 3191 | ' if (newestAtTop) {',
|
| 3192 | ' for (i = logEntries.length - 1; i >= 0; i--) {',
|
| 3193 | ' actOnLogEntry(logEntries[i]);',
|
| 3194 | ' }',
|
| 3195 | ' } else {',
|
| 3196 | ' for (i = 0, iLen = logEntries.length; i < iLen; i++) {',
|
| 3197 | ' actOnLogEntry(logEntries[i]);',
|
| 3198 | ' }',
|
| 3199 | ' }',
|
| 3200 | ' currentSearch.matches = matches;',
|
| 3201 | ' if (currentMatch) {',
|
| 3202 | ' currentMatch.setCurrent();',
|
| 3203 | ' }',
|
| 3204 | ' } else if (scrollToLatest) {',
|
| 3205 | ' doScrollToLatest();',
|
| 3206 | ' }',
|
| 3207 | ' }',
|
| 3208 | ' $("newestAtTop").checked = isNewestAtTop;',
|
| 3209 | ' }',
|
| 3210 | '',
|
| 3211 | ' function toggleNewestAtTop() {',
|
| 3212 | ' var isNewestAtTop = $("newestAtTop").checked;',
|
| 3213 | ' setNewestAtTop(isNewestAtTop);',
|
| 3214 | ' }',
|
| 3215 | '',
|
| 3216 | ' var scrollToLatest = true;',
|
| 3217 | '',
|
| 3218 | ' function setScrollToLatest(isScrollToLatest) {',
|
| 3219 | ' scrollToLatest = isScrollToLatest;',
|
| 3220 | ' if (scrollToLatest) {',
|
| 3221 | ' doScrollToLatest();',
|
| 3222 | ' }',
|
| 3223 | ' $("scrollToLatest").checked = isScrollToLatest;',
|
| 3224 | ' }',
|
| 3225 | '',
|
| 3226 | ' function toggleScrollToLatest() {',
|
| 3227 | ' var isScrollToLatest = $("scrollToLatest").checked;',
|
| 3228 | ' setScrollToLatest(isScrollToLatest);',
|
| 3229 | ' }',
|
| 3230 | '',
|
| 3231 | ' function doScrollToLatest() {',
|
| 3232 | ' var l = logMainContainer;',
|
| 3233 | ' if (typeof l.scrollTop != "undefined") {',
|
| 3234 | ' if (newestAtTop) {',
|
| 3235 | ' l.scrollTop = 0;',
|
| 3236 | ' } else {',
|
| 3237 | ' var latestLogEntry = l.lastChild;',
|
| 3238 | ' if (latestLogEntry) {',
|
| 3239 | ' l.scrollTop = l.scrollHeight;',
|
| 3240 | ' }',
|
| 3241 | ' }',
|
| 3242 | ' }',
|
| 3243 | ' }',
|
| 3244 | '',
|
| 3245 | ' var closeIfOpenerCloses = true;',
|
| 3246 | '',
|
| 3247 | ' function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',
|
| 3248 | ' closeIfOpenerCloses = isCloseIfOpenerCloses;',
|
| 3249 | ' }',
|
| 3250 | '',
|
| 3251 | ' var maxMessages = null;',
|
| 3252 | '',
|
| 3253 | ' function setMaxMessages(max) {',
|
| 3254 | ' maxMessages = max;',
|
| 3255 | ' pruneLogEntries();',
|
| 3256 | ' }',
|
| 3257 | '',
|
| 3258 | ' var showCommandLine = false;',
|
| 3259 | '',
|
| 3260 | ' function setShowCommandLine(isShowCommandLine) {',
|
| 3261 | ' showCommandLine = isShowCommandLine;',
|
| 3262 | ' if (loaded) {',
|
| 3263 | ' $("commandLine").style.display = showCommandLine ? "block" : "none";',
|
| 3264 | ' setCommandInputWidth();',
|
| 3265 | ' setLogContainerHeight();',
|
| 3266 | ' }',
|
| 3267 | ' }',
|
| 3268 | '',
|
| 3269 | ' function focusCommandLine() {',
|
| 3270 | ' if (loaded) {',
|
| 3271 | ' $("command").focus();',
|
| 3272 | ' }',
|
| 3273 | ' }',
|
| 3274 | '',
|
| 3275 | ' function focusSearch() {',
|
| 3276 | ' if (loaded) {',
|
| 3277 | ' $("searchBox").focus();',
|
| 3278 | ' }',
|
| 3279 | ' }',
|
| 3280 | '',
|
| 3281 | ' function getLogItems() {',
|
| 3282 | ' var items = [];',
|
| 3283 | ' for (var i = 0, len = logItems.length; i < len; i++) {',
|
| 3284 | ' logItems[i].serialize(items);',
|
| 3285 | ' }',
|
| 3286 | ' return items;',
|
| 3287 | ' }',
|
| 3288 | '',
|
| 3289 | ' function setLogItems(items) {',
|
| 3290 | ' var loggingReallyEnabled = loggingEnabled;',
|
| 3291 | ' // Temporarily turn logging on',
|
| 3292 | ' loggingEnabled = true;',
|
| 3293 | ' for (var i = 0, len = items.length; i < len; i++) {',
|
| 3294 | ' switch (items[i][0]) {',
|
| 3295 | ' case LogItem.serializedItemKeys.LOG_ENTRY:',
|
| 3296 | ' log(items[i][1], items[i][2]);',
|
| 3297 | ' break;',
|
| 3298 | ' case LogItem.serializedItemKeys.GROUP_START:',
|
| 3299 | ' group(items[i][1]);',
|
| 3300 | ' break;',
|
| 3301 | ' case LogItem.serializedItemKeys.GROUP_END:',
|
| 3302 | ' groupEnd();',
|
| 3303 | ' break;',
|
| 3304 | ' }',
|
| 3305 | ' }',
|
| 3306 | ' loggingEnabled = loggingReallyEnabled;',
|
| 3307 | ' }',
|
| 3308 | '',
|
| 3309 | ' function log(logLevel, formattedMessage) {',
|
| 3310 | ' if (loggingEnabled) {',
|
| 3311 | ' var logEntry = new LogEntry(logLevel, formattedMessage);',
|
| 3312 | ' logEntries.push(logEntry);',
|
| 3313 | ' logEntriesAndSeparators.push(logEntry);',
|
| 3314 | ' logItems.push(logEntry);',
|
| 3315 | ' currentGroup.addChild(logEntry);',
|
| 3316 | ' if (loaded) {',
|
| 3317 | ' if (logQueuedEventsTimer !== null) {',
|
| 3318 | ' clearTimeout(logQueuedEventsTimer);',
|
| 3319 | ' }',
|
| 3320 | ' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',
|
| 3321 | ' unrenderedLogItemsExist = true;',
|
| 3322 | ' }',
|
| 3323 | ' }',
|
| 3324 | ' }',
|
| 3325 | '',
|
| 3326 | ' function renderQueuedLogItems() {',
|
| 3327 | ' logQueuedEventsTimer = null;',
|
| 3328 | ' var pruned = pruneLogEntries();',
|
| 3329 | '',
|
| 3330 | ' // Render any unrendered log entries and apply the current search to them',
|
| 3331 | ' var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',
|
| 3332 | ' for (var i = 0, len = logItems.length; i < len; i++) {',
|
| 3333 | ' if (!logItems[i].rendered) {',
|
| 3334 | ' logItems[i].render();',
|
| 3335 | ' logItems[i].appendToLog();',
|
| 3336 | ' if (currentSearch && (logItems[i] instanceof LogEntry)) {',
|
| 3337 | ' currentSearch.applyTo(logItems[i]);',
|
| 3338 | ' }',
|
| 3339 | ' }',
|
| 3340 | ' }',
|
| 3341 | ' if (currentSearch) {',
|
| 3342 | ' if (pruned) {',
|
| 3343 | ' if (currentSearch.hasVisibleMatches()) {',
|
| 3344 | ' if (currentMatchIndex === null) {',
|
| 3345 | ' setCurrentMatchIndex(0);',
|
| 3346 | ' }',
|
| 3347 | ' displayMatches();',
|
| 3348 | ' } else {',
|
| 3349 | ' displayNoMatches();',
|
| 3350 | ' }',
|
| 3351 | ' } else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',
|
| 3352 | ' setCurrentMatchIndex(0);',
|
| 3353 | ' displayMatches();',
|
| 3354 | ' }',
|
| 3355 | ' }',
|
| 3356 | ' if (scrollToLatest) {',
|
| 3357 | ' doScrollToLatest();',
|
| 3358 | ' }',
|
| 3359 | ' unrenderedLogItemsExist = false;',
|
| 3360 | ' }',
|
| 3361 | '',
|
| 3362 | ' function pruneLogEntries() {',
|
| 3363 | ' if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',
|
| 3364 | ' var numberToDelete = logEntriesAndSeparators.length - maxMessages;',
|
| 3365 | ' var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',
|
| 3366 | ' if (currentSearch) {',
|
| 3367 | ' currentSearch.removeMatches(prunedLogEntries);',
|
| 3368 | ' }',
|
| 3369 | ' var group;',
|
| 3370 | ' for (var i = 0; i < numberToDelete; i++) {',
|
| 3371 | ' group = logEntriesAndSeparators[i].group;',
|
| 3372 | ' array_remove(logItems, logEntriesAndSeparators[i]);',
|
| 3373 | ' array_remove(logEntries, logEntriesAndSeparators[i]);',
|
| 3374 | ' logEntriesAndSeparators[i].remove(true, true);',
|
| 3375 | ' if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',
|
| 3376 | ' array_remove(logItems, group);',
|
| 3377 | ' group.remove(true, true);',
|
| 3378 | ' }',
|
| 3379 | ' }',
|
| 3380 | ' logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',
|
| 3381 | ' return true;',
|
| 3382 | ' }',
|
| 3383 | ' return false;',
|
| 3384 | ' }',
|
| 3385 | '',
|
| 3386 | ' function group(name, startExpanded) {',
|
| 3387 | ' if (loggingEnabled) {',
|
| 3388 | ' initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',
|
| 3389 | ' var newGroup = new Group(name, false, initiallyExpanded);',
|
| 3390 | ' currentGroup.addChild(newGroup);',
|
| 3391 | ' currentGroup = newGroup;',
|
| 3392 | ' logItems.push(newGroup);',
|
| 3393 | ' if (loaded) {',
|
| 3394 | ' if (logQueuedEventsTimer !== null) {',
|
| 3395 | ' clearTimeout(logQueuedEventsTimer);',
|
| 3396 | ' }',
|
| 3397 | ' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',
|
| 3398 | ' unrenderedLogItemsExist = true;',
|
| 3399 | ' }',
|
| 3400 | ' }',
|
| 3401 | ' }',
|
| 3402 | '',
|
| 3403 | ' function groupEnd() {',
|
| 3404 | ' currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',
|
| 3405 | ' }',
|
| 3406 | '',
|
| 3407 | ' function mainPageReloaded() {',
|
| 3408 | ' currentGroup = rootGroup;',
|
| 3409 | ' var separator = new Separator();',
|
| 3410 | ' logEntriesAndSeparators.push(separator);',
|
| 3411 | ' logItems.push(separator);',
|
| 3412 | ' currentGroup.addChild(separator);',
|
| 3413 | ' }',
|
| 3414 | '',
|
| 3415 | ' function closeWindow() {',
|
| 3416 | ' if (appender && mainWindowExists()) {',
|
| 3417 | ' appender.close(true);',
|
| 3418 | ' } else {',
|
| 3419 | ' window.close();',
|
| 3420 | ' }',
|
| 3421 | ' }',
|
| 3422 | '',
|
| 3423 | ' function hide() {',
|
| 3424 | ' if (appender && mainWindowExists()) {',
|
| 3425 | ' appender.hide();',
|
| 3426 | ' }',
|
| 3427 | ' }',
|
| 3428 | '',
|
| 3429 | ' var mainWindow = window;',
|
| 3430 | ' var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',
|
| 3431 | '',
|
| 3432 | ' function setMainWindow(win) {',
|
| 3433 | ' mainWindow = win;',
|
| 3434 | ' mainWindow[windowId] = window;',
|
| 3435 | ' // If this is a pop-up, poll the opener to see if it\'s closed',
|
| 3436 | ' if (opener && closeIfOpenerCloses) {',
|
| 3437 | ' pollOpener();',
|
| 3438 | ' }',
|
| 3439 | ' }',
|
| 3440 | '',
|
| 3441 | ' function pollOpener() {',
|
| 3442 | ' if (closeIfOpenerCloses) {',
|
| 3443 | ' if (mainWindowExists()) {',
|
| 3444 | ' setTimeout(pollOpener, 500);',
|
| 3445 | ' } else {',
|
| 3446 | ' closeWindow();',
|
| 3447 | ' }',
|
| 3448 | ' }',
|
| 3449 | ' }',
|
| 3450 | '',
|
| 3451 | ' function mainWindowExists() {',
|
| 3452 | ' try {',
|
| 3453 | ' return (mainWindow && !mainWindow.closed &&',
|
| 3454 | ' mainWindow[windowId] == window);',
|
| 3455 | ' } catch (ex) {}',
|
| 3456 | ' return false;',
|
| 3457 | ' }',
|
| 3458 | '',
|
| 3459 | ' var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',
|
| 3460 | '',
|
| 3461 | ' function getCheckBox(logLevel) {',
|
| 3462 | ' return $("switch_" + logLevel);',
|
| 3463 | ' }',
|
| 3464 | '',
|
| 3465 | ' function getIeWrappedLogContainer() {',
|
| 3466 | ' return $("log_wrapped");',
|
| 3467 | ' }',
|
| 3468 | '',
|
| 3469 | ' function getIeUnwrappedLogContainer() {',
|
| 3470 | ' return $("log_unwrapped");',
|
| 3471 | ' }',
|
| 3472 | '',
|
| 3473 | ' function applyFilters() {',
|
| 3474 | ' for (var i = 0; i < logLevels.length; i++) {',
|
| 3475 | ' if (getCheckBox(logLevels[i]).checked) {',
|
| 3476 | ' addClass(logMainContainer, logLevels[i]);',
|
| 3477 | ' } else {',
|
| 3478 | ' removeClass(logMainContainer, logLevels[i]);',
|
| 3479 | ' }',
|
| 3480 | ' }',
|
| 3481 | ' updateSearchFromFilters();',
|
| 3482 | ' }',
|
| 3483 | '',
|
| 3484 | ' function toggleAllLevels() {',
|
| 3485 | ' var turnOn = $("switch_ALL").checked;',
|
| 3486 | ' for (var i = 0; i < logLevels.length; i++) {',
|
| 3487 | ' getCheckBox(logLevels[i]).checked = turnOn;',
|
| 3488 | ' if (turnOn) {',
|
| 3489 | ' addClass(logMainContainer, logLevels[i]);',
|
| 3490 | ' } else {',
|
| 3491 | ' removeClass(logMainContainer, logLevels[i]);',
|
| 3492 | ' }',
|
| 3493 | ' }',
|
| 3494 | ' }',
|
| 3495 | '',
|
| 3496 | ' function checkAllLevels() {',
|
| 3497 | ' for (var i = 0; i < logLevels.length; i++) {',
|
| 3498 | ' if (!getCheckBox(logLevels[i]).checked) {',
|
| 3499 | ' getCheckBox("ALL").checked = false;',
|
| 3500 | ' return;',
|
| 3501 | ' }',
|
| 3502 | ' }',
|
| 3503 | ' getCheckBox("ALL").checked = true;',
|
| 3504 | ' }',
|
| 3505 | '',
|
| 3506 | ' function clearLog() {',
|
| 3507 | ' rootGroup.clear();',
|
| 3508 | ' currentGroup = rootGroup;',
|
| 3509 | ' logEntries = [];',
|
| 3510 | ' logItems = [];',
|
| 3511 | ' logEntriesAndSeparators = [];',
|
| 3512 | ' doSearch();',
|
| 3513 | ' }',
|
| 3514 | '',
|
| 3515 | ' function toggleWrap() {',
|
| 3516 | ' var enable = $("wrap").checked;',
|
| 3517 | ' if (enable) {',
|
| 3518 | ' addClass(logMainContainer, "wrap");',
|
| 3519 | ' } else {',
|
| 3520 | ' removeClass(logMainContainer, "wrap");',
|
| 3521 | ' }',
|
| 3522 | ' refreshCurrentMatch();',
|
| 3523 | ' }',
|
| 3524 | '',
|
| 3525 | ' /* ------------------------------------------------------------------- */',
|
| 3526 | '',
|
| 3527 | ' // Search',
|
| 3528 | '',
|
| 3529 | ' var searchTimer = null;',
|
| 3530 | '',
|
| 3531 | ' function scheduleSearch() {',
|
| 3532 | ' try {',
|
| 3533 | ' clearTimeout(searchTimer);',
|
| 3534 | ' } catch (ex) {',
|
| 3535 | ' // Do nothing',
|
| 3536 | ' }',
|
| 3537 | ' searchTimer = setTimeout(doSearch, 500);',
|
| 3538 | ' }',
|
| 3539 | '',
|
| 3540 | ' function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',
|
| 3541 | ' this.searchTerm = searchTerm;',
|
| 3542 | ' this.isRegex = isRegex;',
|
| 3543 | ' this.searchRegex = searchRegex;',
|
| 3544 | ' this.isCaseSensitive = isCaseSensitive;',
|
| 3545 | ' this.matches = [];',
|
| 3546 | ' }',
|
| 3547 | '',
|
| 3548 | ' Search.prototype = {',
|
| 3549 | ' hasMatches: function() {',
|
| 3550 | ' return this.matches.length > 0;',
|
| 3551 | ' },',
|
| 3552 | '',
|
| 3553 | ' hasVisibleMatches: function() {',
|
| 3554 | ' if (this.hasMatches()) {',
|
| 3555 | ' for (var i = 0; i < this.matches.length; i++) {',
|
| 3556 | ' if (this.matches[i].isVisible()) {',
|
| 3557 | ' return true;',
|
| 3558 | ' }',
|
| 3559 | ' }',
|
| 3560 | ' }',
|
| 3561 | ' return false;',
|
| 3562 | ' },',
|
| 3563 | '',
|
| 3564 | ' match: function(logEntry) {',
|
| 3565 | ' var entryText = String(logEntry.formattedMessage);',
|
| 3566 | ' var matchesSearch = false;',
|
| 3567 | ' if (this.isRegex) {',
|
| 3568 | ' matchesSearch = this.searchRegex.test(entryText);',
|
| 3569 | ' } else if (this.isCaseSensitive) {',
|
| 3570 | ' matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',
|
| 3571 | ' } else {',
|
| 3572 | ' matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',
|
| 3573 | ' }',
|
| 3574 | ' return matchesSearch;',
|
| 3575 | ' },',
|
| 3576 | '',
|
| 3577 | ' getNextVisibleMatchIndex: function() {',
|
| 3578 | ' for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',
|
| 3579 | ' if (this.matches[i].isVisible()) {',
|
| 3580 | ' return i;',
|
| 3581 | ' }',
|
| 3582 | ' }',
|
| 3583 | ' // Start again from the first match',
|
| 3584 | ' for (i = 0; i <= currentMatchIndex; i++) {',
|
| 3585 | ' if (this.matches[i].isVisible()) {',
|
| 3586 | ' return i;',
|
| 3587 | ' }',
|
| 3588 | ' }',
|
| 3589 | ' return -1;',
|
| 3590 | ' },',
|
| 3591 | '',
|
| 3592 | ' getPreviousVisibleMatchIndex: function() {',
|
| 3593 | ' for (var i = currentMatchIndex - 1; i >= 0; i--) {',
|
| 3594 | ' if (this.matches[i].isVisible()) {',
|
| 3595 | ' return i;',
|
| 3596 | ' }',
|
| 3597 | ' }',
|
| 3598 | ' // Start again from the last match',
|
| 3599 | ' for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',
|
| 3600 | ' if (this.matches[i].isVisible()) {',
|
| 3601 | ' return i;',
|
| 3602 | ' }',
|
| 3603 | ' }',
|
| 3604 | ' return -1;',
|
| 3605 | ' },',
|
| 3606 | '',
|
| 3607 | ' applyTo: function(logEntry) {',
|
| 3608 | ' var doesMatch = this.match(logEntry);',
|
| 3609 | ' if (doesMatch) {',
|
| 3610 | ' logEntry.group.expand();',
|
| 3611 | ' logEntry.setSearchMatch(true);',
|
| 3612 | ' var logEntryContent;',
|
| 3613 | ' var wrappedLogEntryContent;',
|
| 3614 | ' var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',
|
| 3615 | ' var searchTermReplacementEndTag = "<" + "/span>";',
|
| 3616 | ' var preTagName = isIe ? "pre" : "span";',
|
| 3617 | ' var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',
|
| 3618 | ' var preEndTag = "<" + "/" + preTagName + ">";',
|
| 3619 | ' var startIndex = 0;',
|
| 3620 | ' var searchIndex, matchedText, textBeforeMatch;',
|
| 3621 | ' if (this.isRegex) {',
|
| 3622 | ' var flags = this.isCaseSensitive ? "g" : "gi";',
|
| 3623 | ' var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',
|
| 3624 | '',
|
| 3625 | ' // Replace the search term with temporary tokens for the start and end tags',
|
| 3626 | ' var rnd = ("" + Math.random()).substr(2);',
|
| 3627 | ' var startToken = "%%s" + rnd + "%%";',
|
| 3628 | ' var endToken = "%%e" + rnd + "%%";',
|
| 3629 | ' logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',
|
| 3630 | '',
|
| 3631 | ' // Escape the HTML to get rid of angle brackets',
|
| 3632 | ' logEntryContent = escapeHtml(logEntryContent);',
|
| 3633 | '',
|
| 3634 | ' // Substitute the proper HTML back in for the search match',
|
| 3635 | ' var result;',
|
| 3636 | ' var searchString = logEntryContent;',
|
| 3637 | ' logEntryContent = "";',
|
| 3638 | ' wrappedLogEntryContent = "";',
|
| 3639 | ' while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',
|
| 3640 | ' var endTokenIndex = searchString.indexOf(endToken, searchIndex);',
|
| 3641 | ' matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',
|
| 3642 | ' textBeforeMatch = searchString.substring(startIndex, searchIndex);',
|
| 3643 | ' logEntryContent += preStartTag + textBeforeMatch + preEndTag;',
|
| 3644 | ' logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',
|
| 3645 | ' preEndTag + searchTermReplacementEndTag;',
|
| 3646 | ' if (isIe) {',
|
| 3647 | ' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',
|
| 3648 | ' matchedText + searchTermReplacementEndTag;',
|
| 3649 | ' }',
|
| 3650 | ' startIndex = endTokenIndex + endToken.length;',
|
| 3651 | ' }',
|
| 3652 | ' logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',
|
| 3653 | ' if (isIe) {',
|
| 3654 | ' wrappedLogEntryContent += searchString.substr(startIndex);',
|
| 3655 | ' }',
|
| 3656 | ' } else {',
|
| 3657 | ' logEntryContent = "";',
|
| 3658 | ' wrappedLogEntryContent = "";',
|
| 3659 | ' var searchTermReplacementLength = searchTermReplacementStartTag.length +',
|
| 3660 | ' this.searchTerm.length + searchTermReplacementEndTag.length;',
|
| 3661 | ' var searchTermLength = this.searchTerm.length;',
|
| 3662 | ' var searchTermLowerCase = this.searchTerm.toLowerCase();',
|
| 3663 | ' var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',
|
| 3664 | ' while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',
|
| 3665 | ' matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',
|
| 3666 | ' textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',
|
| 3667 | ' var searchTermReplacement = searchTermReplacementStartTag +',
|
| 3668 | ' preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',
|
| 3669 | ' logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',
|
| 3670 | ' if (isIe) {',
|
| 3671 | ' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',
|
| 3672 | ' matchedText + searchTermReplacementEndTag;',
|
| 3673 | ' }',
|
| 3674 | ' startIndex = searchIndex + searchTermLength;',
|
| 3675 | ' }',
|
| 3676 | ' var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',
|
| 3677 | ' logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',
|
| 3678 | ' if (isIe) {',
|
| 3679 | ' wrappedLogEntryContent += textAfterLastMatch;',
|
| 3680 | ' }',
|
| 3681 | ' }',
|
| 3682 | ' logEntry.setContent(logEntryContent, wrappedLogEntryContent);',
|
| 3683 | ' var logEntryMatches = logEntry.getSearchMatches();',
|
| 3684 | ' this.matches = this.matches.concat(logEntryMatches);',
|
| 3685 | ' } else {',
|
| 3686 | ' logEntry.setSearchMatch(false);',
|
| 3687 | ' logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',
|
| 3688 | ' }',
|
| 3689 | ' return doesMatch;',
|
| 3690 | ' },',
|
| 3691 | '',
|
| 3692 | ' removeMatches: function(logEntries) {',
|
| 3693 | ' var matchesToRemoveCount = 0;',
|
| 3694 | ' var currentMatchRemoved = false;',
|
| 3695 | ' var matchesToRemove = [];',
|
| 3696 | ' var i, iLen, j, jLen;',
|
| 3697 | '',
|
| 3698 | ' // Establish the list of matches to be removed',
|
| 3699 | ' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',
|
| 3700 | ' for (j = 0, jLen = logEntries.length; j < jLen; j++) {',
|
| 3701 | ' if (this.matches[i].belongsTo(logEntries[j])) {',
|
| 3702 | ' matchesToRemove.push(this.matches[i]);',
|
| 3703 | ' if (i === currentMatchIndex) {',
|
| 3704 | ' currentMatchRemoved = true;',
|
| 3705 | ' }',
|
| 3706 | ' }',
|
| 3707 | ' }',
|
| 3708 | ' }',
|
| 3709 | '',
|
| 3710 | ' // Set the new current match index if the current match has been deleted',
|
| 3711 | ' // This will be the first match that appears after the first log entry being',
|
| 3712 | ' // deleted, if one exists; otherwise, it\'s the first match overall',
|
| 3713 | ' var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',
|
| 3714 | ' if (currentMatchRemoved) {',
|
| 3715 | ' for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',
|
| 3716 | ' if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',
|
| 3717 | ' newMatch = this.matches[i];',
|
| 3718 | ' break;',
|
| 3719 | ' }',
|
| 3720 | ' }',
|
| 3721 | ' }',
|
| 3722 | '',
|
| 3723 | ' // Remove the matches',
|
| 3724 | ' for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',
|
| 3725 | ' array_remove(this.matches, matchesToRemove[i]);',
|
| 3726 | ' matchesToRemove[i].remove();',
|
| 3727 | ' }',
|
| 3728 | '',
|
| 3729 | ' // Set the new match, if one exists',
|
| 3730 | ' if (this.hasVisibleMatches()) {',
|
| 3731 | ' if (newMatch === null) {',
|
| 3732 | ' setCurrentMatchIndex(0);',
|
| 3733 | ' } else {',
|
| 3734 | ' // Get the index of the new match',
|
| 3735 | ' var newMatchIndex = 0;',
|
| 3736 | ' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',
|
| 3737 | ' if (newMatch === this.matches[i]) {',
|
| 3738 | ' newMatchIndex = i;',
|
| 3739 | ' break;',
|
| 3740 | ' }',
|
| 3741 | ' }',
|
| 3742 | ' setCurrentMatchIndex(newMatchIndex);',
|
| 3743 | ' }',
|
| 3744 | ' } else {',
|
| 3745 | ' currentMatchIndex = null;',
|
| 3746 | ' displayNoMatches();',
|
| 3747 | ' }',
|
| 3748 | ' }',
|
| 3749 | ' };',
|
| 3750 | '',
|
| 3751 | ' function getPageOffsetTop(el, container) {',
|
| 3752 | ' var currentEl = el;',
|
| 3753 | ' var y = 0;',
|
| 3754 | ' while (currentEl && currentEl != container) {',
|
| 3755 | ' y += currentEl.offsetTop;',
|
| 3756 | ' currentEl = currentEl.offsetParent;',
|
| 3757 | ' }',
|
| 3758 | ' return y;',
|
| 3759 | ' }',
|
| 3760 | '',
|
| 3761 | ' function scrollIntoView(el) {',
|
| 3762 | ' var logContainer = logMainContainer;',
|
| 3763 | ' // Check if the whole width of the element is visible and centre if not',
|
| 3764 | ' if (!$("wrap").checked) {',
|
| 3765 | ' var logContainerLeft = logContainer.scrollLeft;',
|
| 3766 | ' var logContainerRight = logContainerLeft + logContainer.offsetWidth;',
|
| 3767 | ' var elLeft = el.offsetLeft;',
|
| 3768 | ' var elRight = elLeft + el.offsetWidth;',
|
| 3769 | ' if (elLeft < logContainerLeft || elRight > logContainerRight) {',
|
| 3770 | ' logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',
|
| 3771 | ' }',
|
| 3772 | ' }',
|
| 3773 | ' // Check if the whole height of the element is visible and centre if not',
|
| 3774 | ' var logContainerTop = logContainer.scrollTop;',
|
| 3775 | ' var logContainerBottom = logContainerTop + logContainer.offsetHeight;',
|
| 3776 | ' var elTop = getPageOffsetTop(el) - getToolBarsHeight();',
|
| 3777 | ' var elBottom = elTop + el.offsetHeight;',
|
| 3778 | ' if (elTop < logContainerTop || elBottom > logContainerBottom) {',
|
| 3779 | ' logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',
|
| 3780 | ' }',
|
| 3781 | ' }',
|
| 3782 | '',
|
| 3783 | ' function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',
|
| 3784 | ' this.logEntryLevel = logEntryLevel;',
|
| 3785 | ' this.spanInMainDiv = spanInMainDiv;',
|
| 3786 | ' if (isIe) {',
|
| 3787 | ' this.spanInUnwrappedPre = spanInUnwrappedPre;',
|
| 3788 | ' this.spanInWrappedDiv = spanInWrappedDiv;',
|
| 3789 | ' }',
|
| 3790 | ' this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',
|
| 3791 | ' }',
|
| 3792 | '',
|
| 3793 | ' Match.prototype = {',
|
| 3794 | ' equals: function(match) {',
|
| 3795 | ' return this.mainSpan === match.mainSpan;',
|
| 3796 | ' },',
|
| 3797 | '',
|
| 3798 | ' setCurrent: function() {',
|
| 3799 | ' if (isIe) {',
|
| 3800 | ' addClass(this.spanInUnwrappedPre, "currentmatch");',
|
| 3801 | ' addClass(this.spanInWrappedDiv, "currentmatch");',
|
| 3802 | ' // Scroll the visible one into view',
|
| 3803 | ' var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',
|
| 3804 | ' scrollIntoView(elementToScroll);',
|
| 3805 | ' } else {',
|
| 3806 | ' addClass(this.spanInMainDiv, "currentmatch");',
|
| 3807 | ' scrollIntoView(this.spanInMainDiv);',
|
| 3808 | ' }',
|
| 3809 | ' },',
|
| 3810 | '',
|
| 3811 | ' belongsTo: function(logEntry) {',
|
| 3812 | ' if (isIe) {',
|
| 3813 | ' return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',
|
| 3814 | ' } else {',
|
| 3815 | ' return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',
|
| 3816 | ' }',
|
| 3817 | ' },',
|
| 3818 | '',
|
| 3819 | ' setNotCurrent: function() {',
|
| 3820 | ' if (isIe) {',
|
| 3821 | ' removeClass(this.spanInUnwrappedPre, "currentmatch");',
|
| 3822 | ' removeClass(this.spanInWrappedDiv, "currentmatch");',
|
| 3823 | ' } else {',
|
| 3824 | ' removeClass(this.spanInMainDiv, "currentmatch");',
|
| 3825 | ' }',
|
| 3826 | ' },',
|
| 3827 | '',
|
| 3828 | ' isOrphan: function() {',
|
| 3829 | ' return isOrphan(this.mainSpan);',
|
| 3830 | ' },',
|
| 3831 | '',
|
| 3832 | ' isVisible: function() {',
|
| 3833 | ' return getCheckBox(this.logEntryLevel).checked;',
|
| 3834 | ' },',
|
| 3835 | '',
|
| 3836 | ' remove: function() {',
|
| 3837 | ' if (isIe) {',
|
| 3838 | ' this.spanInUnwrappedPre = null;',
|
| 3839 | ' this.spanInWrappedDiv = null;',
|
| 3840 | ' } else {',
|
| 3841 | ' this.spanInMainDiv = null;',
|
| 3842 | ' }',
|
| 3843 | ' }',
|
| 3844 | ' };',
|
| 3845 | '',
|
| 3846 | ' var currentSearch = null;',
|
| 3847 | ' var currentMatchIndex = null;',
|
| 3848 | '',
|
| 3849 | ' function doSearch() {',
|
| 3850 | ' var searchBox = $("searchBox");',
|
| 3851 | ' var searchTerm = searchBox.value;',
|
| 3852 | ' var isRegex = $("searchRegex").checked;',
|
| 3853 | ' var isCaseSensitive = $("searchCaseSensitive").checked;',
|
| 3854 | ' var i;',
|
| 3855 | '',
|
| 3856 | ' if (searchTerm === "") {',
|
| 3857 | ' $("searchReset").disabled = true;',
|
| 3858 | ' $("searchNav").style.display = "none";',
|
| 3859 | ' removeClass(document.body, "searching");',
|
| 3860 | ' removeClass(searchBox, "hasmatches");',
|
| 3861 | ' removeClass(searchBox, "nomatches");',
|
| 3862 | ' for (i = 0; i < logEntries.length; i++) {',
|
| 3863 | ' logEntries[i].clearSearch();',
|
| 3864 | ' logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',
|
| 3865 | ' }',
|
| 3866 | ' currentSearch = null;',
|
| 3867 | ' setLogContainerHeight();',
|
| 3868 | ' } else {',
|
| 3869 | ' $("searchReset").disabled = false;',
|
| 3870 | ' $("searchNav").style.display = "block";',
|
| 3871 | ' var searchRegex;',
|
| 3872 | ' var regexValid;',
|
| 3873 | ' if (isRegex) {',
|
| 3874 | ' try {',
|
| 3875 | ' searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',
|
| 3876 | ' regexValid = true;',
|
| 3877 | ' replaceClass(searchBox, "validregex", "invalidregex");',
|
| 3878 | ' searchBox.title = "Valid regex";',
|
| 3879 | ' } catch (ex) {',
|
| 3880 | ' regexValid = false;',
|
| 3881 | ' replaceClass(searchBox, "invalidregex", "validregex");',
|
| 3882 | ' searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',
|
| 3883 | ' return;',
|
| 3884 | ' }',
|
| 3885 | ' } else {',
|
| 3886 | ' searchBox.title = "";',
|
| 3887 | ' removeClass(searchBox, "validregex");',
|
| 3888 | ' removeClass(searchBox, "invalidregex");',
|
| 3889 | ' }',
|
| 3890 | ' addClass(document.body, "searching");',
|
| 3891 | ' currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',
|
| 3892 | ' for (i = 0; i < logEntries.length; i++) {',
|
| 3893 | ' currentSearch.applyTo(logEntries[i]);',
|
| 3894 | ' }',
|
| 3895 | ' setLogContainerHeight();',
|
| 3896 | '',
|
| 3897 | ' // Highlight the first search match',
|
| 3898 | ' if (currentSearch.hasVisibleMatches()) {',
|
| 3899 | ' setCurrentMatchIndex(0);',
|
| 3900 | ' displayMatches();',
|
| 3901 | ' } else {',
|
| 3902 | ' displayNoMatches();',
|
| 3903 | ' }',
|
| 3904 | ' }',
|
| 3905 | ' }',
|
| 3906 | '',
|
| 3907 | ' function updateSearchFromFilters() {',
|
| 3908 | ' if (currentSearch) {',
|
| 3909 | ' if (currentSearch.hasMatches()) {',
|
| 3910 | ' if (currentMatchIndex === null) {',
|
| 3911 | ' currentMatchIndex = 0;',
|
| 3912 | ' }',
|
| 3913 | ' var currentMatch = currentSearch.matches[currentMatchIndex];',
|
| 3914 | ' if (currentMatch.isVisible()) {',
|
| 3915 | ' displayMatches();',
|
| 3916 | ' setCurrentMatchIndex(currentMatchIndex);',
|
| 3917 | ' } else {',
|
| 3918 | ' currentMatch.setNotCurrent();',
|
| 3919 | ' // Find the next visible match, if one exists',
|
| 3920 | ' var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',
|
| 3921 | ' if (nextVisibleMatchIndex > -1) {',
|
| 3922 | ' setCurrentMatchIndex(nextVisibleMatchIndex);',
|
| 3923 | ' displayMatches();',
|
| 3924 | ' } else {',
|
| 3925 | ' displayNoMatches();',
|
| 3926 | ' }',
|
| 3927 | ' }',
|
| 3928 | ' } else {',
|
| 3929 | ' displayNoMatches();',
|
| 3930 | ' }',
|
| 3931 | ' }',
|
| 3932 | ' }',
|
| 3933 | '',
|
| 3934 | ' function refreshCurrentMatch() {',
|
| 3935 | ' if (currentSearch && currentSearch.hasVisibleMatches()) {',
|
| 3936 | ' setCurrentMatchIndex(currentMatchIndex);',
|
| 3937 | ' }',
|
| 3938 | ' }',
|
| 3939 | '',
|
| 3940 | ' function displayMatches() {',
|
| 3941 | ' replaceClass($("searchBox"), "hasmatches", "nomatches");',
|
| 3942 | ' $("searchBox").title = "" + currentSearch.matches.length + " matches found";',
|
| 3943 | ' $("searchNav").style.display = "block";',
|
| 3944 | ' setLogContainerHeight();',
|
| 3945 | ' }',
|
| 3946 | '',
|
| 3947 | ' function displayNoMatches() {',
|
| 3948 | ' replaceClass($("searchBox"), "nomatches", "hasmatches");',
|
| 3949 | ' $("searchBox").title = "No matches found";',
|
| 3950 | ' $("searchNav").style.display = "none";',
|
| 3951 | ' setLogContainerHeight();',
|
| 3952 | ' }',
|
| 3953 | '',
|
| 3954 | ' function toggleSearchEnabled(enable) {',
|
| 3955 | ' enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',
|
| 3956 | ' $("searchBox").disabled = !enable;',
|
| 3957 | ' $("searchReset").disabled = !enable;',
|
| 3958 | ' $("searchRegex").disabled = !enable;',
|
| 3959 | ' $("searchNext").disabled = !enable;',
|
| 3960 | ' $("searchPrevious").disabled = !enable;',
|
| 3961 | ' $("searchCaseSensitive").disabled = !enable;',
|
| 3962 | ' $("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',
|
| 3963 | ' currentSearch && currentSearch.hasVisibleMatches()) ?',
|
| 3964 | ' "block" : "none";',
|
| 3965 | ' if (enable) {',
|
| 3966 | ' removeClass($("search"), "greyedout");',
|
| 3967 | ' addClass(document.body, "searching");',
|
| 3968 | ' if ($("searchHighlight").checked) {',
|
| 3969 | ' addClass(logMainContainer, "searchhighlight");',
|
| 3970 | ' } else {',
|
| 3971 | ' removeClass(logMainContainer, "searchhighlight");',
|
| 3972 | ' }',
|
| 3973 | ' if ($("searchFilter").checked) {',
|
| 3974 | ' addClass(logMainContainer, "searchfilter");',
|
| 3975 | ' } else {',
|
| 3976 | ' removeClass(logMainContainer, "searchfilter");',
|
| 3977 | ' }',
|
| 3978 | ' $("searchDisable").checked = !enable;',
|
| 3979 | ' } else {',
|
| 3980 | ' addClass($("search"), "greyedout");',
|
| 3981 | ' removeClass(document.body, "searching");',
|
| 3982 | ' removeClass(logMainContainer, "searchhighlight");',
|
| 3983 | ' removeClass(logMainContainer, "searchfilter");',
|
| 3984 | ' }',
|
| 3985 | ' setLogContainerHeight();',
|
| 3986 | ' }',
|
| 3987 | '',
|
| 3988 | ' function toggleSearchFilter() {',
|
| 3989 | ' var enable = $("searchFilter").checked;',
|
| 3990 | ' if (enable) {',
|
| 3991 | ' addClass(logMainContainer, "searchfilter");',
|
| 3992 | ' } else {',
|
| 3993 | ' removeClass(logMainContainer, "searchfilter");',
|
| 3994 | ' }',
|
| 3995 | ' refreshCurrentMatch();',
|
| 3996 | ' }',
|
| 3997 | '',
|
| 3998 | ' function toggleSearchHighlight() {',
|
| 3999 | ' var enable = $("searchHighlight").checked;',
|
| 4000 | ' if (enable) {',
|
| 4001 | ' addClass(logMainContainer, "searchhighlight");',
|
| 4002 | ' } else {',
|
| 4003 | ' removeClass(logMainContainer, "searchhighlight");',
|
| 4004 | ' }',
|
| 4005 | ' }',
|
| 4006 | '',
|
| 4007 | ' function clearSearch() {',
|
| 4008 | ' $("searchBox").value = "";',
|
| 4009 | ' doSearch();',
|
| 4010 | ' }',
|
| 4011 | '',
|
| 4012 | ' function searchNext() {',
|
| 4013 | ' if (currentSearch !== null && currentMatchIndex !== null) {',
|
| 4014 | ' currentSearch.matches[currentMatchIndex].setNotCurrent();',
|
| 4015 | ' var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',
|
| 4016 | ' if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',
|
| 4017 | ' setCurrentMatchIndex(nextMatchIndex);',
|
| 4018 | ' }',
|
| 4019 | ' }',
|
| 4020 | ' }',
|
| 4021 | '',
|
| 4022 | ' function searchPrevious() {',
|
| 4023 | ' if (currentSearch !== null && currentMatchIndex !== null) {',
|
| 4024 | ' currentSearch.matches[currentMatchIndex].setNotCurrent();',
|
| 4025 | ' var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',
|
| 4026 | ' if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',
|
| 4027 | ' setCurrentMatchIndex(previousMatchIndex);',
|
| 4028 | ' }',
|
| 4029 | ' }',
|
| 4030 | ' }',
|
| 4031 | '',
|
| 4032 | ' function setCurrentMatchIndex(index) {',
|
| 4033 | ' currentMatchIndex = index;',
|
| 4034 | ' currentSearch.matches[currentMatchIndex].setCurrent();',
|
| 4035 | ' }',
|
| 4036 | '',
|
| 4037 | ' /* ------------------------------------------------------------------------- */',
|
| 4038 | '',
|
| 4039 | ' // CSS Utilities',
|
| 4040 | '',
|
| 4041 | ' function addClass(el, cssClass) {',
|
| 4042 | ' if (!hasClass(el, cssClass)) {',
|
| 4043 | ' if (el.className) {',
|
| 4044 | ' el.className += " " + cssClass;',
|
| 4045 | ' } else {',
|
| 4046 | ' el.className = cssClass;',
|
| 4047 | ' }',
|
| 4048 | ' }',
|
| 4049 | ' }',
|
| 4050 | '',
|
| 4051 | ' function hasClass(el, cssClass) {',
|
| 4052 | ' if (el.className) {',
|
| 4053 | ' var classNames = el.className.split(" ");',
|
| 4054 | ' return array_contains(classNames, cssClass);',
|
| 4055 | ' }',
|
| 4056 | ' return false;',
|
| 4057 | ' }',
|
| 4058 | '',
|
| 4059 | ' function removeClass(el, cssClass) {',
|
| 4060 | ' if (hasClass(el, cssClass)) {',
|
| 4061 | ' // Rebuild the className property',
|
| 4062 | ' var existingClasses = el.className.split(" ");',
|
| 4063 | ' var newClasses = [];',
|
| 4064 | ' for (var i = 0, len = existingClasses.length; i < len; i++) {',
|
| 4065 | ' if (existingClasses[i] != cssClass) {',
|
| 4066 | ' newClasses[newClasses.length] = existingClasses[i];',
|
| 4067 | ' }',
|
| 4068 | ' }',
|
| 4069 | ' el.className = newClasses.join(" ");',
|
| 4070 | ' }',
|
| 4071 | ' }',
|
| 4072 | '',
|
| 4073 | ' function replaceClass(el, newCssClass, oldCssClass) {',
|
| 4074 | ' removeClass(el, oldCssClass);',
|
| 4075 | ' addClass(el, newCssClass);',
|
| 4076 | ' }',
|
| 4077 | '',
|
| 4078 | ' /* ------------------------------------------------------------------------- */',
|
| 4079 | '',
|
| 4080 | ' // Other utility functions',
|
| 4081 | '',
|
| 4082 | ' function getElementsByClass(el, cssClass, tagName) {',
|
| 4083 | ' var elements = el.getElementsByTagName(tagName);',
|
| 4084 | ' var matches = [];',
|
| 4085 | ' for (var i = 0, len = elements.length; i < len; i++) {',
|
| 4086 | ' if (hasClass(elements[i], cssClass)) {',
|
| 4087 | ' matches.push(elements[i]);',
|
| 4088 | ' }',
|
| 4089 | ' }',
|
| 4090 | ' return matches;',
|
| 4091 | ' }',
|
| 4092 | '',
|
| 4093 | ' // Syntax borrowed from Prototype library',
|
| 4094 | ' function $(id) {',
|
| 4095 | ' return document.getElementById(id);',
|
| 4096 | ' }',
|
| 4097 | '',
|
| 4098 | ' function isDescendant(node, ancestorNode) {',
|
| 4099 | ' while (node != null) {',
|
| 4100 | ' if (node === ancestorNode) {',
|
| 4101 | ' return true;',
|
| 4102 | ' }',
|
| 4103 | ' node = node.parentNode;',
|
| 4104 | ' }',
|
| 4105 | ' return false;',
|
| 4106 | ' }',
|
| 4107 | '',
|
| 4108 | ' function isOrphan(node) {',
|
| 4109 | ' var currentNode = node;',
|
| 4110 | ' while (currentNode) {',
|
| 4111 | ' if (currentNode == document.body) {',
|
| 4112 | ' return false;',
|
| 4113 | ' }',
|
| 4114 | ' currentNode = currentNode.parentNode;',
|
| 4115 | ' }',
|
| 4116 | ' return true;',
|
| 4117 | ' }',
|
| 4118 | '',
|
| 4119 | ' function escapeHtml(str) {',
|
| 4120 | ' return str.replace(/&/g, "&").replace(/[<]/g, "<").replace(/>/g, ">");',
|
| 4121 | ' }',
|
| 4122 | '',
|
| 4123 | ' function getWindowWidth() {',
|
| 4124 | ' if (window.innerWidth) {',
|
| 4125 | ' return window.innerWidth;',
|
| 4126 | ' } else if (document.documentElement && document.documentElement.clientWidth) {',
|
| 4127 | ' return document.documentElement.clientWidth;',
|
| 4128 | ' } else if (document.body) {',
|
| 4129 | ' return document.body.clientWidth;',
|
| 4130 | ' }',
|
| 4131 | ' return 0;',
|
| 4132 | ' }',
|
| 4133 | '',
|
| 4134 | ' function getWindowHeight() {',
|
| 4135 | ' if (window.innerHeight) {',
|
| 4136 | ' return window.innerHeight;',
|
| 4137 | ' } else if (document.documentElement && document.documentElement.clientHeight) {',
|
| 4138 | ' return document.documentElement.clientHeight;',
|
| 4139 | ' } else if (document.body) {',
|
| 4140 | ' return document.body.clientHeight;',
|
| 4141 | ' }',
|
| 4142 | ' return 0;',
|
| 4143 | ' }',
|
| 4144 | '',
|
| 4145 | ' function getToolBarsHeight() {',
|
| 4146 | ' return $("switches").offsetHeight;',
|
| 4147 | ' }',
|
| 4148 | '',
|
| 4149 | ' function getChromeHeight() {',
|
| 4150 | ' var height = getToolBarsHeight();',
|
| 4151 | ' if (showCommandLine) {',
|
| 4152 | ' height += $("commandLine").offsetHeight;',
|
| 4153 | ' }',
|
| 4154 | ' return height;',
|
| 4155 | ' }',
|
| 4156 | '',
|
| 4157 | ' function setLogContainerHeight() {',
|
| 4158 | ' if (logMainContainer) {',
|
| 4159 | ' var windowHeight = getWindowHeight();',
|
| 4160 | ' $("body").style.height = getWindowHeight() + "px";',
|
| 4161 | ' logMainContainer.style.height = "" +',
|
| 4162 | ' Math.max(0, windowHeight - getChromeHeight()) + "px";',
|
| 4163 | ' }',
|
| 4164 | ' }',
|
| 4165 | '',
|
| 4166 | ' function setCommandInputWidth() {',
|
| 4167 | ' if (showCommandLine) {',
|
| 4168 | ' $("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',
|
| 4169 | ' ($("evaluateButton").offsetWidth + 13)) + "px";',
|
| 4170 | ' }',
|
| 4171 | ' }',
|
| 4172 | '',
|
| 4173 | ' window.onresize = function() {',
|
| 4174 | ' setCommandInputWidth();',
|
| 4175 | ' setLogContainerHeight();',
|
| 4176 | ' };',
|
| 4177 | '',
|
| 4178 | ' if (!Array.prototype.push) {',
|
| 4179 | ' Array.prototype.push = function() {',
|
| 4180 | ' for (var i = 0, len = arguments.length; i < len; i++){',
|
| 4181 | ' this[this.length] = arguments[i];',
|
| 4182 | ' }',
|
| 4183 | ' return this.length;',
|
| 4184 | ' };',
|
| 4185 | ' }',
|
| 4186 | '',
|
| 4187 | ' if (!Array.prototype.pop) {',
|
| 4188 | ' Array.prototype.pop = function() {',
|
| 4189 | ' if (this.length > 0) {',
|
| 4190 | ' var val = this[this.length - 1];',
|
| 4191 | ' this.length = this.length - 1;',
|
| 4192 | ' return val;',
|
| 4193 | ' }',
|
| 4194 | ' };',
|
| 4195 | ' }',
|
| 4196 | '',
|
| 4197 | ' if (!Array.prototype.shift) {',
|
| 4198 | ' Array.prototype.shift = function() {',
|
| 4199 | ' if (this.length > 0) {',
|
| 4200 | ' var firstItem = this[0];',
|
| 4201 | ' for (var i = 0, len = this.length - 1; i < len; i++) {',
|
| 4202 | ' this[i] = this[i + 1];',
|
| 4203 | ' }',
|
| 4204 | ' this.length = this.length - 1;',
|
| 4205 | ' return firstItem;',
|
| 4206 | ' }',
|
| 4207 | ' };',
|
| 4208 | ' }',
|
| 4209 | '',
|
| 4210 | ' if (!Array.prototype.splice) {',
|
| 4211 | ' Array.prototype.splice = function(startIndex, deleteCount) {',
|
| 4212 | ' var itemsAfterDeleted = this.slice(startIndex + deleteCount);',
|
| 4213 | ' var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',
|
| 4214 | ' this.length = startIndex;',
|
| 4215 | ' // Copy the arguments into a proper Array object',
|
| 4216 | ' var argumentsArray = [];',
|
| 4217 | ' for (var i = 0, len = arguments.length; i < len; i++) {',
|
| 4218 | ' argumentsArray[i] = arguments[i];',
|
| 4219 | ' }',
|
| 4220 | ' var itemsToAppend = (argumentsArray.length > 2) ?',
|
| 4221 | ' itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',
|
| 4222 | ' for (i = 0, len = itemsToAppend.length; i < len; i++) {',
|
| 4223 | ' this.push(itemsToAppend[i]);',
|
| 4224 | ' }',
|
| 4225 | ' return itemsDeleted;',
|
| 4226 | ' };',
|
| 4227 | ' }',
|
| 4228 | '',
|
| 4229 | ' function array_remove(arr, val) {',
|
| 4230 | ' var index = -1;',
|
| 4231 | ' for (var i = 0, len = arr.length; i < len; i++) {',
|
| 4232 | ' if (arr[i] === val) {',
|
| 4233 | ' index = i;',
|
| 4234 | ' break;',
|
| 4235 | ' }',
|
| 4236 | ' }',
|
| 4237 | ' if (index >= 0) {',
|
| 4238 | ' arr.splice(index, 1);',
|
| 4239 | ' return index;',
|
| 4240 | ' } else {',
|
| 4241 | ' return false;',
|
| 4242 | ' }',
|
| 4243 | ' }',
|
| 4244 | '',
|
| 4245 | ' function array_removeFromStart(array, numberToRemove) {',
|
| 4246 | ' if (Array.prototype.splice) {',
|
| 4247 | ' array.splice(0, numberToRemove);',
|
| 4248 | ' } else {',
|
| 4249 | ' for (var i = numberToRemove, len = array.length; i < len; i++) {',
|
| 4250 | ' array[i - numberToRemove] = array[i];',
|
| 4251 | ' }',
|
| 4252 | ' array.length = array.length - numberToRemove;',
|
| 4253 | ' }',
|
| 4254 | ' return array;',
|
| 4255 | ' }',
|
| 4256 | '',
|
| 4257 | ' function array_contains(arr, val) {',
|
| 4258 | ' for (var i = 0, len = arr.length; i < len; i++) {',
|
| 4259 | ' if (arr[i] == val) {',
|
| 4260 | ' return true;',
|
| 4261 | ' }',
|
| 4262 | ' }',
|
| 4263 | ' return false;',
|
| 4264 | ' }',
|
| 4265 | '',
|
| 4266 | ' function getErrorMessage(ex) {',
|
| 4267 | ' if (ex.message) {',
|
| 4268 | ' return ex.message;',
|
| 4269 | ' } else if (ex.description) {',
|
| 4270 | ' return ex.description;',
|
| 4271 | ' }',
|
| 4272 | ' return "" + ex;',
|
| 4273 | ' }',
|
| 4274 | '',
|
| 4275 | ' function moveCaretToEnd(input) {',
|
| 4276 | ' if (input.setSelectionRange) {',
|
| 4277 | ' input.focus();',
|
| 4278 | ' var length = input.value.length;',
|
| 4279 | ' input.setSelectionRange(length, length);',
|
| 4280 | ' } else if (input.createTextRange) {',
|
| 4281 | ' var range = input.createTextRange();',
|
| 4282 | ' range.collapse(false);',
|
| 4283 | ' range.select();',
|
| 4284 | ' }',
|
| 4285 | ' input.focus();',
|
| 4286 | ' }',
|
| 4287 | '',
|
| 4288 | ' function stopPropagation(evt) {',
|
| 4289 | ' if (evt.stopPropagation) {',
|
| 4290 | ' evt.stopPropagation();',
|
| 4291 | ' } else if (typeof evt.cancelBubble != "undefined") {',
|
| 4292 | ' evt.cancelBubble = true;',
|
| 4293 | ' }',
|
| 4294 | ' }',
|
| 4295 | '',
|
| 4296 | ' function getEvent(evt) {',
|
| 4297 | ' return evt ? evt : event;',
|
| 4298 | ' }',
|
| 4299 | '',
|
| 4300 | ' function getTarget(evt) {',
|
| 4301 | ' return evt.target ? evt.target : evt.srcElement;',
|
| 4302 | ' }',
|
| 4303 | '',
|
| 4304 | ' function getRelatedTarget(evt) {',
|
| 4305 | ' if (evt.relatedTarget) {',
|
| 4306 | ' return evt.relatedTarget;',
|
| 4307 | ' } else if (evt.srcElement) {',
|
| 4308 | ' switch(evt.type) {',
|
| 4309 | ' case "mouseover":',
|
| 4310 | ' return evt.fromElement;',
|
| 4311 | ' case "mouseout":',
|
| 4312 | ' return evt.toElement;',
|
| 4313 | ' default:',
|
| 4314 | ' return evt.srcElement;',
|
| 4315 | ' }',
|
| 4316 | ' }',
|
| 4317 | ' }',
|
| 4318 | '',
|
| 4319 | ' function cancelKeyEvent(evt) {',
|
| 4320 | ' evt.returnValue = false;',
|
| 4321 | ' stopPropagation(evt);',
|
| 4322 | ' }',
|
| 4323 | '',
|
| 4324 | ' function evalCommandLine() {',
|
| 4325 | ' var expr = $("command").value;',
|
| 4326 | ' evalCommand(expr);',
|
| 4327 | ' $("command").value = "";',
|
| 4328 | ' }',
|
| 4329 | '',
|
| 4330 | ' function evalLastCommand() {',
|
| 4331 | ' if (lastCommand != null) {',
|
| 4332 | ' evalCommand(lastCommand);',
|
| 4333 | ' }',
|
| 4334 | ' }',
|
| 4335 | '',
|
| 4336 | ' var lastCommand = null;',
|
| 4337 | ' var commandHistory = [];',
|
| 4338 | ' var currentCommandIndex = 0;',
|
| 4339 | '',
|
| 4340 | ' function evalCommand(expr) {',
|
| 4341 | ' if (appender) {',
|
| 4342 | ' appender.evalCommandAndAppend(expr);',
|
| 4343 | ' } else {',
|
| 4344 | ' var prefix = ">>> " + expr + "\\r\\n";',
|
| 4345 | ' try {',
|
| 4346 | ' log("INFO", prefix + eval(expr));',
|
| 4347 | ' } catch (ex) {',
|
| 4348 | ' log("ERROR", prefix + "Error: " + getErrorMessage(ex));',
|
| 4349 | ' }',
|
| 4350 | ' }',
|
| 4351 | ' // Update command history',
|
| 4352 | ' if (expr != commandHistory[commandHistory.length - 1]) {',
|
| 4353 | ' commandHistory.push(expr);',
|
| 4354 | ' // Update the appender',
|
| 4355 | ' if (appender) {',
|
| 4356 | ' appender.storeCommandHistory(commandHistory);',
|
| 4357 | ' }',
|
| 4358 | ' }',
|
| 4359 | ' currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',
|
| 4360 | ' lastCommand = expr;',
|
| 4361 | ' }',
|
| 4362 | ' //]]>',
|
| 4363 | ' </script>',
|
| 4364 | ' <style type="text/css">',
|
| 4365 | ' body {',
|
| 4366 | ' background-color: white;',
|
| 4367 | ' color: black;',
|
| 4368 | ' padding: 0;',
|
| 4369 | ' margin: 0;',
|
| 4370 | ' font-family: tahoma, verdana, arial, helvetica, sans-serif;',
|
| 4371 | ' overflow: hidden;',
|
| 4372 | ' }',
|
| 4373 | '',
|
| 4374 | ' div#switchesContainer input {',
|
| 4375 | ' margin-bottom: 0;',
|
| 4376 | ' }',
|
| 4377 | '',
|
| 4378 | ' div.toolbar {',
|
| 4379 | ' border-top: solid #ffffff 1px;',
|
| 4380 | ' border-bottom: solid #aca899 1px;',
|
| 4381 | ' background-color: #f1efe7;',
|
| 4382 | ' padding: 3px 5px;',
|
| 4383 | ' font-size: 68.75%;',
|
| 4384 | ' }',
|
| 4385 | '',
|
| 4386 | ' div.toolbar, div#search input {',
|
| 4387 | ' font-family: tahoma, verdana, arial, helvetica, sans-serif;',
|
| 4388 | ' }',
|
| 4389 | '',
|
| 4390 | ' div.toolbar input.button {',
|
| 4391 | ' padding: 0 5px;',
|
| 4392 | ' font-size: 100%;',
|
| 4393 | ' }',
|
| 4394 | '',
|
| 4395 | ' div.toolbar input.hidden {',
|
| 4396 | ' display: none;',
|
| 4397 | ' }',
|
| 4398 | '',
|
| 4399 | ' div#switches input#clearButton {',
|
| 4400 | ' margin-left: 20px;',
|
| 4401 | ' }',
|
| 4402 | '',
|
| 4403 | ' div#levels label {',
|
| 4404 | ' font-weight: bold;',
|
| 4405 | ' }',
|
| 4406 | '',
|
| 4407 | ' div#levels label, div#options label {',
|
| 4408 | ' margin-right: 5px;',
|
| 4409 | ' }',
|
| 4410 | '',
|
| 4411 | ' div#levels label#wrapLabel {',
|
| 4412 | ' font-weight: normal;',
|
| 4413 | ' }',
|
| 4414 | '',
|
| 4415 | ' div#search label {',
|
| 4416 | ' margin-right: 10px;',
|
| 4417 | ' }',
|
| 4418 | '',
|
| 4419 | ' div#search label.searchboxlabel {',
|
| 4420 | ' margin-right: 0;',
|
| 4421 | ' }',
|
| 4422 | '',
|
| 4423 | ' div#search input {',
|
| 4424 | ' font-size: 100%;',
|
| 4425 | ' }',
|
| 4426 | '',
|
| 4427 | ' div#search input.validregex {',
|
| 4428 | ' color: green;',
|
| 4429 | ' }',
|
| 4430 | '',
|
| 4431 | ' div#search input.invalidregex {',
|
| 4432 | ' color: red;',
|
| 4433 | ' }',
|
| 4434 | '',
|
| 4435 | ' div#search input.nomatches {',
|
| 4436 | ' color: white;',
|
| 4437 | ' background-color: #ff6666;',
|
| 4438 | ' }',
|
| 4439 | '',
|
| 4440 | ' div#search input.nomatches {',
|
| 4441 | ' color: white;',
|
| 4442 | ' background-color: #ff6666;',
|
| 4443 | ' }',
|
| 4444 | '',
|
| 4445 | ' div#searchNav {',
|
| 4446 | ' display: none;',
|
| 4447 | ' }',
|
| 4448 | '',
|
| 4449 | ' div#commandLine {',
|
| 4450 | ' display: none;',
|
| 4451 | ' }',
|
| 4452 | '',
|
| 4453 | ' div#commandLine input#command {',
|
| 4454 | ' font-size: 100%;',
|
| 4455 | ' font-family: Courier New, Courier;',
|
| 4456 | ' }',
|
| 4457 | '',
|
| 4458 | ' div#commandLine input#evaluateButton {',
|
| 4459 | ' }',
|
| 4460 | '',
|
| 4461 | ' *.greyedout {',
|
| 4462 | ' color: gray !important;',
|
| 4463 | ' border-color: gray !important;',
|
| 4464 | ' }',
|
| 4465 | '',
|
| 4466 | ' *.greyedout *.alwaysenabled { color: black; }',
|
| 4467 | '',
|
| 4468 | ' *.unselectable {',
|
| 4469 | ' -khtml-user-select: none;',
|
| 4470 | ' -moz-user-select: none;',
|
| 4471 | ' user-select: none;',
|
| 4472 | ' }',
|
| 4473 | '',
|
| 4474 | ' div#log {',
|
| 4475 | ' font-family: Courier New, Courier;',
|
| 4476 | ' font-size: 75%;',
|
| 4477 | ' width: 100%;',
|
| 4478 | ' overflow: auto;',
|
| 4479 | ' clear: both;',
|
| 4480 | ' position: relative;',
|
| 4481 | ' }',
|
| 4482 | '',
|
| 4483 | ' div.group {',
|
| 4484 | ' border-color: #cccccc;',
|
| 4485 | ' border-style: solid;',
|
| 4486 | ' border-width: 1px 0 1px 1px;',
|
| 4487 | ' overflow: visible;',
|
| 4488 | ' }',
|
| 4489 | '',
|
| 4490 | ' div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',
|
| 4491 | ' height: 1%;',
|
| 4492 | ' }',
|
| 4493 | '',
|
| 4494 | ' div.group div.groupheading span.expander {',
|
| 4495 | ' border: solid black 1px;',
|
| 4496 | ' font-family: Courier New, Courier;',
|
| 4497 | ' font-size: 0.833em;',
|
| 4498 | ' background-color: #eeeeee;',
|
| 4499 | ' position: relative;',
|
| 4500 | ' top: -1px;',
|
| 4501 | ' color: black;',
|
| 4502 | ' padding: 0 2px;',
|
| 4503 | ' cursor: pointer;',
|
| 4504 | ' cursor: hand;',
|
| 4505 | ' height: 1%;',
|
| 4506 | ' }',
|
| 4507 | '',
|
| 4508 | ' div.group div.groupcontent {',
|
| 4509 | ' margin-left: 10px;',
|
| 4510 | ' padding-bottom: 2px;',
|
| 4511 | ' overflow: visible;',
|
| 4512 | ' }',
|
| 4513 | '',
|
| 4514 | ' div.group div.expanded {',
|
| 4515 | ' display: block;',
|
| 4516 | ' }',
|
| 4517 | '',
|
| 4518 | ' div.group div.collapsed {',
|
| 4519 | ' display: none;',
|
| 4520 | ' }',
|
| 4521 | '',
|
| 4522 | ' *.logentry {',
|
| 4523 | ' overflow: visible;',
|
| 4524 | ' display: none;',
|
| 4525 | ' white-space: pre;',
|
| 4526 | ' }',
|
| 4527 | '',
|
| 4528 | ' span.pre {',
|
| 4529 | ' white-space: pre;',
|
| 4530 | ' }',
|
| 4531 | ' ',
|
| 4532 | ' pre.unwrapped {',
|
| 4533 | ' display: inline !important;',
|
| 4534 | ' }',
|
| 4535 | '',
|
| 4536 | ' pre.unwrapped pre.pre, div.wrapped pre.pre {',
|
| 4537 | ' display: inline;',
|
| 4538 | ' }',
|
| 4539 | '',
|
| 4540 | ' div.wrapped pre.pre {',
|
| 4541 | ' white-space: normal;',
|
| 4542 | ' }',
|
| 4543 | '',
|
| 4544 | ' div.wrapped {',
|
| 4545 | ' display: none;',
|
| 4546 | ' }',
|
| 4547 | '',
|
| 4548 | ' body.searching *.logentry span.currentmatch {',
|
| 4549 | ' color: white !important;',
|
| 4550 | ' background-color: green !important;',
|
| 4551 | ' }',
|
| 4552 | '',
|
| 4553 | ' body.searching div.searchhighlight *.logentry span.searchterm {',
|
| 4554 | ' color: black;',
|
| 4555 | ' background-color: yellow;',
|
| 4556 | ' }',
|
| 4557 | '',
|
| 4558 | ' div.wrap *.logentry {',
|
| 4559 | ' white-space: normal !important;',
|
| 4560 | ' border-width: 0 0 1px 0;',
|
| 4561 | ' border-color: #dddddd;',
|
| 4562 | ' border-style: dotted;',
|
| 4563 | ' }',
|
| 4564 | '',
|
| 4565 | ' div.wrap #log_wrapped, #log_unwrapped {',
|
| 4566 | ' display: block;',
|
| 4567 | ' }',
|
| 4568 | '',
|
| 4569 | ' div.wrap #log_unwrapped, #log_wrapped {',
|
| 4570 | ' display: none;',
|
| 4571 | ' }',
|
| 4572 | '',
|
| 4573 | ' div.wrap *.logentry span.pre {',
|
| 4574 | ' overflow: visible;',
|
| 4575 | ' white-space: normal;',
|
| 4576 | ' }',
|
| 4577 | '',
|
| 4578 | ' div.wrap *.logentry pre.unwrapped {',
|
| 4579 | ' display: none;',
|
| 4580 | ' }',
|
| 4581 | '',
|
| 4582 | ' div.wrap *.logentry span.wrapped {',
|
| 4583 | ' display: inline;',
|
| 4584 | ' }',
|
| 4585 | '',
|
| 4586 | ' div.searchfilter *.searchnonmatch {',
|
| 4587 | ' display: none !important;',
|
| 4588 | ' }',
|
| 4589 | '',
|
| 4590 | ' div#log *.TRACE, label#label_TRACE {',
|
| 4591 | ' color: #666666;',
|
| 4592 | ' }',
|
| 4593 | '',
|
| 4594 | ' div#log *.DEBUG, label#label_DEBUG {',
|
| 4595 | ' color: green;',
|
| 4596 | ' }',
|
| 4597 | '',
|
| 4598 | ' div#log *.INFO, label#label_INFO {',
|
| 4599 | ' color: #000099;',
|
| 4600 | ' }',
|
| 4601 | '',
|
| 4602 | ' div#log *.WARN, label#label_WARN {',
|
| 4603 | ' color: #999900;',
|
| 4604 | ' }',
|
| 4605 | '',
|
| 4606 | ' div#log *.ERROR, label#label_ERROR {',
|
| 4607 | ' color: red;',
|
| 4608 | ' }',
|
| 4609 | '',
|
| 4610 | ' div#log *.FATAL, label#label_FATAL {',
|
| 4611 | ' color: #660066;',
|
| 4612 | ' }',
|
| 4613 | '',
|
| 4614 | ' div.TRACE#log *.TRACE,',
|
| 4615 | ' div.DEBUG#log *.DEBUG,',
|
| 4616 | ' div.INFO#log *.INFO,',
|
| 4617 | ' div.WARN#log *.WARN,',
|
| 4618 | ' div.ERROR#log *.ERROR,',
|
| 4619 | ' div.FATAL#log *.FATAL {',
|
| 4620 | ' display: block;',
|
| 4621 | ' }',
|
| 4622 | '',
|
| 4623 | ' div#log div.separator {',
|
| 4624 | ' background-color: #cccccc;',
|
| 4625 | ' margin: 5px 0;',
|
| 4626 | ' line-height: 1px;',
|
| 4627 | ' }',
|
| 4628 | ' </style>',
|
| 4629 | ' </head>',
|
| 4630 | '',
|
| 4631 | ' <body id="body">',
|
| 4632 | ' <div id="switchesContainer">',
|
| 4633 | ' <div id="switches">',
|
| 4634 | ' <div id="levels" class="toolbar">',
|
| 4635 | ' Filters:',
|
| 4636 | ' <input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',
|
| 4637 | ' <input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',
|
| 4638 | ' <input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',
|
| 4639 | ' <input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',
|
| 4640 | ' <input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',
|
| 4641 | ' <input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',
|
| 4642 | ' <input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',
|
| 4643 | ' </div>',
|
| 4644 | ' <div id="search" class="toolbar">',
|
| 4645 | ' <label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',
|
| 4646 | ' <input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',
|
| 4647 | ' <input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',
|
| 4648 | ' <input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',
|
| 4649 | ' <input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',
|
| 4650 | ' <div id="searchNav">',
|
| 4651 | ' <input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',
|
| 4652 | ' <input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',
|
| 4653 | ' <input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',
|
| 4654 | ' <input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',
|
| 4655 | ' </div>',
|
| 4656 | ' </div>',
|
| 4657 | ' <div id="options" class="toolbar">',
|
| 4658 | ' Options:',
|
| 4659 | ' <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',
|
| 4660 | ' <input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',
|
| 4661 | ' <input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',
|
| 4662 | ' <input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',
|
| 4663 | ' <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />',
|
| 4664 | ' <input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',
|
| 4665 | ' <input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',
|
| 4666 | ' </div>',
|
| 4667 | ' </div>',
|
| 4668 | ' </div>',
|
| 4669 | ' <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',
|
| 4670 | ' <div id="commandLine" class="toolbar">',
|
| 4671 | ' <div id="commandLineContainer">',
|
| 4672 | ' <input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',
|
| 4673 | ' <input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',
|
| 4674 | ' </div>',
|
| 4675 | ' </div>',
|
| 4676 | ' </body>',
|
| 4677 | '</html>',
|
| 4678 | ''
|
| 4679 | ];
|
| 4680 | };
|
| 4681 |
|
| 4682 | var defaultCommandLineFunctions = [];
|
| 4683 |
|
| 4684 | ConsoleAppender = function() {};
|
| 4685 |
|
| 4686 | var consoleAppenderIdCounter = 1;
|
| 4687 | ConsoleAppender.prototype = new Appender();
|
| 4688 |
|
| 4689 | ConsoleAppender.prototype.create = function(inPage, container,
|
| 4690 | lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {
|
| 4691 | var appender = this;
|
| 4692 |
|
| 4693 | // Common properties
|
| 4694 | var initialized = false;
|
| 4695 | var consoleWindowCreated = false;
|
| 4696 | var consoleWindowLoaded = false;
|
| 4697 | var consoleClosed = false;
|
| 4698 |
|
| 4699 | var queuedLoggingEvents = [];
|
| 4700 | var isSupported = true;
|
| 4701 | var consoleAppenderId = consoleAppenderIdCounter++;
|
| 4702 |
|
| 4703 | // Local variables
|
| 4704 | initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);
|
| 4705 | lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);
|
| 4706 | useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);
|
| 4707 | var newestMessageAtTop = this.defaults.newestMessageAtTop;
|
| 4708 | var scrollToLatestMessage = this.defaults.scrollToLatestMessage;
|
| 4709 | width = width ? width : this.defaults.width;
|
| 4710 | height = height ? height : this.defaults.height;
|
| 4711 | var maxMessages = this.defaults.maxMessages;
|
| 4712 | var showCommandLine = this.defaults.showCommandLine;
|
| 4713 | var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;
|
| 4714 | var showHideButton = this.defaults.showHideButton;
|
| 4715 | var showCloseButton = this.defaults.showCloseButton;
|
| 4716 | var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;
|
| 4717 |
|
| 4718 | this.setLayout(this.defaults.layout);
|
| 4719 |
|
| 4720 | // Functions whose implementations vary between subclasses
|
| 4721 | var init, createWindow, safeToAppend, getConsoleWindow, open;
|
| 4722 |
|
| 4723 | // Configuration methods. The function scope is used to prevent
|
| 4724 | // direct alteration to the appender configuration properties.
|
| 4725 | var appenderName = inPage ? "InPageAppender" : "PopUpAppender";
|
| 4726 | var checkCanConfigure = function(configOptionName) {
|
| 4727 | if (consoleWindowCreated) {
|
| 4728 | handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");
|
| 4729 | return false;
|
| 4730 | }
|
| 4731 | return true;
|
| 4732 | };
|
| 4733 |
|
| 4734 | var consoleWindowExists = function() {
|
| 4735 | return (consoleWindowLoaded && isSupported && !consoleClosed);
|
| 4736 | };
|
| 4737 |
|
| 4738 | this.isNewestMessageAtTop = function() { return newestMessageAtTop; };
|
| 4739 | this.setNewestMessageAtTop = function(newestMessageAtTopParam) {
|
| 4740 | newestMessageAtTop = bool(newestMessageAtTopParam);
|
| 4741 | if (consoleWindowExists()) {
|
| 4742 | getConsoleWindow().setNewestAtTop(newestMessageAtTop);
|
| 4743 | }
|
| 4744 | };
|
| 4745 |
|
| 4746 | this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };
|
| 4747 | this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {
|
| 4748 | scrollToLatestMessage = bool(scrollToLatestMessageParam);
|
| 4749 | if (consoleWindowExists()) {
|
| 4750 | getConsoleWindow().setScrollToLatest(scrollToLatestMessage);
|
| 4751 | }
|
| 4752 | };
|
| 4753 |
|
| 4754 | this.getWidth = function() { return width; };
|
| 4755 | this.setWidth = function(widthParam) {
|
| 4756 | if (checkCanConfigure("width")) {
|
| 4757 | width = extractStringFromParam(widthParam, width);
|
| 4758 | }
|
| 4759 | };
|
| 4760 |
|
| 4761 | this.getHeight = function() { return height; };
|
| 4762 | this.setHeight = function(heightParam) {
|
| 4763 | if (checkCanConfigure("height")) {
|
| 4764 | height = extractStringFromParam(heightParam, height);
|
| 4765 | }
|
| 4766 | };
|
| 4767 |
|
| 4768 | this.getMaxMessages = function() { return maxMessages; };
|
| 4769 | this.setMaxMessages = function(maxMessagesParam) {
|
| 4770 | maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);
|
| 4771 | if (consoleWindowExists()) {
|
| 4772 | getConsoleWindow().setMaxMessages(maxMessages);
|
| 4773 | }
|
| 4774 | };
|
| 4775 |
|
| 4776 | this.isShowCommandLine = function() { return showCommandLine; };
|
| 4777 | this.setShowCommandLine = function(showCommandLineParam) {
|
| 4778 | showCommandLine = bool(showCommandLineParam);
|
| 4779 | if (consoleWindowExists()) {
|
| 4780 | getConsoleWindow().setShowCommandLine(showCommandLine);
|
| 4781 | }
|
| 4782 | };
|
| 4783 |
|
| 4784 | this.isShowHideButton = function() { return showHideButton; };
|
| 4785 | this.setShowHideButton = function(showHideButtonParam) {
|
| 4786 | showHideButton = bool(showHideButtonParam);
|
| 4787 | if (consoleWindowExists()) {
|
| 4788 | getConsoleWindow().setShowHideButton(showHideButton);
|
| 4789 | }
|
| 4790 | };
|
| 4791 |
|
| 4792 | this.isShowCloseButton = function() { return showCloseButton; };
|
| 4793 | this.setShowCloseButton = function(showCloseButtonParam) {
|
| 4794 | showCloseButton = bool(showCloseButtonParam);
|
| 4795 | if (consoleWindowExists()) {
|
| 4796 | getConsoleWindow().setShowCloseButton(showCloseButton);
|
| 4797 | }
|
| 4798 | };
|
| 4799 |
|
| 4800 | this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };
|
| 4801 | this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {
|
| 4802 | commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);
|
| 4803 | };
|
| 4804 |
|
| 4805 | var minimized = initiallyMinimized;
|
| 4806 | this.isInitiallyMinimized = function() { return initiallyMinimized; };
|
| 4807 | this.setInitiallyMinimized = function(initiallyMinimizedParam) {
|
| 4808 | if (checkCanConfigure("initiallyMinimized")) {
|
| 4809 | initiallyMinimized = bool(initiallyMinimizedParam);
|
| 4810 | minimized = initiallyMinimized;
|
| 4811 | }
|
| 4812 | };
|
| 4813 |
|
| 4814 | this.isUseDocumentWrite = function() { return useDocumentWrite; };
|
| 4815 | this.setUseDocumentWrite = function(useDocumentWriteParam) {
|
| 4816 | if (checkCanConfigure("useDocumentWrite")) {
|
| 4817 | useDocumentWrite = bool(useDocumentWriteParam);
|
| 4818 | }
|
| 4819 | };
|
| 4820 |
|
| 4821 | // Common methods
|
| 4822 | function QueuedLoggingEvent(loggingEvent, formattedMessage) {
|
| 4823 | this.loggingEvent = loggingEvent;
|
| 4824 | this.levelName = loggingEvent.level.name;
|
| 4825 | this.formattedMessage = formattedMessage;
|
| 4826 | }
|
| 4827 |
|
| 4828 | QueuedLoggingEvent.prototype.append = function() {
|
| 4829 | getConsoleWindow().log(this.levelName, this.formattedMessage);
|
| 4830 | };
|
| 4831 |
|
| 4832 | function QueuedGroup(name, initiallyExpanded) {
|
| 4833 | this.name = name;
|
| 4834 | this.initiallyExpanded = initiallyExpanded;
|
| 4835 | }
|
| 4836 |
|
| 4837 | QueuedGroup.prototype.append = function() {
|
| 4838 | getConsoleWindow().group(this.name, this.initiallyExpanded);
|
| 4839 | };
|
| 4840 |
|
| 4841 | function QueuedGroupEnd() {}
|
| 4842 |
|
| 4843 | QueuedGroupEnd.prototype.append = function() {
|
| 4844 | getConsoleWindow().groupEnd();
|
| 4845 | };
|
| 4846 |
|
| 4847 | var checkAndAppend = function() {
|
| 4848 | // Next line forces a check of whether the window has been closed
|
| 4849 | safeToAppend();
|
| 4850 | if (!initialized) {
|
| 4851 | init();
|
| 4852 | } else if (consoleClosed && reopenWhenClosed) {
|
| 4853 | createWindow();
|
| 4854 | }
|
| 4855 | if (safeToAppend()) {
|
| 4856 | appendQueuedLoggingEvents();
|
| 4857 | }
|
| 4858 | };
|
| 4859 |
|
| 4860 | this.append = function(loggingEvent) {
|
| 4861 | if (isSupported) {
|
| 4862 | // Format the message
|
| 4863 | var formattedMessage = appender.getLayout().format(loggingEvent);
|
| 4864 | if (this.getLayout().ignoresThrowable()) {
|
| 4865 | formattedMessage += loggingEvent.getThrowableStrRep();
|
| 4866 | }
|
| 4867 | queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));
|
| 4868 | checkAndAppend();
|
| 4869 | }
|
| 4870 | };
|
| 4871 |
|
| 4872 | this.group = function(name, initiallyExpanded) {
|
| 4873 | if (isSupported) {
|
| 4874 | queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));
|
| 4875 | checkAndAppend();
|
| 4876 | }
|
| 4877 | };
|
| 4878 |
|
| 4879 | this.groupEnd = function() {
|
| 4880 | if (isSupported) {
|
| 4881 | queuedLoggingEvents.push(new QueuedGroupEnd());
|
| 4882 | checkAndAppend();
|
| 4883 | }
|
| 4884 | };
|
| 4885 |
|
| 4886 | var appendQueuedLoggingEvents = function() {
|
| 4887 | var currentLoggingEvent;
|
| 4888 | while (queuedLoggingEvents.length > 0) {
|
| 4889 | queuedLoggingEvents.shift().append();
|
| 4890 | }
|
| 4891 | if (focusConsoleWindow) {
|
| 4892 | getConsoleWindow().focus();
|
| 4893 | }
|
| 4894 | };
|
| 4895 |
|
| 4896 | this.setAddedToLogger = function(logger) {
|
| 4897 | this.loggers.push(logger);
|
| 4898 | if (enabled && !lazyInit) {
|
| 4899 | init();
|
| 4900 | }
|
| 4901 | };
|
| 4902 |
|
| 4903 | this.clear = function() {
|
| 4904 | if (consoleWindowExists()) {
|
| 4905 | getConsoleWindow().clearLog();
|
| 4906 | }
|
| 4907 | queuedLoggingEvents.length = 0;
|
| 4908 | };
|
| 4909 |
|
| 4910 | this.focus = function() {
|
| 4911 | if (consoleWindowExists()) {
|
| 4912 | getConsoleWindow().focus();
|
| 4913 | }
|
| 4914 | };
|
| 4915 |
|
| 4916 | this.focusCommandLine = function() {
|
| 4917 | if (consoleWindowExists()) {
|
| 4918 | getConsoleWindow().focusCommandLine();
|
| 4919 | }
|
| 4920 | };
|
| 4921 |
|
| 4922 | this.focusSearch = function() {
|
| 4923 | if (consoleWindowExists()) {
|
| 4924 | getConsoleWindow().focusSearch();
|
| 4925 | }
|
| 4926 | };
|
| 4927 |
|
| 4928 | var commandWindow = window;
|
| 4929 |
|
| 4930 | this.getCommandWindow = function() { return commandWindow; };
|
| 4931 | this.setCommandWindow = function(commandWindowParam) {
|
| 4932 | commandWindow = commandWindowParam;
|
| 4933 | };
|
| 4934 |
|
| 4935 | this.executeLastCommand = function() {
|
| 4936 | if (consoleWindowExists()) {
|
| 4937 | getConsoleWindow().evalLastCommand();
|
| 4938 | }
|
| 4939 | };
|
| 4940 |
|
| 4941 | var commandLayout = new PatternLayout("%m");
|
| 4942 | this.getCommandLayout = function() { return commandLayout; };
|
| 4943 | this.setCommandLayout = function(commandLayoutParam) {
|
| 4944 | commandLayout = commandLayoutParam;
|
| 4945 | };
|
| 4946 |
|
| 4947 | this.evalCommandAndAppend = function(expr) {
|
| 4948 | var commandReturnValue = { appendResult: true, isError: false };
|
| 4949 | var commandOutput = "";
|
| 4950 | // Evaluate the command
|
| 4951 | try {
|
| 4952 | var result, i;
|
| 4953 | // The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no
|
| 4954 | // eval method on the window object initially, but once execScript has been called on
|
| 4955 | // it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25
|
| 4956 | if (!commandWindow.eval && commandWindow.execScript) {
|
| 4957 | commandWindow.execScript("null");
|
| 4958 | }
|
| 4959 |
|
| 4960 | var commandLineFunctionsHash = {};
|
| 4961 | for (i = 0, len = commandLineFunctions.length; i < len; i++) {
|
| 4962 | commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];
|
| 4963 | }
|
| 4964 |
|
| 4965 | // Keep an array of variables that are being changed in the command window so that they
|
| 4966 | // can be restored to their original values afterwards
|
| 4967 | var objectsToRestore = [];
|
| 4968 | var addObjectToRestore = function(name) {
|
| 4969 | objectsToRestore.push([name, commandWindow[name]]);
|
| 4970 | };
|
| 4971 |
|
| 4972 | addObjectToRestore("appender");
|
| 4973 | commandWindow.appender = appender;
|
| 4974 |
|
| 4975 | addObjectToRestore("commandReturnValue");
|
| 4976 | commandWindow.commandReturnValue = commandReturnValue;
|
| 4977 |
|
| 4978 | addObjectToRestore("commandLineFunctionsHash");
|
| 4979 | commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;
|
| 4980 |
|
| 4981 | var addFunctionToWindow = function(name) {
|
| 4982 | addObjectToRestore(name);
|
| 4983 | commandWindow[name] = function() {
|
| 4984 | return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);
|
| 4985 | };
|
| 4986 | };
|
| 4987 |
|
| 4988 | for (i = 0, len = commandLineFunctions.length; i < len; i++) {
|
| 4989 | addFunctionToWindow(commandLineFunctions[i][0]);
|
| 4990 | }
|
| 4991 |
|
| 4992 | // Another bizarre workaround to get IE to eval in the global scope
|
| 4993 | if (commandWindow === window && commandWindow.execScript) {
|
| 4994 | addObjectToRestore("evalExpr");
|
| 4995 | addObjectToRestore("result");
|
| 4996 | window.evalExpr = expr;
|
| 4997 | commandWindow.execScript("window.result=eval(window.evalExpr);");
|
| 4998 | result = window.result;
|
| 4999 | } else {
|
| 5000 | result = commandWindow.eval(expr);
|
| 5001 | }
|
| 5002 | commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);
|
| 5003 |
|
| 5004 | // Restore variables in the command window to their original state
|
| 5005 | for (i = 0, len = objectsToRestore.length; i < len; i++) {
|
| 5006 | commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];
|
| 5007 | }
|
| 5008 | } catch (ex) {
|
| 5009 | commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);
|
| 5010 | commandReturnValue.isError = true;
|
| 5011 | }
|
| 5012 | // Append command output
|
| 5013 | if (commandReturnValue.appendResult) {
|
| 5014 | var message = ">>> " + expr;
|
| 5015 | if (!isUndefined(commandOutput)) {
|
| 5016 | message += newLine + commandOutput;
|
| 5017 | }
|
| 5018 | var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;
|
| 5019 | var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);
|
| 5020 | var mainLayout = this.getLayout();
|
| 5021 | this.setLayout(commandLayout);
|
| 5022 | this.append(loggingEvent);
|
| 5023 | this.setLayout(mainLayout);
|
| 5024 | }
|
| 5025 | };
|
| 5026 |
|
| 5027 | var commandLineFunctions = defaultCommandLineFunctions.concat([]);
|
| 5028 |
|
| 5029 | this.addCommandLineFunction = function(functionName, commandLineFunction) {
|
| 5030 | commandLineFunctions.push([functionName, commandLineFunction]);
|
| 5031 | };
|
| 5032 |
|
| 5033 | var commandHistoryCookieName = "log4javascriptCommandHistory";
|
| 5034 | this.storeCommandHistory = function(commandHistory) {
|
| 5035 | setCookie(commandHistoryCookieName, commandHistory.join(","));
|
| 5036 | };
|
| 5037 |
|
| 5038 | var writeHtml = function(doc) {
|
| 5039 | var lines = getConsoleHtmlLines();
|
| 5040 | doc.open();
|
| 5041 | for (var i = 0, len = lines.length; i < len; i++) {
|
| 5042 | doc.writeln(lines[i]);
|
| 5043 | }
|
| 5044 | doc.close();
|
| 5045 | };
|
| 5046 |
|
| 5047 | // Set up event listeners
|
| 5048 | this.setEventTypes(["load", "unload"]);
|
| 5049 |
|
| 5050 | var consoleWindowLoadHandler = function() {
|
| 5051 | var win = getConsoleWindow();
|
| 5052 | win.setAppender(appender);
|
| 5053 | win.setNewestAtTop(newestMessageAtTop);
|
| 5054 | win.setScrollToLatest(scrollToLatestMessage);
|
| 5055 | win.setMaxMessages(maxMessages);
|
| 5056 | win.setShowCommandLine(showCommandLine);
|
| 5057 | win.setShowHideButton(showHideButton);
|
| 5058 | win.setShowCloseButton(showCloseButton);
|
| 5059 | win.setMainWindow(window);
|
| 5060 |
|
| 5061 | // Restore command history stored in cookie
|
| 5062 | var storedValue = getCookie(commandHistoryCookieName);
|
| 5063 | if (storedValue) {
|
| 5064 | win.commandHistory = storedValue.split(",");
|
| 5065 | win.currentCommandIndex = win.commandHistory.length;
|
| 5066 | }
|
| 5067 |
|
| 5068 | appender.dispatchEvent("load", { "win" : win });
|
| 5069 | };
|
| 5070 |
|
| 5071 | this.unload = function() {
|
| 5072 | logLog.debug("unload " + this + ", caller: " + this.unload.caller);
|
| 5073 | if (!consoleClosed) {
|
| 5074 | logLog.debug("really doing unload " + this);
|
| 5075 | consoleClosed = true;
|
| 5076 | consoleWindowLoaded = false;
|
| 5077 | consoleWindowCreated = false;
|
| 5078 | appender.dispatchEvent("unload", {});
|
| 5079 | }
|
| 5080 | };
|
| 5081 |
|
| 5082 | var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {
|
| 5083 | function doPoll() {
|
| 5084 | try {
|
| 5085 | // Test if the console has been closed while polling
|
| 5086 | if (consoleClosed) {
|
| 5087 | clearInterval(poll);
|
| 5088 | }
|
| 5089 | if (windowTest(getConsoleWindow())) {
|
| 5090 | clearInterval(poll);
|
| 5091 | successCallback();
|
| 5092 | }
|
| 5093 | } catch (ex) {
|
| 5094 | clearInterval(poll);
|
| 5095 | isSupported = false;
|
| 5096 | handleError(errorMessage, ex);
|
| 5097 | }
|
| 5098 | }
|
| 5099 |
|
| 5100 | // Poll the pop-up since the onload event is not reliable
|
| 5101 | var poll = setInterval(doPoll, interval);
|
| 5102 | };
|
| 5103 |
|
| 5104 | var getConsoleUrl = function() {
|
| 5105 | var documentDomainSet = (document.domain != location.hostname);
|
| 5106 | return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +
|
| 5107 | (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");
|
| 5108 | };
|
| 5109 |
|
| 5110 | // Define methods and properties that vary between subclasses
|
| 5111 | if (inPage) {
|
| 5112 | // InPageAppender
|
| 5113 |
|
| 5114 | var containerElement = null;
|
| 5115 |
|
| 5116 | // Configuration methods. The function scope is used to prevent
|
| 5117 | // direct alteration to the appender configuration properties.
|
| 5118 | var cssProperties = [];
|
| 5119 | this.addCssProperty = function(name, value) {
|
| 5120 | if (checkCanConfigure("cssProperties")) {
|
| 5121 | cssProperties.push([name, value]);
|
| 5122 | }
|
| 5123 | };
|
| 5124 |
|
| 5125 | // Define useful variables
|
| 5126 | var windowCreationStarted = false;
|
| 5127 | var iframeContainerDiv;
|
| 5128 | var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;
|
| 5129 |
|
| 5130 | this.hide = function() {
|
| 5131 | if (initialized && consoleWindowCreated) {
|
| 5132 | if (consoleWindowExists()) {
|
| 5133 | getConsoleWindow().$("command").blur();
|
| 5134 | }
|
| 5135 | iframeContainerDiv.style.display = "none";
|
| 5136 | minimized = true;
|
| 5137 | }
|
| 5138 | };
|
| 5139 |
|
| 5140 | this.show = function() {
|
| 5141 | if (initialized) {
|
| 5142 | if (consoleWindowCreated) {
|
| 5143 | iframeContainerDiv.style.display = "block";
|
| 5144 | this.setShowCommandLine(showCommandLine); // Force IE to update
|
| 5145 | minimized = false;
|
| 5146 | } else if (!windowCreationStarted) {
|
| 5147 | createWindow(true);
|
| 5148 | }
|
| 5149 | }
|
| 5150 | };
|
| 5151 |
|
| 5152 | this.isVisible = function() {
|
| 5153 | return !minimized && !consoleClosed;
|
| 5154 | };
|
| 5155 |
|
| 5156 | this.close = function(fromButton) {
|
| 5157 | if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {
|
| 5158 | iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);
|
| 5159 | this.unload();
|
| 5160 | }
|
| 5161 | };
|
| 5162 |
|
| 5163 | // Create open, init, getConsoleWindow and safeToAppend functions
|
| 5164 | open = function() {
|
| 5165 | var initErrorMessage = "InPageAppender.open: unable to create console iframe";
|
| 5166 |
|
| 5167 | function finalInit() {
|
| 5168 | try {
|
| 5169 | if (!initiallyMinimized) {
|
| 5170 | appender.show();
|
| 5171 | }
|
| 5172 | consoleWindowLoadHandler();
|
| 5173 | consoleWindowLoaded = true;
|
| 5174 | appendQueuedLoggingEvents();
|
| 5175 | } catch (ex) {
|
| 5176 | isSupported = false;
|
| 5177 | handleError(initErrorMessage, ex);
|
| 5178 | }
|
| 5179 | }
|
| 5180 |
|
| 5181 | function writeToDocument() {
|
| 5182 | try {
|
| 5183 | var windowTest = function(win) { return isLoaded(win); };
|
| 5184 | if (useDocumentWrite) {
|
| 5185 | writeHtml(getConsoleWindow().document);
|
| 5186 | }
|
| 5187 | if (windowTest(getConsoleWindow())) {
|
| 5188 | finalInit();
|
| 5189 | } else {
|
| 5190 | pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);
|
| 5191 | }
|
| 5192 | } catch (ex) {
|
| 5193 | isSupported = false;
|
| 5194 | handleError(initErrorMessage, ex);
|
| 5195 | }
|
| 5196 | }
|
| 5197 |
|
| 5198 | minimized = false;
|
| 5199 | iframeContainerDiv = containerElement.appendChild(document.createElement("div"));
|
| 5200 |
|
| 5201 | iframeContainerDiv.style.width = width;
|
| 5202 | iframeContainerDiv.style.height = height;
|
| 5203 | iframeContainerDiv.style.border = "solid gray 1px";
|
| 5204 |
|
| 5205 | for (var i = 0, len = cssProperties.length; i < len; i++) {
|
| 5206 | iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];
|
| 5207 | }
|
| 5208 |
|
| 5209 | var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";
|
| 5210 |
|
| 5211 | // Adding an iframe using the DOM would be preferable, but it doesn't work
|
| 5212 | // in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror
|
| 5213 | // it creates the iframe fine but I haven't been able to find a way to obtain
|
| 5214 | // the iframe's window object
|
| 5215 | iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +
|
| 5216 | "' width='100%' height='100%' frameborder='0'" + iframeSrc +
|
| 5217 | " scrolling='no'></iframe>";
|
| 5218 | consoleClosed = false;
|
| 5219 |
|
| 5220 | // Write the console HTML to the iframe
|
| 5221 | var iframeDocumentExistsTest = function(win) {
|
| 5222 | try {
|
| 5223 | return bool(win) && bool(win.document);
|
| 5224 | } catch (ex) {
|
| 5225 | return false;
|
| 5226 | }
|
| 5227 | };
|
| 5228 | if (iframeDocumentExistsTest(getConsoleWindow())) {
|
| 5229 | writeToDocument();
|
| 5230 | } else {
|
| 5231 | pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);
|
| 5232 | }
|
| 5233 | consoleWindowCreated = true;
|
| 5234 | };
|
| 5235 |
|
| 5236 | createWindow = function(show) {
|
| 5237 | if (show || !initiallyMinimized) {
|
| 5238 | var pageLoadHandler = function() {
|
| 5239 | if (!container) {
|
| 5240 | // Set up default container element
|
| 5241 | containerElement = document.createElement("div");
|
| 5242 | containerElement.style.position = "fixed";
|
| 5243 | containerElement.style.left = "0";
|
| 5244 | containerElement.style.right = "0";
|
| 5245 | containerElement.style.bottom = "0";
|
| 5246 | document.body.appendChild(containerElement);
|
| 5247 | appender.addCssProperty("borderWidth", "1px 0 0 0");
|
| 5248 | appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be
|
| 5249 | open();
|
| 5250 | } else {
|
| 5251 | try {
|
| 5252 | var el = document.getElementById(container);
|
| 5253 | if (el.nodeType == 1) {
|
| 5254 | containerElement = el;
|
| 5255 | }
|
| 5256 | open();
|
| 5257 | } catch (ex) {
|
| 5258 | handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);
|
| 5259 | }
|
| 5260 | }
|
| 5261 | };
|
| 5262 |
|
| 5263 | // Test the type of the container supplied. First, check if it's an element
|
| 5264 | if (pageLoaded && container && container.appendChild) {
|
| 5265 | containerElement = container;
|
| 5266 | open();
|
| 5267 | } else if (pageLoaded) {
|
| 5268 | pageLoadHandler();
|
| 5269 | } else {
|
| 5270 | log4javascript.addEventListener("load", pageLoadHandler);
|
| 5271 | }
|
| 5272 | windowCreationStarted = true;
|
| 5273 | }
|
| 5274 | };
|
| 5275 |
|
| 5276 | init = function() {
|
| 5277 | createWindow();
|
| 5278 | initialized = true;
|
| 5279 | };
|
| 5280 |
|
| 5281 | getConsoleWindow = function() {
|
| 5282 | var iframe = window.frames[iframeId];
|
| 5283 | if (iframe) {
|
| 5284 | return iframe;
|
| 5285 | }
|
| 5286 | };
|
| 5287 |
|
| 5288 | safeToAppend = function() {
|
| 5289 | if (isSupported && !consoleClosed) {
|
| 5290 | if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {
|
| 5291 | consoleWindowLoaded = true;
|
| 5292 | }
|
| 5293 | return consoleWindowLoaded;
|
| 5294 | }
|
| 5295 | return false;
|
| 5296 | };
|
| 5297 | } else {
|
| 5298 | // PopUpAppender
|
| 5299 |
|
| 5300 | // Extract params
|
| 5301 | var useOldPopUp = appender.defaults.useOldPopUp;
|
| 5302 | var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;
|
| 5303 | var reopenWhenClosed = this.defaults.reopenWhenClosed;
|
| 5304 |
|
| 5305 | // Configuration methods. The function scope is used to prevent
|
| 5306 | // direct alteration to the appender configuration properties.
|
| 5307 | this.isUseOldPopUp = function() { return useOldPopUp; };
|
| 5308 | this.setUseOldPopUp = function(useOldPopUpParam) {
|
| 5309 | if (checkCanConfigure("useOldPopUp")) {
|
| 5310 | useOldPopUp = bool(useOldPopUpParam);
|
| 5311 | }
|
| 5312 | };
|
| 5313 |
|
| 5314 | this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };
|
| 5315 | this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {
|
| 5316 | if (checkCanConfigure("complainAboutPopUpBlocking")) {
|
| 5317 | complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);
|
| 5318 | }
|
| 5319 | };
|
| 5320 |
|
| 5321 | this.isFocusPopUp = function() { return focusConsoleWindow; };
|
| 5322 | this.setFocusPopUp = function(focusPopUpParam) {
|
| 5323 | // This property can be safely altered after logging has started
|
| 5324 | focusConsoleWindow = bool(focusPopUpParam);
|
| 5325 | };
|
| 5326 |
|
| 5327 | this.isReopenWhenClosed = function() { return reopenWhenClosed; };
|
| 5328 | this.setReopenWhenClosed = function(reopenWhenClosedParam) {
|
| 5329 | // This property can be safely altered after logging has started
|
| 5330 | reopenWhenClosed = bool(reopenWhenClosedParam);
|
| 5331 | };
|
| 5332 |
|
| 5333 | this.close = function() {
|
| 5334 | logLog.debug("close " + this);
|
| 5335 | try {
|
| 5336 | popUp.close();
|
| 5337 | this.unload();
|
| 5338 | } catch (ex) {
|
| 5339 | // Do nothing
|
| 5340 | }
|
| 5341 | };
|
| 5342 |
|
| 5343 | this.hide = function() {
|
| 5344 | logLog.debug("hide " + this);
|
| 5345 | if (consoleWindowExists()) {
|
| 5346 | this.close();
|
| 5347 | }
|
| 5348 | };
|
| 5349 |
|
| 5350 | this.show = function() {
|
| 5351 | logLog.debug("show " + this);
|
| 5352 | if (!consoleWindowCreated) {
|
| 5353 | open();
|
| 5354 | }
|
| 5355 | };
|
| 5356 |
|
| 5357 | this.isVisible = function() {
|
| 5358 | return safeToAppend();
|
| 5359 | };
|
| 5360 |
|
| 5361 | // Define useful variables
|
| 5362 | var popUp;
|
| 5363 |
|
| 5364 | // Create open, init, getConsoleWindow and safeToAppend functions
|
| 5365 | open = function() {
|
| 5366 | var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";
|
| 5367 | var frameInfo = "";
|
| 5368 | try {
|
| 5369 | var frameEl = window.frameElement;
|
| 5370 | if (frameEl) {
|
| 5371 | frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");
|
| 5372 | }
|
| 5373 | } catch (e) {
|
| 5374 | frameInfo = "_inaccessibleParentFrame";
|
| 5375 | }
|
| 5376 | var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;
|
| 5377 | if (!useOldPopUp || !useDocumentWrite) {
|
| 5378 | // Ensure a previous window isn't used by using a unique name
|
| 5379 | windowName = windowName + "_" + uniqueId;
|
| 5380 | }
|
| 5381 |
|
| 5382 | var checkPopUpClosed = function(win) {
|
| 5383 | if (consoleClosed) {
|
| 5384 | return true;
|
| 5385 | } else {
|
| 5386 | try {
|
| 5387 | return bool(win) && win.closed;
|
| 5388 | } catch(ex) {}
|
| 5389 | }
|
| 5390 | return false;
|
| 5391 | };
|
| 5392 |
|
| 5393 | var popUpClosedCallback = function() {
|
| 5394 | if (!consoleClosed) {
|
| 5395 | appender.unload();
|
| 5396 | }
|
| 5397 | };
|
| 5398 |
|
| 5399 | function finalInit() {
|
| 5400 | getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);
|
| 5401 | consoleWindowLoadHandler();
|
| 5402 | consoleWindowLoaded = true;
|
| 5403 | appendQueuedLoggingEvents();
|
| 5404 | pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,
|
| 5405 | "PopUpAppender.checkPopUpClosed: error checking pop-up window");
|
| 5406 | }
|
| 5407 |
|
| 5408 | try {
|
| 5409 | popUp = window.open(getConsoleUrl(), windowName, windowProperties);
|
| 5410 | consoleClosed = false;
|
| 5411 | consoleWindowCreated = true;
|
| 5412 | if (popUp && popUp.document) {
|
| 5413 | if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {
|
| 5414 | popUp.mainPageReloaded();
|
| 5415 | finalInit();
|
| 5416 | } else {
|
| 5417 | if (useDocumentWrite) {
|
| 5418 | writeHtml(popUp.document);
|
| 5419 | }
|
| 5420 | // Check if the pop-up window object is available
|
| 5421 | var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };
|
| 5422 | if (isLoaded(popUp)) {
|
| 5423 | finalInit();
|
| 5424 | } else {
|
| 5425 | pollConsoleWindow(popUpLoadedTest, 100, finalInit,
|
| 5426 | "PopUpAppender.init: unable to create console window");
|
| 5427 | }
|
| 5428 | }
|
| 5429 | } else {
|
| 5430 | isSupported = false;
|
| 5431 | logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");
|
| 5432 | if (complainAboutPopUpBlocking) {
|
| 5433 | handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");
|
| 5434 | }
|
| 5435 | }
|
| 5436 | } catch (ex) {
|
| 5437 | handleError("PopUpAppender.init: error creating pop-up", ex);
|
| 5438 | }
|
| 5439 | };
|
| 5440 |
|
| 5441 | createWindow = function() {
|
| 5442 | if (!initiallyMinimized) {
|
| 5443 | open();
|
| 5444 | }
|
| 5445 | };
|
| 5446 |
|
| 5447 | init = function() {
|
| 5448 | createWindow();
|
| 5449 | initialized = true;
|
| 5450 | };
|
| 5451 |
|
| 5452 | getConsoleWindow = function() {
|
| 5453 | return popUp;
|
| 5454 | };
|
| 5455 |
|
| 5456 | safeToAppend = function() {
|
| 5457 | if (isSupported && !isUndefined(popUp) && !consoleClosed) {
|
| 5458 | if (popUp.closed ||
|
| 5459 | (consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera
|
| 5460 | appender.unload();
|
| 5461 | logLog.debug("PopUpAppender: pop-up closed");
|
| 5462 | return false;
|
| 5463 | }
|
| 5464 | if (!consoleWindowLoaded && isLoaded(popUp)) {
|
| 5465 | consoleWindowLoaded = true;
|
| 5466 | }
|
| 5467 | }
|
| 5468 | return isSupported && consoleWindowLoaded && !consoleClosed;
|
| 5469 | };
|
| 5470 | }
|
| 5471 |
|
| 5472 | // Expose getConsoleWindow so that automated tests can check the DOM
|
| 5473 | this.getConsoleWindow = getConsoleWindow;
|
| 5474 | };
|
| 5475 |
|
| 5476 | ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {
|
| 5477 | defaultCommandLineFunctions.push([functionName, commandLineFunction]);
|
| 5478 | };
|
| 5479 |
|
| 5480 | /* ------------------------------------------------------------------ */
|
| 5481 |
|
| 5482 | function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,
|
| 5483 | width, height) {
|
| 5484 | this.create(false, null, lazyInit, initiallyMinimized,
|
| 5485 | useDocumentWrite, width, height, this.defaults.focusPopUp);
|
| 5486 | }
|
| 5487 |
|
| 5488 | PopUpAppender.prototype = new ConsoleAppender();
|
| 5489 |
|
| 5490 | PopUpAppender.prototype.defaults = {
|
| 5491 | layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),
|
| 5492 | initiallyMinimized: false,
|
| 5493 | focusPopUp: false,
|
| 5494 | lazyInit: true,
|
| 5495 | useOldPopUp: true,
|
| 5496 | complainAboutPopUpBlocking: true,
|
| 5497 | newestMessageAtTop: false,
|
| 5498 | scrollToLatestMessage: true,
|
| 5499 | width: "600",
|
| 5500 | height: "400",
|
| 5501 | reopenWhenClosed: false,
|
| 5502 | maxMessages: null,
|
| 5503 | showCommandLine: true,
|
| 5504 | commandLineObjectExpansionDepth: 1,
|
| 5505 | showHideButton: false,
|
| 5506 | showCloseButton: true,
|
| 5507 | showLogEntryDeleteButtons: true,
|
| 5508 | useDocumentWrite: true
|
| 5509 | };
|
| 5510 |
|
| 5511 | PopUpAppender.prototype.toString = function() {
|
| 5512 | return "PopUpAppender";
|
| 5513 | };
|
| 5514 |
|
| 5515 | log4javascript.PopUpAppender = PopUpAppender;
|
| 5516 |
|
| 5517 | /* ------------------------------------------------------------------ */
|
| 5518 |
|
| 5519 | function InPageAppender(container, lazyInit, initiallyMinimized,
|
| 5520 | useDocumentWrite, width, height) {
|
| 5521 | this.create(true, container, lazyInit, initiallyMinimized,
|
| 5522 | useDocumentWrite, width, height, false);
|
| 5523 | }
|
| 5524 |
|
| 5525 | InPageAppender.prototype = new ConsoleAppender();
|
| 5526 |
|
| 5527 | InPageAppender.prototype.defaults = {
|
| 5528 | layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),
|
| 5529 | initiallyMinimized: false,
|
| 5530 | lazyInit: true,
|
| 5531 | newestMessageAtTop: false,
|
| 5532 | scrollToLatestMessage: true,
|
| 5533 | width: "100%",
|
| 5534 | height: "220px",
|
| 5535 | maxMessages: null,
|
| 5536 | showCommandLine: true,
|
| 5537 | commandLineObjectExpansionDepth: 1,
|
| 5538 | showHideButton: false,
|
| 5539 | showCloseButton: false,
|
| 5540 | showLogEntryDeleteButtons: true,
|
| 5541 | useDocumentWrite: true
|
| 5542 | };
|
| 5543 |
|
| 5544 | InPageAppender.prototype.toString = function() {
|
| 5545 | return "InPageAppender";
|
| 5546 | };
|
| 5547 |
|
| 5548 | log4javascript.InPageAppender = InPageAppender;
|
| 5549 |
|
| 5550 | // Next line for backwards compatibility
|
| 5551 | log4javascript.InlineAppender = InPageAppender;
|
| 5552 | })();
|
| 5553 | /* ---------------------------------------------------------------------- */
|
| 5554 | // Console extension functions
|
| 5555 |
|
| 5556 | function padWithSpaces(str, len) {
|
| 5557 | if (str.length < len) {
|
| 5558 | var spaces = [];
|
| 5559 | var numberOfSpaces = Math.max(0, len - str.length);
|
| 5560 | for (var i = 0; i < numberOfSpaces; i++) {
|
| 5561 | spaces[i] = " ";
|
| 5562 | }
|
| 5563 | str += spaces.join("");
|
| 5564 | }
|
| 5565 | return str;
|
| 5566 | }
|
| 5567 |
|
| 5568 | (function() {
|
| 5569 | function dir(obj) {
|
| 5570 | var maxLen = 0;
|
| 5571 | // Obtain the length of the longest property name
|
| 5572 | for (var p in obj) {
|
| 5573 | maxLen = Math.max(toStr(p).length, maxLen);
|
| 5574 | }
|
| 5575 | // Create the nicely formatted property list
|
| 5576 | var propList = [];
|
| 5577 | for (p in obj) {
|
| 5578 | var propNameStr = " " + padWithSpaces(toStr(p), maxLen + 2);
|
| 5579 | var propVal;
|
| 5580 | try {
|
| 5581 | propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));
|
| 5582 | } catch (ex) {
|
| 5583 | propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";
|
| 5584 | }
|
| 5585 | propList.push(propNameStr + propVal);
|
| 5586 | }
|
| 5587 | return propList.join(newLine);
|
| 5588 | }
|
| 5589 |
|
| 5590 | var nodeTypes = {
|
| 5591 | ELEMENT_NODE: 1,
|
| 5592 | ATTRIBUTE_NODE: 2,
|
| 5593 | TEXT_NODE: 3,
|
| 5594 | CDATA_SECTION_NODE: 4,
|
| 5595 | ENTITY_REFERENCE_NODE: 5,
|
| 5596 | ENTITY_NODE: 6,
|
| 5597 | PROCESSING_INSTRUCTION_NODE: 7,
|
| 5598 | COMMENT_NODE: 8,
|
| 5599 | DOCUMENT_NODE: 9,
|
| 5600 | DOCUMENT_TYPE_NODE: 10,
|
| 5601 | DOCUMENT_FRAGMENT_NODE: 11,
|
| 5602 | NOTATION_NODE: 12
|
| 5603 | };
|
| 5604 |
|
| 5605 | var preFormattedElements = ["script", "pre"];
|
| 5606 |
|
| 5607 | // This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD
|
| 5608 | var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];
|
| 5609 | var indentationUnit = " ";
|
| 5610 |
|
| 5611 | // Create and return an XHTML string from the node specified
|
| 5612 | function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {
|
| 5613 | includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;
|
| 5614 | if (typeof indentation != "string") {
|
| 5615 | indentation = "";
|
| 5616 | }
|
| 5617 | startNewLine = !!startNewLine;
|
| 5618 | preformatted = !!preformatted;
|
| 5619 | var xhtml;
|
| 5620 |
|
| 5621 | function isWhitespace(node) {
|
| 5622 | return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));
|
| 5623 | }
|
| 5624 |
|
| 5625 | function fixAttributeValue(attrValue) {
|
| 5626 | return attrValue.toString().replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """);
|
| 5627 | }
|
| 5628 |
|
| 5629 | function getStyleAttributeValue(el) {
|
| 5630 | var stylePairs = el.style.cssText.split(";");
|
| 5631 | var styleValue = "";
|
| 5632 | var isFirst = true;
|
| 5633 | for (var j = 0, len = stylePairs.length; j < len; j++) {
|
| 5634 | var nameValueBits = stylePairs[j].split(":");
|
| 5635 | var props = [];
|
| 5636 | if (!/^\s*$/.test(nameValueBits[0])) {
|
| 5637 | props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));
|
| 5638 | }
|
| 5639 | styleValue = props.join(";");
|
| 5640 | }
|
| 5641 | return styleValue;
|
| 5642 | }
|
| 5643 |
|
| 5644 | function getNamespace(el) {
|
| 5645 | if (el.prefix) {
|
| 5646 | return el.prefix;
|
| 5647 | } else if (el.outerHTML) {
|
| 5648 | var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");
|
| 5649 | if (regex.test(el.outerHTML)) {
|
| 5650 | return RegExp.$1.toLowerCase();
|
| 5651 | }
|
| 5652 | }
|
| 5653 | return "";
|
| 5654 | }
|
| 5655 |
|
| 5656 | var lt = "<";
|
| 5657 | var gt = ">";
|
| 5658 |
|
| 5659 | if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {
|
| 5660 | switch (rootNode.nodeType) {
|
| 5661 | case nodeTypes.ELEMENT_NODE:
|
| 5662 | var tagName = rootNode.tagName.toLowerCase();
|
| 5663 | xhtml = startNewLine ? newLine + indentation : "";
|
| 5664 | xhtml += lt;
|
| 5665 | // Allow for namespaces, where present
|
| 5666 | var prefix = getNamespace(rootNode);
|
| 5667 | var hasPrefix = !!prefix;
|
| 5668 | if (hasPrefix) {
|
| 5669 | xhtml += prefix + ":";
|
| 5670 | }
|
| 5671 | xhtml += tagName;
|
| 5672 | for (i = 0, len = rootNode.attributes.length; i < len; i++) {
|
| 5673 | var currentAttr = rootNode.attributes[i];
|
| 5674 | // Check the attribute is valid.
|
| 5675 | if (! currentAttr.specified ||
|
| 5676 | currentAttr.nodeValue === null ||
|
| 5677 | currentAttr.nodeName.toLowerCase() === "style" ||
|
| 5678 | typeof currentAttr.nodeValue !== "string" ||
|
| 5679 | currentAttr.nodeName.indexOf("_moz") === 0) {
|
| 5680 | continue;
|
| 5681 | }
|
| 5682 | xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";
|
| 5683 | xhtml += fixAttributeValue(currentAttr.nodeValue);
|
| 5684 | xhtml += "\"";
|
| 5685 | }
|
| 5686 | // Style needs to be done separately as it is not reported as an
|
| 5687 | // attribute in IE
|
| 5688 | if (rootNode.style.cssText) {
|
| 5689 | var styleValue = getStyleAttributeValue(rootNode);
|
| 5690 | if (styleValue !== "") {
|
| 5691 | xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";
|
| 5692 | }
|
| 5693 | }
|
| 5694 | if (array_contains(emptyElements, tagName) ||
|
| 5695 | (hasPrefix && !rootNode.hasChildNodes())) {
|
| 5696 | xhtml += "/" + gt;
|
| 5697 | } else {
|
| 5698 | xhtml += gt;
|
| 5699 | // Add output for childNodes collection (which doesn't include attribute nodes)
|
| 5700 | var childStartNewLine = !(rootNode.childNodes.length === 1 &&
|
| 5701 | rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);
|
| 5702 | var childPreformatted = array_contains(preFormattedElements, tagName);
|
| 5703 | for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {
|
| 5704 | xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,
|
| 5705 | childStartNewLine, childPreformatted);
|
| 5706 | }
|
| 5707 | // Add the end tag
|
| 5708 | var endTag = lt + "/" + tagName + gt;
|
| 5709 | xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;
|
| 5710 | }
|
| 5711 | return xhtml;
|
| 5712 | case nodeTypes.TEXT_NODE:
|
| 5713 | if (isWhitespace(rootNode)) {
|
| 5714 | xhtml = "";
|
| 5715 | } else {
|
| 5716 | if (preformatted) {
|
| 5717 | xhtml = rootNode.nodeValue;
|
| 5718 | } else {
|
| 5719 | // Trim whitespace from each line of the text node
|
| 5720 | var lines = splitIntoLines(trim(rootNode.nodeValue));
|
| 5721 | var trimmedLines = [];
|
| 5722 | for (var i = 0, len = lines.length; i < len; i++) {
|
| 5723 | trimmedLines[i] = trim(lines[i]);
|
| 5724 | }
|
| 5725 | xhtml = trimmedLines.join(newLine + indentation);
|
| 5726 | }
|
| 5727 | if (startNewLine) {
|
| 5728 | xhtml = newLine + indentation + xhtml;
|
| 5729 | }
|
| 5730 | }
|
| 5731 | return xhtml;
|
| 5732 | case nodeTypes.CDATA_SECTION_NODE:
|
| 5733 | return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;
|
| 5734 | case nodeTypes.DOCUMENT_NODE:
|
| 5735 | xhtml = "";
|
| 5736 | // Add output for childNodes collection (which doesn't include attribute nodes)
|
| 5737 | for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {
|
| 5738 | xhtml += getXhtml(rootNode.childNodes[i], true, indentation);
|
| 5739 | }
|
| 5740 | return xhtml;
|
| 5741 | default:
|
| 5742 | return "";
|
| 5743 | }
|
| 5744 | } else {
|
| 5745 | xhtml = "";
|
| 5746 | // Add output for childNodes collection (which doesn't include attribute nodes)
|
| 5747 | for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {
|
| 5748 | xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);
|
| 5749 | }
|
| 5750 | return xhtml;
|
| 5751 | }
|
| 5752 | }
|
| 5753 |
|
| 5754 | function createCommandLineFunctions() {
|
| 5755 | ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {
|
| 5756 | return document.getElementById(args[0]);
|
| 5757 | });
|
| 5758 |
|
| 5759 | ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {
|
| 5760 | var lines = [];
|
| 5761 | for (var i = 0, len = args.length; i < len; i++) {
|
| 5762 | lines[i] = dir(args[i]);
|
| 5763 | }
|
| 5764 | return lines.join(newLine + newLine);
|
| 5765 | });
|
| 5766 |
|
| 5767 | ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {
|
| 5768 | var lines = [];
|
| 5769 | for (var i = 0, len = args.length; i < len; i++) {
|
| 5770 | var win = appender.getCommandWindow();
|
| 5771 | lines[i] = getXhtml(args[i]);
|
| 5772 | }
|
| 5773 | return lines.join(newLine + newLine);
|
| 5774 | });
|
| 5775 |
|
| 5776 | ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {
|
| 5777 | var win, message;
|
| 5778 | if (args.length === 0 || args[0] === "") {
|
| 5779 | win = window;
|
| 5780 | message = "Command line set to run in main window";
|
| 5781 | } else {
|
| 5782 | if (args[0].window == args[0]) {
|
| 5783 | win = args[0];
|
| 5784 | message = "Command line set to run in frame '" + args[0].name + "'";
|
| 5785 | } else {
|
| 5786 | win = window.frames[args[0]];
|
| 5787 | if (win) {
|
| 5788 | message = "Command line set to run in frame '" + args[0] + "'";
|
| 5789 | } else {
|
| 5790 | returnValue.isError = true;
|
| 5791 | message = "Frame '" + args[0] + "' does not exist";
|
| 5792 | win = appender.getCommandWindow();
|
| 5793 | }
|
| 5794 | }
|
| 5795 | }
|
| 5796 | appender.setCommandWindow(win);
|
| 5797 | return message;
|
| 5798 | });
|
| 5799 |
|
| 5800 | ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {
|
| 5801 | returnValue.appendResult = false;
|
| 5802 | appender.clear();
|
| 5803 | });
|
| 5804 |
|
| 5805 | ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {
|
| 5806 | var keys = [];
|
| 5807 | for (var k in args[0]) {
|
| 5808 | keys.push(k);
|
| 5809 | }
|
| 5810 | return keys;
|
| 5811 | });
|
| 5812 |
|
| 5813 | ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {
|
| 5814 | var values = [];
|
| 5815 | for (var k in args[0]) {
|
| 5816 | try {
|
| 5817 | values.push(args[0][k]);
|
| 5818 | } catch (ex) {
|
| 5819 | logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));
|
| 5820 | }
|
| 5821 | }
|
| 5822 | return values;
|
| 5823 | });
|
| 5824 |
|
| 5825 | ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {
|
| 5826 | var expansionDepth = parseInt(args[0], 10);
|
| 5827 | if (isNaN(expansionDepth) || expansionDepth < 0) {
|
| 5828 | returnValue.isError = true;
|
| 5829 | return "" + args[0] + " is not a valid expansion depth";
|
| 5830 | } else {
|
| 5831 | appender.setCommandLineObjectExpansionDepth(expansionDepth);
|
| 5832 | return "Object expansion depth set to " + expansionDepth;
|
| 5833 | }
|
| 5834 | });
|
| 5835 | }
|
| 5836 |
|
| 5837 | function init() {
|
| 5838 | // Add command line functions
|
| 5839 | createCommandLineFunctions();
|
| 5840 | }
|
| 5841 |
|
| 5842 | /* ------------------------------------------------------------------ */
|
| 5843 |
|
| 5844 | init();
|
| 5845 | })();
|
| 5846 |
|
| 5847 | /* ---------------------------------------------------------------------- */
|
| 5848 | // Main load
|
| 5849 |
|
| 5850 | log4javascript.setDocumentReady = function() {
|
| 5851 | pageLoaded = true;
|
| 5852 | log4javascript.dispatchEvent("load", {});
|
| 5853 | };
|
| 5854 |
|
| 5855 | if (window.addEventListener) {
|
| 5856 | window.addEventListener("load", log4javascript.setDocumentReady, false);
|
| 5857 | } else if (window.attachEvent) {
|
| 5858 | window.attachEvent("onload", log4javascript.setDocumentReady);
|
| 5859 | } else {
|
| 5860 | var oldOnload = window.onload;
|
| 5861 | if (typeof window.onload != "function") {
|
| 5862 | window.onload = log4javascript.setDocumentReady;
|
| 5863 | } else {
|
| 5864 | window.onload = function(evt) {
|
| 5865 | if (oldOnload) {
|
| 5866 | oldOnload(evt);
|
| 5867 | }
|
| 5868 | log4javascript.setDocumentReady();
|
| 5869 | };
|
| 5870 | }
|
| 5871 | }
|
| 5872 |
|
| 5873 | // Ensure that the log4javascript object is available in the window. This
|
| 5874 | // is necessary for log4javascript to be available in IE if loaded using
|
| 5875 | // Dojo's module system
|
| 5876 | window.log4javascript = log4javascript;
|
| 5877 |
|
| 5878 | return log4javascript;
|
| 5879 | })(); |