-
Notifications
You must be signed in to change notification settings - Fork 11
/
console.js
166 lines (147 loc) · 5.71 KB
/
console.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
(function() {
// https://github.com/jsbin/jsbin/blob/master/public/js/vendor/stringify.js
var stringify = (function() {
var sortci = function(a, b) {
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
};
var htmlEntities = function(str) {
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
};
/**
* Recursively stringify an object. Keeps track of which objects it has
* visited to avoid hitting circular references, and a buffer for indentation.
* Goes 2 levels deep.
*/
return function stringify(o, visited, buffer) {
var i, vi, type = '',
parts = [];
buffer = buffer || '';
visited = visited || [];
// Get out fast with primitives that don't like toString
if (o === null) {
return 'null';
}
if (typeof o === 'undefined') {
return 'undefined';
}
// Determine the type
try {
type = ({}).toString.call(o);
} catch (e) { // only happens when typeof is protected (...randomly)
type = '[object Object]';
}
// Handle the primitive types
if (type == '[object Number]') {
return '' + o;
}
if (type == '[object Boolean]') {
return o ? 'true' : 'false';
}
if (type == '[object Function]') {
return o.toString().split('\n ').join('\n' + buffer);
}
if (type == '[object String]') {
return '"' + htmlEntities(o.replace(/"/g, '\\"')) + '"';
}
// Check for circular references
for (vi = 0; vi < visited.length; vi++) {
if (o === visited[vi]) {
// Notify the user that a circular object was found and, if available,
// show the object's outerHTML (for body and elements)
return '[circular ' + type.slice(1) +
('outerHTML' in o ? ' :\n' + htmlEntities(o.outerHTML).split('\n').join('\n' + buffer) : '')
}
}
// Remember that we visited this object
visited.push(o);
// Stringify each member of the array
if (type == '[object Array]') {
for (i = 0; i < o.length; i++) {
parts.push(stringify(o[i], visited));
}
return '[' + parts.join(', ') + ']';
}
// Fake array – very tricksy, get out quickly
if (type.match(/Array/)) {
return type;
}
var typeStr = type + ' ',
newBuffer = buffer + ' ';
// Dive down if we're less than 2 levels deep
if (buffer.length / 2 < 2) {
var names = [];
// Some objects don't like 'in', so just skip them
try {
for (i in o) {
names.push(i);
}
} catch (e) {}
names.sort(sortci);
for (i = 0; i < names.length; i++) {
try {
parts.push(newBuffer + names[i] + ': ' + stringify(o[names[i]], visited, newBuffer));
} catch (e) {}
}
}
// If nothing was gathered, return empty object
if (!parts.length) return typeStr + '{ ... }';
// Return the indented object with new lines
return typeStr + '{\n' + parts.join(',\n') + '\n' + buffer + '}';
};
}());
var nativeConsole = {};
function appendElement(message) {
if (document.body) {
document.body.append(message);
} else {
// wait for document ready
setTimeout(appendElement, 100, message);
}
}
function createElement(text, color) {
var pre = document.createElement('pre');
pre.style.color = color || '#000000';
pre.innerText = text;
return pre;
}
function virtualConsoleFactory(key, color) {
return function() {
// Reflect.apply -> Function.prototype.apply.call
Function.prototype.apply.call(nativeConsole[key], nativeConsole, arguments);
// Array.from -> Array.prototype.slice.call
var args = Array.prototype.slice.call(arguments)
.map(function (arg) {
return stringify(arg);
})
.join(', ');
appendElement(createElement(args, color));
};
}
// override native console
for (var attr in window.console) {
if (window.console.hasOwnProperty(attr)) {
nativeConsole[attr] = window.console[attr];
switch (attr) {
case 'clear':
window.console['clear'] = function clear() {
if (document.body) {
document.body.innerHtml = null;
}
nativeConsole.clear.call(nativeConsole);
};;
break;
case 'error':
window.console['error'] = virtualConsoleFactory('error', '#ff0000');
break;
default:
window.console[attr] = virtualConsoleFactory(attr);
}
}
}
// to catch error event
window.addEventListener('error', function(e) {
e.preventDefault();
console.error(e.message);
return true;
}, true);
})();