diff --git a/src/Console/Log.es6 b/src/Console/Log.es6 index 7665514..5c53c81 100644 --- a/src/Console/Log.es6 +++ b/src/Console/Log.es6 @@ -1,5 +1,6 @@ import util from '../lib/util' import stringify from '../lib/stringify.es6' +import origGetAbstract from '../lib/getAbstract.es6' import highlight from '../lib/highlight.es6' import beautify from 'js-beautify' import JsonViewer from '../lib/JsonViewer.es6' @@ -175,6 +176,14 @@ Log.showGetterVal = false; Log.showUnenumerable = true; Log.showSrcInSources = false; +var getAbstract = util.wrap(origGetAbstract, function (fn, obj) +{ + return fn(obj, { + getterVal: Log.showGetterVal, + unenumerable: false + }); +}); + function stringifyWrapper(obj, options = {}) { util.defaults(options, { @@ -319,7 +328,7 @@ function substituteStr(args) case 'O': if (util.isObj(arg)) { - newStr += stringifyWrapper(arg); + newStr += getAbstract(arg); } break; case 'o': @@ -328,7 +337,7 @@ function substituteStr(args) newStr += formatEl(arg); } else if (util.isObj(arg)) { - newStr += stringifyWrapper(arg); + newStr += getAbstract(arg); } break; case 'c': @@ -355,7 +364,7 @@ function substituteStr(args) function formatObj(val) { - return `${getObjType(val)} ${stringifyWrapper(val)}`; + return `${getObjType(val)} ${getAbstract(val)}`; } function formatFn(val) diff --git a/src/lib/JsonViewer.es6 b/src/lib/JsonViewer.es6 index 17663c9..9e26faf 100644 --- a/src/lib/JsonViewer.es6 +++ b/src/lib/JsonViewer.es6 @@ -56,19 +56,12 @@ function jsonToHtml(data, firstLevel) function createEl(key, val, firstLevel) { - var type = 'object', - open = '{', - close = '}'; + var type = 'object'; if (key === 'erudaProto') key = '__proto__'; if (key === 'erudaId') return `
  • `; - if (util.isArr(val)) - { - type = 'array'; - open = '['; - close = ']'; - } + if (util.isArr(val)) type = 'array'; function wrapKey(key) { @@ -89,13 +82,16 @@ function createEl(key, val, firstLevel) } if (util.isObj(val)) { + var objAbstract = val['erudaObjAbstract'] || util.upperFirst(type); + var obj = `
  • ${wrapKey(key)} - ${open} ${(val['erudaObjAbstract'] || '')} + ${objAbstract} ${close}
  • `; + + return obj + ``; } if (util.isNum(val) || util.isBool(val)) { diff --git a/src/lib/getAbstract.es6 b/src/lib/getAbstract.es6 new file mode 100644 index 0000000..d74bcde --- /dev/null +++ b/src/lib/getAbstract.es6 @@ -0,0 +1,249 @@ +// Simple version for stringify, used for displaying object abstract. +import util from './util' + +// Modified from: https://jsconsole.com/ +export default function getAbstract(obj, { + visited = [], + topObj, + level = 0, + getterVal = false, + unenumerable = true + } = {}) +{ + let json = '', + type = '', + keyNum = 5, + parts = [], + names = [], + objEllipsis = '', + circular = false, + i, len; + + topObj = topObj || obj; + + let passOpts = { + visited, getterVal, + unenumerable, + level: level + 1 + }; + let doStringify = level === 0; + + let keyWrapper = '', + fnWrapper = '', + numWrapper = '', + nullWrapper = '', + strWrapper = '', + boolWrapper = '', + specialWrapper = '', + strEscape = str => util.escape(str), + wrapperEnd = ''; + + let wrapKey = key => keyWrapper + strEscape(key) + wrapperEnd, + wrapNum = num => numWrapper + num + wrapperEnd, + wrapBool = bool => boolWrapper + bool + wrapperEnd, + wrapNull = str => nullWrapper + str + wrapperEnd; + + function wrapStr(str) + { + str = util.toStr(str); + + str = str.replace(/\\/g, ''); + if (util.startWith(str, 'function')) + { + return fnWrapper + 'function' + wrapperEnd + ' ( )'; + } + if (util.contain(SPECIAL_VAL, str) || util.startWith(str, 'Array[')) + { + return specialWrapper + strEscape(str) + wrapperEnd; + } + if (util.startWith(str, '[circular]')) + { + return specialWrapper + '[circular]' + wrapperEnd; + } + if (util.startWith(str, '[object ')) + { + return specialWrapper + strEscape(str.replace(/(\[object )|]/g, '')) + wrapperEnd; + } + + return strWrapper + strEscape(`"${str}"`) + wrapperEnd; + } + try { + type = ({}).toString.call(obj); + } catch (e) + { + type = '[object Object]'; + } + + var isFn = (type == '[object Function]'), + isStr = (type == '[object String]'), + isArr = (type == '[object Array]'), + isObj = (type == '[object Object]'), + isNum = (type == '[object Number]'), + isSymbol = (type == '[object Symbol]'), + isBool = (type == '[object Boolean]'); + + for (i = 0, len = visited.length; i < len; i++) + { + if (obj === visited[i]) + { + circular = true; + break; + } + } + + if (circular) + { + json = wrapStr('[circular]'); + } else if (isStr) + { + json = wrapStr(escapeJsonStr(obj)); + } else if (isArr) + { + visited.push(obj); + + if (doStringify) + { + json = '['; + util.each(obj, val => parts.push(`${getAbstract(val, passOpts)}`)); + json += parts.join(', ') + ']'; + } else + { + json = wrapStr(`Array[${obj.length}]`); + } + } else if (isObj) + { + visited.push(obj); + + if (canBeProto(obj)) + { + obj = Object.getPrototypeOf(obj); + } + + names = unenumerable ? Object.getOwnPropertyNames(obj) : Object.keys(obj); + if (doStringify) + { + i = 1; + json = '{ '; + util.each(names, name => + { + if (i > keyNum) + { + objEllipsis = '...'; + return; + } + let key = wrapKey(escapeJsonStr(name)); + + if (!getterVal) + { + let descriptor = Object.getOwnPropertyDescriptor(obj, name); + if (descriptor.get) + { + parts.push(`${key}: ${wrapStr('(...)')}`); + i++; + return; + } + } + if (typeof topObj[name] === 'function') return; + parts.push(`${key}: ${getAbstract(topObj[name], passOpts)}`); + i++; + }); + json += parts.join(', ') + objEllipsis + ' }'; + } else + { + json = wrapStr('Object'); + } + } else if (isNum) + { + json = obj + ''; + if (util.endWith(json, 'Infinity') || json === 'NaN') + { + json = `"${json}"`; + } else + { + json = wrapNum(json); + } + } else if (isBool) + { + json = wrapBool(obj ? 'true' : 'false'); + } else if (obj === null) + { + json = wrapNull('null'); + } else if (isSymbol) + { + json = wrapStr('Symbol'); + } else if (obj === undefined) + { + json = wrapStr('undefined'); + } else if (type === '[object HTMLAllCollection]') + { + // https://docs.webplatform.org/wiki/dom/HTMLAllCollection + // Might cause a performance issue when stringify a dom element. + json = wrapStr('[object HTMLAllCollection]'); + } else if (type === '[object HTMLDocument]' && level > 1) + { + // Same as reason above. + json = wrapStr('[object HTMLDocument]'); + } else { + try + { + visited.push(obj); + if (canBeProto(obj)) + { + obj = Object.getPrototypeOf(obj); + } + + if (doStringify) + { + i = 1; + json = '{ '; + names = unenumerable ? Object.getOwnPropertyNames(obj) : Object.keys(obj); + util.each(names, name => + { + if (i > keyNum) + { + objEllipsis = '...'; + return; + } + let key = wrapKey(escapeJsonStr(name)); + + if (!getterVal) + { + let descriptor = Object.getOwnPropertyDescriptor(obj, name); + if (descriptor.get) + { + parts.push(`${key}: ${wrapStr('(...)')}`); + i++; + return; + } + } + if (typeof topObj[name] === 'function') return; + parts.push(`${key}: ${getAbstract(topObj[name], passOpts)}`); + i++; + }); + json += parts.join(', ') + objEllipsis + ' }'; + } else + { + json = wrapStr(obj); + } + } catch (e) + { + json = wrapStr(obj); + } + } + + return json; +} + +const SPECIAL_VAL = ['(...)', 'undefined', 'Symbol', 'Object']; + +var escapeJsonStr = str => str.replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\f|\n|\r|\t/g, ''); + +function canBeProto(obj) +{ + let emptyObj = util.isEmpty(Object.getOwnPropertyNames(obj)), + proto = Object.getPrototypeOf(obj); + + return emptyObj && proto && proto !== Object.prototype; +} diff --git a/src/lib/json.scss b/src/lib/json.scss index 042dbd6..9e18e9b 100644 --- a/src/lib/json.scss +++ b/src/lib/json.scss @@ -65,7 +65,6 @@ top: 3px; } li .collapsed ~ .close:before { - content: "... "; color: #999; } .hidden ~ ul { diff --git a/src/lib/util.js b/src/lib/util.js index 1061108..28dc450 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -1759,13 +1759,13 @@ module.exports = (function () * var Student = People.extend({ * initialize: function (name, age, school) * { - * this.callSuper('initialize', name, age); + * this.callSuper(People, 'initialize', arguments); * * this.school = school. * }, * introduce: function () * { - * return this.callSuper('introduce') + '\n I study at ' + this.school + '.'. + * return this.callSuper(People, 'introduce') + '\n I study at ' + this.school + '.'. * } * }, { * is: function (obj) @@ -1795,22 +1795,13 @@ module.exports = (function () { var args = toArr(arguments); - if (has(ctor.prototype, 'initialize') && - !regCallSuper.test(this.initialize.toString()) && - this.callSuper) - { - args.unshift('initialize'); - this.callSuper.apply(this, args); - args.shift(); - } - return this.initialize ? this.initialize.apply(this, args) || this : this; }; inherits(ctor, parent); - ctor.superclass = ctor.prototype.superclass = parent; + ctor.prototype.superclass = parent; ctor.extend = function (methods, statics) { @@ -1838,13 +1829,13 @@ module.exports = (function () var Base = exports.Base = makeClass(Object, { className: 'Base', - callSuper: function (name) + callSuper: function (parent, name, args) { - var superMethod = this.superclass.prototype[name]; + var superMethod = parent.prototype[name]; if (!superMethod) return; - return superMethod.apply(this, toArr(arguments).slice(1)); + return superMethod.apply(this, args); }, toString: function () { @@ -2588,7 +2579,7 @@ module.exports = (function () /* bind events to certain dom elements. TODO * * ```javascript - * event.on('#test', 'click', function () + * $event.on('#test', 'click', function () * { * // ... * }); @@ -3420,7 +3411,7 @@ module.exports = (function () * |return|string|Globally-unique id| * * ```javascript - * uniqueId('eusita_'); // -> 'eustia_xxx' + * uniqId('eusita_'); // -> 'eustia_xxx' * ``` */ @@ -3504,5 +3495,34 @@ module.exports = (function () return exports; })(); + /* ------------------------------ wrap ------------------------------ */ + + var wrap = _.wrap = (function () + { + /* Wrap the function inside a wrapper function, passing it as the first argument. + * + * |Name |Type |Desc | + * |-------|--------|----------------| + * |fn |* |Function to wrap| + * |wrapper|function|Wrapper function| + * |return |function|New function | + * + * ```javascript + * var p = wrap(escape, function(fn, text) + * { + * return '

    ' + fn(text) + '

    '; + * }); + * p('You & Me'); // -> '

    You & Me

    ' + * ``` + */ + + function exports(fn, wrapper) + { + return partial(wrapper, fn); + } + + return exports; + })(); + return _; })(); \ No newline at end of file