|
39 | 39 | * @property {jquery} output |
40 | 40 | */ |
41 | 41 | this.output = $("#trace"); |
| 42 | + |
| 43 | + /** |
| 44 | + * A stack of jquery elements representing log groups, so that logs can be |
| 45 | + * added to the proper groups. |
| 46 | + * @property {Array} groupStack |
| 47 | + */ |
| 48 | + this.groupStack = []; |
| 49 | + |
| 50 | + /** |
| 51 | + * The next id for a group to ensure unique ids for each one. |
| 52 | + * @property {Number} nextGroupId |
| 53 | + */ |
| 54 | + this.nextGroupId = 0; |
42 | 55 |
|
43 | 56 | /** |
44 | 57 | * Clear the output on a new session |
|
132 | 145 | this.setFilters(filters ? filters.split(',') : allFilters); |
133 | 146 |
|
134 | 147 | this.clear(); |
| 148 | + |
| 149 | + if(DEBUG) |
| 150 | + window.RemoteTrace = this; |
135 | 151 | }; |
136 | 152 |
|
137 | 153 | // Reference to the prototype |
|
245 | 261 | p.clear = function() |
246 | 262 | { |
247 | 263 | this.output.empty(); |
| 264 | + this.groupStack.length = 0; |
248 | 265 | this.saveButton.addClass('disabled'); |
249 | 266 | this.clearButton.addClass('disabled'); |
250 | 267 | }; |
|
314 | 331 |
|
315 | 332 | result = JSON.parse(result); |
316 | 333 |
|
317 | | - var level = (result.level || "GENERAL").toLowerCase(); |
318 | | - var now = (new Date()).toLocaleString(); |
| 334 | + var level = (result.level || "GENERAL").toLowerCase(), |
| 335 | + stack = result.stack; |
| 336 | + |
| 337 | + var now = new Date(); |
| 338 | + if(result.time) |
| 339 | + now.setTime(result.time); |
| 340 | + now = now.toLocaleString(); |
319 | 341 |
|
320 | 342 | this.saveButton.removeClass('disabled'); |
321 | 343 | this.clearButton.removeClass('disabled'); |
|
326 | 348 | } |
327 | 349 | else if(level == "clear") |
328 | 350 | { |
| 351 | + this.clear(); |
329 | 352 | } |
330 | | - else if(level == "group") |
331 | | - { |
332 | | - } |
333 | | - else if(level == "groupCollapsed") |
| 353 | + else if(level == "group" || level == "groupcollapsed") |
334 | 354 | { |
| 355 | + var log = this.prepareAndLogMessage(now, result.message, "general", stack), |
| 356 | + groupId = "group_" + this.nextGroupId++; |
| 357 | + var chevron = $("<span class='groupToggle' data-toggle='collapse' data-target='#" + groupId + "'></span>"); |
| 358 | + chevron.append( |
| 359 | + $("<span class='glyphicon glyphicon-chevron-right right'></span>"), |
| 360 | + $("<span class='glyphicon glyphicon-chevron-down down'></span>") |
| 361 | + ); |
| 362 | + log.prepend(chevron); |
| 363 | + |
| 364 | + var group = $("<div class='group log collapse in' id='" + groupId + "'></div>"); |
| 365 | + this.getLogParent().append(group); |
| 366 | + this.groupStack.push(group); |
| 367 | + |
| 368 | + if(level == "groupcollapsed") |
| 369 | + { |
| 370 | + chevron.addClass("collapsed"); |
| 371 | + group.collapse("hide");//.removeClass("in"); |
| 372 | + } |
335 | 373 | } |
336 | | - else if(level == "groupEnd") |
| 374 | + else if(level == "groupend") |
337 | 375 | { |
| 376 | + this.groupStack.pop(); |
338 | 377 | } |
339 | 378 | else if (Array.isArray(result.message)) |
340 | 379 | { |
341 | | - var message, i, j, tokens, token, sub; |
342 | | - |
343 | | - for (i = 0; i < result.message.length; i++) |
344 | | - { |
345 | | - message = result.message[i]; |
346 | | - |
347 | | - // Ignore non-strings |
348 | | - if (typeof message == "string") |
349 | | - { |
350 | | - tokens = message.match(/%[sdifoObxec]/g); |
351 | | - |
352 | | - if (tokens) |
353 | | - { |
354 | | - for (j = 0; j < tokens.length; j++) |
355 | | - { |
356 | | - token = tokens[j]; |
357 | | - sub = result.message[++i]; |
358 | | - |
359 | | - // CSS substitution check |
360 | | - if (token == "%c") |
361 | | - { |
362 | | - sub = '<span style="'+ sub + '">'; |
363 | | - message += '</span>'; |
364 | | - } |
365 | | - // Do object substitution |
366 | | - else if (token == "%o" || token == "%O") |
367 | | - { |
368 | | - sub = JSON.stringify(sub, null, "\t"); |
369 | | - } |
370 | | - else if(token == "%d" || token == "%i") |
371 | | - { |
372 | | - sub = parseInt(sub); |
373 | | - } |
374 | | - message = message.replace(token, String(sub)); |
375 | | - } |
376 | | - } |
377 | | - } |
378 | | - this.logMessage(now, message, level); |
379 | | - } |
| 380 | + this.prepareAndLogMessage(now, result.message, level, stack); |
380 | 381 | } |
381 | 382 |
|
382 | 383 | if (this.maxLogs) |
|
390 | 391 | this.output.scrollTop(this.output[0].scrollHeight); |
391 | 392 | } |
392 | 393 | }; |
| 394 | + |
| 395 | + p.prepareAndLogMessage = function(now, messages, level, stack) |
| 396 | + { |
| 397 | + if(!messages || !messages.length) |
| 398 | + { |
| 399 | + return this.logMessage(now, [""], level, stack); |
| 400 | + } |
| 401 | + |
| 402 | + var message, j, tokens, token, sub; |
| 403 | + |
| 404 | + message = messages[0]; |
| 405 | + |
| 406 | + //if the first message is a string, then check it for string formatting tokens |
| 407 | + if (typeof message == "string") |
| 408 | + { |
| 409 | + tokens = message.match(/%[sdifoObxec]/g); |
| 410 | + |
| 411 | + if (tokens) |
| 412 | + { |
| 413 | + for (j = 0; j < tokens.length; j++) |
| 414 | + { |
| 415 | + token = tokens[j]; |
| 416 | + sub = messages[1]; |
| 417 | + |
| 418 | + // CSS substitution check |
| 419 | + if (token == "%c") |
| 420 | + { |
| 421 | + sub = '<span style="'+ sub + '">'; |
| 422 | + message += '</span>'; |
| 423 | + } |
| 424 | + // Do object substitution |
| 425 | + else if (token == "%o" || token == "%O") |
| 426 | + { |
| 427 | + sub = JSON.stringify(sub, null, "\t"); |
| 428 | + } |
| 429 | + else if(token == "%d" || token == "%i") |
| 430 | + { |
| 431 | + sub = parseInt(sub); |
| 432 | + } |
| 433 | + message = message.replace(token, String(sub)); |
| 434 | + |
| 435 | + messages.splice(1, 1); |
| 436 | + } |
| 437 | + } |
| 438 | + messages[0] = message; |
| 439 | + } |
| 440 | + return this.logMessage(now, messages, level, stack); |
| 441 | + }; |
393 | 442 |
|
394 | 443 | /** |
395 | 444 | * Log a new message |
396 | 445 | * @method logMessage |
397 | 446 | * @param {String} now The current time name |
398 | | - * @param {String} message The message to log |
| 447 | + * @param {Array} messages The message to log |
399 | 448 | * @param {String} level The level to use |
| 449 | + * @param {Array} [stack] The stack trace for the log. |
400 | 450 | */ |
401 | | - p.logMessage = function(now, message, level) |
| 451 | + p.logMessage = function(now, messages, level, stack) |
402 | 452 | { |
403 | | - if (typeof message === "object") |
| 453 | + var message = ""; |
| 454 | + for(var i = 0; i < messages.length; ++i) |
404 | 455 | { |
405 | | - message = JSON.stringify(message, null, "\t"); |
| 456 | + if(i > 0) |
| 457 | + message += " "; |
| 458 | + if (typeof message === "object") |
| 459 | + { |
| 460 | + message += JSON.stringify(messages[i], null, "\t"); |
| 461 | + } |
| 462 | + else |
| 463 | + message += messages[i]; |
406 | 464 | } |
407 | | - this.output.append( |
408 | | - $("<div class='log'></div>") |
409 | | - .addClass(level) |
410 | | - .append( |
411 | | - $("<span class='type'></span>").text(level.toUpperCase()), |
412 | | - $("<span class='timestamp'></span>").text(now), |
413 | | - $("<span class='message'></span>").html(message) |
414 | | - ) |
| 465 | + var log = $("<div class='log'></div>") |
| 466 | + .addClass(level) |
| 467 | + .append( |
| 468 | + $("<span class='type'></span>").text(level.toUpperCase()), |
| 469 | + $("<span class='timestamp'></span>").text(now), |
| 470 | + $("<span class='message'></span>").html(message) |
415 | 471 | ); |
| 472 | + this.getLogParent().append(log); |
| 473 | + return log; |
| 474 | + }; |
| 475 | + |
| 476 | + /** |
| 477 | + * Gets the JQuery element that logs should be added to. |
| 478 | + * @method getLogParent |
| 479 | + * @return {jquery} The div to add logs to. |
| 480 | + */ |
| 481 | + p.getLogParent = function() |
| 482 | + { |
| 483 | + if(this.groupStack.length) |
| 484 | + return this.groupStack[this.groupStack.length - 1]; |
| 485 | + return this.output; |
416 | 486 | }; |
417 | 487 |
|
418 | 488 | /** |
|
0 commit comments