Before creating an own solution I tried finding something which already suits my needs. I have got a node.js server where multiple clients / applications connect to. These clients will send log messages to the server which I would like to display in a panel.
Now there are some feature I that I need for a typical multiline textbox for logmessages:
I need to be able to append log messages as they will be send regularly via websockets
It should autoscrolldown unless the user is selecting text or scrolling up
It should be able to use colors and bold/regular
My question:
Is there already a solution for the above use case?
Can I give you my example? It used to be a textarea but I've refactored it to a div with little code changes.
Some highlights of the code, available on github
A custom function to send log messages:
/**
* Add a message to the gamelog
* #param {Object} options : allows custom output
* #param {String} options.message : the message to display
* #param {Boolean} options.isTimed : does the message has a timestamp in front of it?
* #param {Boolean} options.isError : is the message an error?
* #param {Boolean} options.isNewline : start the message on a new line
*/
addMessage: function (options) {
var instance = ns.instance,
audio = instance.audio,
audiofx = audio.settings.fx,
history = this.areaMessage.html();
// isTimed?
options.message = options.isTimed
? history + this.fieldClock.val() + ': ' + options.message
: history + options.message;
// isNewline?
if (options.isNewline) {
options.message = options.message + '<br />';
}
// message
this.areaMessage.html(options.message);
this.scrollTop(this.areaMessage);
// isError?
if (options.isError) {
audio.play(audiofx.error);
}
},
A scroll to top function:
/**
* Automatically scroll down (from the top)
* #param {Object} target : jQuery object
*/
scrollTop: function (target) {
target.scrollTop(99999);
target.scrollTop(target.scrollTop() * 12);
}
To use colored messages you should be able to use an HTML string:
log.addMessage({
message: '<span style="color: red;">[ERROR]</span> ',
isNewLine: false
});
log.addMessage({
message: 'the rest of the error message',
isNewLine: true
});
Feel free to use this idea to enroll your own custom message box.
Related
I'm trying to get the values from two transaction body field using this code below .
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*#param {Record} context.currentRecord
*/
define(['N/record'],
function (msg) {
function beforeSubmit(context) {
try {
var record = context.currentRecord;
var createdDate = record.getValue({
fieldId: 'createddate'
});
var dataNecessidade = record.getValue({
fieldId: 'custbodyek_data_nece_requ_po'
});
console.log(createdDate ,dataNecessidade);
}
catch(ex){
log.error(ex);
}
}
return {
beforeSubmit : beforeSubmit,
};
});
The error raised is "TypeError: Cannot call method "getValue" of undefined"
What I'm doing wrong here?
Thank you!
There is no currentRecord property on the context passed into a user event, hence the error message telling you that record is undefined. Review the docs for the beforeSubmit entry point to find the appropriate values.
On SuiteScript 2 each entry point has different parameters so you need to check those parameters on the Help or if you use an IDE like Eclipse, you will get that information when you create a new script, so for a UserEvent script and the beforeSubmit entry point, you will get something like this:
/**
* Function definition to be triggered before record is loaded.
*
* Task #5060 : calculate PO Spent Amount and Balance in realtime
*
* #param {Object} scriptContext
* #param {Record} scriptContext.newRecord - New record
* #param {Record} scriptContext.oldRecord - Old record
* #param {string} scriptContext.type - Trigger type
* #Since 2015.2
*/
and then you can see that the context parameter doesn't have a currentRecord property, instead, it has two other parameters that you can use newRecord or oldRecord so your code can be like this:
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*#param {Record} context.currentRecord
*/
define(['N/record'],
function (msg) {
// are you aware that you are "injecting" the 'N/record' library into the 'msg' variable ???
function beforeSubmit(context) {
try {
var record = context.newRecord;
var createdDate = record.getValue({
fieldId: 'createddate'
});
var dataNecessidade = record.getValue({
fieldId: 'custbodyek_data_nece_requ_po'
});
console.log(createdDate ,dataNecessidade);
}
catch(ex){
log.error(ex);
}
}
return {
beforeSubmit : beforeSubmit,
};
});
You try to write it like this, I always use this method to get the field value.
const bfRecord= context.newRecord;
const createdDate = bfRecord.getValue('createddate');
i'm a newbie. first sorry for my English. I'm here trying to make a website with wordpress and have some difficult time when i trying to modify a plugin function because i have no basic skill on programming, even a pro need time to edit another developer code.
But i'm here to learn, i have stuck on this function for like 1 month with out any progress and no results.
So, i have two plugin, one name "fancy product designer" is a Woocommerce Product editor where customer can create their own customized product on your site, and second one is "Dokan" is a multi marketplace, where a customer can act like a seller, build their own product, their price, named the product and etc.
Now, i want to integrate both plugin, where customer who want to sell in my site, they need to create their product via "Fancy Product Designer", and then Fill the information of that product (name, price, desc) on Dokan Add Product Pages. In the simple way, i want the image generated by "fancy product designer" is used as Product Featured Image on "Dokan" add product pages, where both of them is on different pages.
Because i was a newbie and no basic skill of coding, i don't know how to implement a code, what code use for, what result the code make, etc. But Here is some code needed to implement the function.
Here's some code of "Fancy Product Designer"
/**
* Creates an image of the current showing product.
*
* #method createImage
* #param {boolean} [openInBlankPage= true] Opens the image in a Pop-up window.
* #param {boolean} [forceDownload=false] Downloads the image to the user's computer.
* #param {string} [backgroundColor=transparent] The background color as hexadecimal value. For 'png' you can also use 'transparent'.
* #param {string} [options] See fabricjs documentation http://fabricjs.com/docs/fabric.Canvas.html#toDataURL.
*/
this.createImage = function(openInBlankPage, forceDownload, backgroundColor, options) {
if(typeof(openInBlankPage)==='undefined') openInBlankPage = true;
if(typeof(forceDownload)==='undefined') forceDownload = false;
backgroundColor = typeof backgroundColor !== 'undefined' ? backgroundColor : 'transparent';
options = typeof options !== 'undefined' ? options : {};
format = options.format === undefined ? 'png' : options.format;
instance.getProductDataURL(function(dataURL) {
var image = new Image();
image.src = dataURL;
image.onload = function() {
if(openInBlankPage) {
var popup = window.open('','_blank');
FPDUtil.popupBlockerAlert(popup, instance);
popup.document.title = "Product Image";
$(popup.document.body).append('<img src="'+this.src+'" download="product.'+format+'" />');
if(forceDownload) {
window.location.href = popup.document.getElementsByTagName('img')[0].src.replace('image/'+format+'', 'image/octet-stream');
}
}
}
}, backgroundColor, options);
/**
I don't know if it used, but its a code to generated the views (Product Canvas/ A layer of image that later joined and become Product Image) to dataURL
/**
* Gets the views as data URL.
*
* #method getViewsDataURL
* #param {Function} callback A function that will be called when the data URL is created. The function receives the data URL.
* #param {string} [backgroundColor=transparent] The background color as hexadecimal value. For 'png' you can also use 'transparent'.
* #param {string} [options] See fabricjs documentation http://fabricjs.com/docs/fabric.Canvas.html#toDataURL.
* #return {array} An array with all views as data URLs.
*/
this.getViewsDataURL = function(callback, backgroundColor, options) {
callback = typeof callback !== 'undefined' ? callback : function() {};
backgroundColor = typeof backgroundColor !== 'undefined' ? backgroundColor : 'transparent';
options = typeof options !== 'undefined' ? options : {};
var dataURLs = [];
for(var i=0; i < instance.viewInstances.length; ++i) {
instance.viewInstances[i].toDataURL(function(dataURL) {
dataURLs.push(dataURL);
if(dataURLs.length === instance.viewInstances.length) {
callback(dataURLs);
}
}, backgroundColor, options, instance.watermarkImg);
}
};
};
/**
* Creates all views in one data URL. The different views will be positioned below each other.
*
* #method getProductDataURL
* #param {Function} callback A function that will be called when the data URL is created. The function receives the data URL.
* #param {String} [backgroundColor=transparent] The background color as hexadecimal value. For 'png' you can also use 'transparent'.
* #param {Object} [options] See fabricjs documentation http://fabricjs.com/docs/fabric.Canvas.html#toDataURL.
* #example fpd.getProductDataURL( function(dataURL){} );
*/
this.getProductDataURL = function(callback, backgroundColor, options) {
callback = typeof callback !== 'undefined' ? callback : function() {};
backgroundColor = typeof backgroundColor !== 'undefined' ? backgroundColor : 'transparent';
options = typeof options !== 'undefined' ? options : {};
//check
if(instance.viewInstances.length === 0) { callback('') }
$body.append('<canvas id="fpd-hidden-canvas"></canvas>');
var printCanvas = new fabric.Canvas('fpd-hidden-canvas', {
containerClass: 'fpd-hidden fpd-hidden-canvas',
enableRetinaScaling: true
}),
viewCount = 0;
function _addCanvasImage(viewInstance) {
if(viewInstance.options.stageWidth > printCanvas.getWidth()) {
printCanvas.setDimensions({width: viewInstance.options.stageWidth});
}
viewInstance.toDataURL(function(dataURL) {
fabric.Image.fromURL(dataURL, function(img) {
printCanvas.add(img);
if(viewCount > 0) {
img.setTop(printCanvas.getHeight());
printCanvas.setDimensions({height: (printCanvas.getHeight() + viewInstance.options.stageHeight)});
}
viewCount++;
if(viewCount < instance.viewInstances.length) {
_addCanvasImage(instance.viewInstances[viewCount]);
}
else {
callback(printCanvas.toDataURL(options));
printCanvas.dispose();
$body.children('.fpd-hidden-canvas, #fpd-hidden-canvas').remove();
if(instance.currentViewInstance) {
instance.currentViewInstance.resetCanvasSize();
}
}
});
And here was the "Dokan" Plugin code to add featured image (note: I dont know if it could be a problem, but dokan can only upload the featured image from wordpress media, even there's an Upload options too but the file uploaded need to be on my computer.)
featuredImage: {
addImage: function(e) {
e.preventDefault();
var self = $(this);
if ( product_featured_frame ) {
product_featured_frame.open();
return;
}
product_featured_frame = wp.media({
// Set the title of the modal.
title: 'Upload featured image',
button: {
text: 'Set featured image',
}
});
product_featured_frame.on('select', function() {
var selection = product_featured_frame.state().get('selection');
selection.map( function( attachment ) {
attachment = attachment.toJSON();
// set the image hidden id
self.siblings('input.dokan-feat-image-id').val(attachment.id);
// set the image
var instruction = self.closest('.instruction-inside');
var wrap = instruction.siblings('.image-wrap');
// wrap.find('img').attr('src', attachment.sizes.thumbnail.url);
wrap.find('img').attr('src', attachment.url);
instruction.addClass('dokan-hide');
wrap.removeClass('dokan-hide');
});
});
product_featured_frame.open();
},
removeImage: function(e) {
e.preventDefault();
var self = $(this);
var wrap = self.closest('.image-wrap');
var instruction = wrap.siblings('.instruction-inside');
instruction.find('input.dokan-feat-image-id').val('0');
wrap.addClass('dokan-hide');
instruction.removeClass('dokan-hide');
}
}
If the code i give is doesn't help you, please ask me to another function and i will look for it.
Please help me to implement the code on html or php or both too so it will redirect from one to another. I have read How to pass extra variables in URL with Wordpress before and i think it could help, so i decided to trying use a param to define a featured image is from other site, but when i trying to use it on "Dokan" add product pages with ?feat_image_id=https://imageurl.com or ?dokan-featured-image=https://imageurl.com and some param that possible (i forget what is it) but nothing happens on that page.
Thank you very much for your attentions, and for everyone who want to help me
I'm working through the Chrome extension tutorial (full code below). There is one thing I don't understand about this, which is related to line 3 of the requestKittens method
req.onload = this.showPhotos_.bind(this);
and line 1 of the showPhotos method:
var kittens = e.target.responseXML.querySelectorAll('photo');
I'm trying to understand how e.target.responseXML points to the response XML of the request. Here's what I think so far: In the line that calls this function (3rd line of requestKittens()), this points to the kittenGenerator object, meaning that kittenGenerator is bound as the first argument for showPhotos(). So the argument e in showPhotos() should be kittenGenerator, right?
If that's true, then the first line of showPhotos()...
var kittens = e.target.responseXML.querySelectorAll('photo');
...is saying that kittenGenerator has a property target. However I checked this in the Chrome console and it doesn't - so there's a mistake in my logic. Anyone able to help?
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Global variable containing the query we'd like to pass to Flickr. In this
* case, kittens!
*
* #type {string}
*/
var QUERY = 'kittens';
var kittenGenerator = {
/**
* Flickr URL that will give us lots and lots of whatever we're looking for.
*
* See http://www.flickr.com/services/api/flickr.photos.search.html for
* details about the construction of this URL.
*
* #type {string}
* #private
*/
searchOnFlickr_: 'https://secure.flickr.com/services/rest/?' +
'method=flickr.photos.search&' +
'api_key=90485e931f687a9b9c2a66bf58a3861a&' +
'text=' + encodeURIComponent(QUERY) + '&' +
'safe_search=1&' +
'content_type=1&' +
'sort=interestingness-desc&' +
'per_page=20',
/**
* Sends an XHR GET request to grab photos of lots and lots of kittens. The
* XHR's 'onload' event is hooks up to the 'showPhotos_' method.
*
* #public
*/
requestKittens: function() {
var req = new XMLHttpRequest();
req.open("GET", this.searchOnFlickr_, true);
req.onload = this.showPhotos_.bind(this);
req.send(null);
},
/**
* Handle the 'onload' event of our kitten XHR request, generated in
* 'requestKittens', by generating 'img' elements, and stuffing them into
* the document for display.
*
* #param {ProgressEvent} e The XHR ProgressEvent.
* #private
*/
showPhotos_: function (e) {
var kittens = e.target.responseXML.querySelectorAll('photo');
for (var i = 0; i < kittens.length; i++) {
var img = document.createElement('img');
img.src = this.constructKittenURL_(kittens[i]);
img.setAttribute('alt', kittens[i].getAttribute('title'));
document.body.appendChild(img);
}
},
/**
* Given a photo, construct a URL using the method outlined at
* http://www.flickr.com/services/api/misc.urlKittenl
*
* #param {DOMElement} A kitten.
* #return {string} The kitten's URL.
* #private
*/
constructKittenURL_: function (photo) {
return "http://farm" + photo.getAttribute("farm") +
".static.flickr.com/" + photo.getAttribute("server") +
"/" + photo.getAttribute("id") +
"_" + photo.getAttribute("secret") +
"_s.jpg";
}
};
// Run our kitten generation script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
kittenGenerator.requestKittens();
});
The first parameter of bind defines the context of partial application.
req.onload = this.showPhotos_.bind(this);
works because XMLHttpRequest uses event as its first parameter on it's onload handler. That's where e.target comes from.
To give you a simple example of bind, consider the following:
function add(a, b) {
return a + b;
}
var addTwo = add.bind(null, 2);
addTwo(10); // yields 12
If you define a context for bind (ie. something else than null), then you can access that context using this within the function.
I am writing a package as part of a small application I am working on and one thing I need to do is fetch json data from an endpoint and populate it to a Server side collection.
I have been receiving error messages telling me I need to put by server side collection update function into a Fiber, or Meteor.bindEnvironment, or Meteor._callAsync.
I am puzzled, because there are no clear and concise explanations telling me what these do exactly, what they are, if and when they are being deprecated or whether or not their use is good practice.
Here is a look at what is important inside my package file
api.addFiles([
'_src/collections.js'
], 'server');
A bit of psuedo code:
1) Set up a list of Mongo.Collection items
2) Populate these using a function I have written called httpFetch() and run this for each collection, returning a resolved promise if the fetch was successful.
3) Call this httpFetch function inside an underscore each() loop, going through each collection I have, fetching the json data, and attempting to insert it to the Server side Mongo DB.
Collections.js looks like what is below. Wrapping the insert function in a Fiber seems to repress the error message but no data is being inserted to the DB.
/**
* Server side component makes requests to a remote
* endpoint to populate server side Mongo Collections.
*
* #class Server
* #static
*/
Server = {
Fiber: Npm.require('fibers'),
/**
* Collections to be populated with content
*
* #property Collections
* #type {Object}
*/
Collections: {
staticContent: new Mongo.Collection('staticContent'),
pages: new Mongo.Collection('pages'),
projects: new Mongo.Collection('projects'),
categories: new Mongo.Collection('categories'),
formations: new Mongo.Collection('formations')
},
/**
* Server side base url for making HTTP calls
*
* #property baseURL
* #type {String}
*/
baseURL: 'http://localhost:3000',
/**
* Function to update all server side collections
*
* #method updateCollections()
* #return {Object} - a resolved or rejected promise
*/
updateCollections: function() {
var deferred = Q.defer(),
self = this,
url = '',
collectionsUpdated = 0;
_.each(self.Collections, function(collection) {
// collection.remove();
url = self.baseURL + '/content/' + collection._name + '.json';
self.httpFetch(url).then(function(result) {
jsonData = EJSON.parse(result.data);
_.each(jsonData.items, function(item) {
console.log('inserting item with id ', item.id);
self.Fiber(function() {
collection.update({testID: "Some random data"}
});
});
deferred.resolve({
status: 'ok',
message: 'Collection updated from url: ' + url
});
}).fail(function(error) {
return deferred.reject({
status: 'error',
message: 'Could not update collection: ' + collection._name,
data: error
});
});
});
return deferred.promise;
},
/**
* Function to load an endpoint from a given url
*
* #method httpFetch()
* #param {String} url
* #return {Object} - A resolved promise if the data was
* received or a rejected promise.
*/
httpFetch: function(url) {
var deferred = Q.defer();
HTTP.call(
'GET',
url,
function(error, result) {
if(error) {
deferred.reject({
status: 'error',
data: error
});
}
else {
deferred.resolve({
status: 'ok',
data: result.content
});
}
}
);
return deferred.promise;
}
};
I am still really stuck on this problem, and from what I have tried before from reading other posts, I still can't seem to figure out the 'best practice' way of getting this working, or getting it working at all.
There are plenty of suggestions from 2011/2012 but I would be reluctant to use them, since Meteor is in constant flux and even a minor update can break quite a lot of things.
Thanks
Good news : the solution is actually much simpler than all the code you've written so far.
From what I've grasped, you wrote an httpFetch function which is using the asynchronous version of HTTP.get decorated with promises. Then you are trying to run your collection update in a new Fiber because async HTTP.get called introduced a callback continued by the use of promise then.
What you need to do in the first place is using the SYNCHRONOUS version of HTTP.get which is available on the server, this will allow you to write this type of code :
updateCollections:function(){
// we are inside a Meteor.method so this code is running inside its own Fiber
_.each(self.Collections, function(collection) {
var url=// whatever
// sync HTTP.get : we get the result right away (from a
// code writing perspective)
var result=HTTP.get(url);
// we got our result and we are still in the method Fiber : we can now
// safely call collection.update without the need to worry about Fiber stuff
});
You should read carefully the docs about the HTTP module : http://docs.meteor.com/#http_call
I now have this working. It appears the problem was with my httpFetch function returning a promise, which was giving rise to the error:
"Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment."
I changed this httpFetch function to run a callback when HTTP.get() had called with success or error.
Inside this callback is the code to parse the fetched data and insert it into my collections, and this is the crucial part that is now working.
Below is the amended Collections.js file with comments to explain everything.
Server = {
/**
* Collections to be populated with content
*
* #property Collections
* #type {Object}
*/
Collections: {
staticContent: new Mongo.Collection('staticContent'),
pages: new Mongo.Collection('pages'),
projects: new Mongo.Collection('projects'),
categories: new Mongo.Collection('categories'),
formations: new Mongo.Collection('formations')
},
/**
* Server side base url for making HTTP calls
*
* #property baseURL
* #type {String}
*/
baseURL: 'http://localhost:3000',
/**
* Function to update all server side collections
*
* #method updateCollections()
* #return {Object} - a resolved or rejected promise
*/
updateCollections: function() {
var deferred = Q.defer(),
self = this,
collectionsUpdated = 0;
/**
* Loop through each collection, fetching its data from the json
* endpoint.
*/
_.each(self.Collections, function(collection) {
/**
* Clear out old collection data
*/
collection.remove({});
/**
* URL endpoint containing json data. Note the name of the collection
* is also the name of the json file. They need to match.
*/
var url = self.baseURL + '/content/' + collection._name + '.json';
/**
* Make Meteor HTTP Get using the function below.
*/
self.httpFetch(url, function(err, res) {
if(err) {
/**
* Reject promise if there was an error
*/
deferred.reject({
status: 'error',
message: 'Error fetching content for url ' + url,
data: err
});
}
else {
/**
* Populate fetched data from json endpoint
*/
var jsonData = res.content;
data = EJSON.parse(res.content);
/**
* Pick out and insert each item into its collection
*/
_.each(data.items, function(item) {
collection.insert(item);
});
collectionsUpdated++;
}
if(collectionsUpdated === _.size(self.Collections)) {
/**
* When we have updated all collections, resovle the promise
*/
deferred.resolve({
status: 'ok',
message: 'All collections updated',
data: {
collections: self.Collections,
count: collectionsUpdated
}
});
}
});
});
/**
* Return the promise
*/
return deferred.promise;
},
/**
* Function to load an endpoint from a given url
*
* #method httpFetch()
* #param {String} url
* #param {Function} cb - Callback in the event of an error
* #return undefined
*/
httpFetch: function(url, cb) {
var res = HTTP.get(
url,
function(error, result) {
cb(error, result);
}
);
}
};
I'm adding a bug report form to my project. When the user hits the send button on the form (after they explain what the bug is) I am getting information of their browser automatically. I'm currently able to get their user-agent and the source code of the page, but I think it would be super useful if I could also get any errors that have been sent to the browser console.
I've googled for stuff like "javascript get console.log content" but haven't really found anything useful.
I read about creating a "wrapper" for window.log, and found this code:
window.log = function(){
log.history = log.history || []; // store logs to an array for reference
log.history.push(arguments);
if(this.console){
console.log( Array.prototype.slice.call(arguments) );
}
};
But it doesn't seem to be getting the errors that the browser (chrome) sends to the console.log.
Does anyone know how I can get ALL of the errors in the console.log?
This seemed like an interesting idea. What I came up with is essentially a small JavaScript class that overrides the console's functions (but allows the default behavior - you can still see the information in Google Chrome's Inspector, for example).
It is pretty simple to use. Save this as 'consolelogger.js':
/**
* ConsoleLogger
*
* Tracks the history of the console.
* #author Johnathon Koster
* #version 1.0.0
*/
var ConsoleLogger = function() {
// Holds an instance of the current object.
var _instance = this;
this._logOverwrite = function(o) {
var _log = o.log;
// Overwrites the console.log function.
o.log = function(e) {
_instance.pushLog(e);
// Calls the console.log function (normal browser behavior)
_log.call(o, e);
}
// Overwrites the console.info function.
o.info = function(e) {
_instance.pushInfoLog(e);
// Calls the console.info function (normal browser behavior)
_log.call(o, e);
}
// Overwrites the console.warn function.
o.warn = function(e) {
_instance.pushWarnLog(e);
// Calls the console.warn function (normal browser behavior)
_log.call(o, e);
}
// Overwrites the console.error function.
o.error = function(e) {
_instance.pushErrorLog(e);
// Calls the console.error function (normal browser behavior)
_log.call(o, e);
}
}(console);
// Holds the history of the console calls made by other scripts.
this._logHistory = [];
this._infoHistory = [];
this._warnHistory = [];
this._errorHistory = [];
this._windowErrors = [];
/**
* This allows users to get the history of items not explicitly added.
*/
window.onerror = function(msg, url, line) {
_instance._windowErrors.push('Message: ' + msg + ' URL: ' + url + ' Line: ' + line);
}
/**
* Adds an item to the log history.
*
* #param {log} object to log
*/
this.pushLog = function(log) {
this._logHistory.push(log);
}
/**
* Adds an item to the information log history.
*
* #param {log} object to log
*/
this.pushInfoLog = function(log) {
this._infoHistory.push(log);
}
/**
* Adds an item to the warning log history.
*
* #param {log} object to log
*/
this.pushWarnLog = function(log) {
this._warnHistory.push(log);
}
/**
* Adds an item to the error log history.
*
* #param {log} object to log
*/
this.pushErrorLog = function(log) {
this._errorHistory.push(log);
}
/**
* Returns the log history.
* #this {ConsoleLogger}
* #return {array} the log history.
*/
this.getLog = function() {
return this._logHistory;
}
/**
* Returns the information log history.
* #this {ConsoleLogger}
* #return {array} the information log history.
*/
this.getInfoLog = function() {
return this._infoHistory;
}
/**
* Returns the warning log history.
* #this {ConsoleLogger}
* #return {array} the warning log history.
*/
this.getWarnLog = function() {
return this._warnHistory;
}
/**
* Returns the error log history.
* #this {ConsoleLogger}
* #return {array} the error log history.
*/
this.getErrorLog = function() {
return this._errorHistory;
}
/**
* Returns the window log history.
* #this {ConsoleLogger}
* #return {array} the window log history.
*/
this.getWindowLog = function() {
return this._windowErrors;
}
/**
* Returns all log histories.
* #this {ConsoleLogger}
* #return {array} the error log(s) history.
*/
this.getLogHistory = function() {
var _return = [];
_return = this._logHistory
_return = _return.concat(this._infoHistory);
_return = _return.concat(this._warnHistory);
_return = _return.concat(this._errorHistory);
_return = _return.concat(this._windowErrors);
return _return;
}
}
And add it to your page like this:
<script src="consolelogger.js"></script>
<script>
// Create a new instance of ConsoleLogger
var logger = new ConsoleLogger;
</script>
Now, you don't have to do anything special to trap 'console.log', 'console.warn', 'console.info', or 'console.error'. The ConsoleLogger will do it for you, and allow you to get the history of what's been added.
To retrieve the history call these functions (all of them return a JavaScript array):
var logHistory = logger.getLog(); // Get the console.log history
var infoHistory = logger.getInfoLog(); // Get the console.info history
var warningHistory = logger.getWarnLog(); // Get the console.warn history
var errorHistory = logger.getErrorLog(); // Get the console.error history
var windowLog = logger.getWindowLog(); // Get the window error history
var allLogs = logger.getLogHistory(); // Returns all log histories as one array.
I apologize for such a lengthy post, but it seems to do the trick! I also created a GitHub repo; if I do any more work on it, changes will be committed there.