diff --git a/doc/TOOL_API.md b/doc/TOOL_API.md index ae390a0..165d792 100644 --- a/doc/TOOL_API.md +++ b/doc/TOOL_API.md @@ -127,7 +127,7 @@ LocalStorage, sessionStorage, cookies, scripts, styleSheets and images. ## Sources -View json, html, js, and css. +View object, html, js, and css. ### Config diff --git a/src/Console/Log.js b/src/Console/Log.js index a81efc8..b82c965 100644 --- a/src/Console/Log.js +++ b/src/Console/Log.js @@ -555,10 +555,10 @@ function formatEl(val) { )}` } -const regUrl = /(^|[\s\n]|<[A-Za-z]*\/?>)((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi +const regUrl = /((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi const recognizeUrl = str => - str.replace(regUrl, '$2') + str.replace(regUrl, '$1') function getFrom() { const e = new Error() diff --git a/src/Elements/Elements.js b/src/Elements/Elements.js index e3cf973..8ade06d 100644 --- a/src/Elements/Elements.js +++ b/src/Elements/Elements.js @@ -21,7 +21,6 @@ import { pxToNum, isNaN, isNum, - stringifyAll, nextTick, Emitter } from '../lib/util' @@ -180,23 +179,10 @@ export default class Elements extends Tool { } }) .on('click', '.eruda-breadcrumb', () => { - let data = this._elData - - if (!data) { - data = stringifyAll(this._curEl, { - unenumerable: true, - symbol: true, - accessGetter: true, - timeout: 1000 - }) - data = JSON.parse(data) - } const sources = container.get('sources') - this._elData = data - if (sources) { - sources.set('json', data) + sources.set('object', this._curEl) container.showTool('sources') } }) @@ -262,7 +248,6 @@ export default class Elements extends Tool { } _setEl(el) { this._curEl = el - this._elData = null this._curCssStore = new CssStore(el) this._highlight.setEl(el) this._rmDefComputedStyle = true diff --git a/src/Network/Network.js b/src/Network/Network.js index 32a54dc..0a23d1f 100644 --- a/src/Network/Network.js +++ b/src/Network/Network.js @@ -187,7 +187,7 @@ export default class Network extends Tool { case 'javascript': return showSources('js', resTxt) case 'json': - return showSources('json', resTxt) + return showSources('object', resTxt) } switch (data.type) { case 'image': diff --git a/src/Resources/Resources.js b/src/Resources/Resources.js index a6263c8..171098a 100644 --- a/src/Resources/Resources.js +++ b/src/Resources/Resources.js @@ -279,7 +279,7 @@ export default class Resources extends Tool { : sessionStorage.getItem(key) try { - showSources('json', JSON.parse(val)) + showSources('object', JSON.parse(val)) } catch (e) { showSources('raw', val) } diff --git a/src/Sources/Sources.js b/src/Sources/Sources.js index 6252023..abb4696 100644 --- a/src/Sources/Sources.js +++ b/src/Sources/Sources.js @@ -1,6 +1,6 @@ import Tool from '../DevTools/Tool' import beautify from 'js-beautify' -import JsonViewer from '../lib/JsonViewer' +import ObjViewer from '../lib/ObjViewer' import Settings from '../Settings/Settings' import { ajax, escape, trim, isStr, highlight } from '../lib/util' import evalCss from '../lib/evalCss' @@ -109,7 +109,7 @@ export default class Sources extends Tool { _loadTpl() { this._codeTpl = require('./code.hbs') this._imgTpl = require('./image.hbs') - this._jsonTpl = require('./json.hbs') + this._objTpl = require('./object.hbs') this._rawTpl = require('./raw.hbs') this._iframeTpl = require('./iframe.hbs') } @@ -164,8 +164,8 @@ export default class Sources extends Tool { return this._renderCode() case 'img': return this._renderImg() - case 'json': - return this._renderJson() + case 'object': + return this._renderObj() case 'raw': return this._renderRaw() case 'iframe': @@ -225,9 +225,9 @@ export default class Sources extends Tool { }) ) } - _renderJson() { - // Using cache will keep binding json events to the same elements. - this._renderHtml(this._jsonTpl(), false) + _renderObj() { + // Using cache will keep binding events to the same elements. + this._renderHtml(this._objTpl(), false) let val = this._data.val @@ -238,7 +238,10 @@ export default class Sources extends Tool { /* eslint-disable no-empty */ } catch (e) {} - new JsonViewer(val, this._$el.find('.eruda-json')) + new ObjViewer(val, this._$el.find('.eruda-json'), { + showUnenumerable: true, + showGetterVal: true + }) } _renderRaw() { this._renderHtml(this._rawTpl({ val: this._data.val })) diff --git a/src/Sources/json.hbs b/src/Sources/object.hbs similarity index 100% rename from src/Sources/json.hbs rename to src/Sources/object.hbs diff --git a/src/lib/JsonViewer.js b/src/lib/JsonViewer.js index e4d26cb..a75e31e 100644 --- a/src/lib/JsonViewer.js +++ b/src/lib/JsonViewer.js @@ -5,8 +5,8 @@ import { uniqId, upperFirst, toNum, - escape, toStr, + escape, chunk, each, isNaN, @@ -275,6 +275,8 @@ export const encode = str => { // $, upperCase, lowerCase, _ export function sortObjName(a, b) { + a = toStr(a) + b = toStr(b) const numA = toNum(a) const numB = toNum(b) if (!isNaN(numA) && !isNaN(numB)) { diff --git a/src/lib/ObjViewer.js b/src/lib/ObjViewer.js index a273480..8d7a573 100644 --- a/src/lib/ObjViewer.js +++ b/src/lib/ObjViewer.js @@ -1,4 +1,5 @@ import { + extend, Emitter, getProto, isNum, @@ -45,6 +46,12 @@ export default class ObjViewer extends Emitter { this._bindEvent() } _objToHtml(data, firstLevel) { + let self = data + const visitedObj = this._visitor.get(data) + if (visitedObj && visitedObj.self) { + self = visitedObj.self + } + let ret = '' const types = ['enumerable'] @@ -86,15 +93,40 @@ export default class ObjViewer extends Emitter { for (let i = 0, len = typeKeys.length; i < len; i++) { const key = typeKeys[i] let val = '' - try { - val = data[key] - if (isPromise(val)) { - val.catch(() => {}) + const descriptor = Object.getOwnPropertyDescriptor(data, key) + const hasGetter = descriptor && descriptor.get + const hasSetter = descriptor && descriptor.set + if (hasGetter && !this._showGetterVal) { + val = '(...)' + } else { + try { + val = self[key] + if (isPromise(val)) { + val.catch(() => {}) + } + } catch (e) { + val = e.message } - } catch (e) { - val = e.message } - ret += this._createEl(key, val, type, firstLevel) + ret += this._createEl(key, data, val, type, firstLevel) + if (hasGetter) { + ret += this._createEl( + `get ${key}`, + data, + descriptor.get, + type, + firstLevel + ) + } + if (hasSetter) { + ret += this._createEl( + `set ${key}`, + data, + descriptor.set, + type, + firstLevel + ) + } } }) @@ -103,13 +135,13 @@ export default class ObjViewer extends Emitter { if (ret === '') { ret = this._objToHtml(proto) } else { - ret += this._createEl('__proto__', proto, 'proto') + ret += this._createEl('__proto__', self || data, proto, 'proto') } } return ret } - _createEl(key, val, keyType, firstLevel = false) { + _createEl(key, self, val, keyType, firstLevel = false) { const visitor = this._visitor let t = typeof val const valType = type(val, false) @@ -141,7 +173,11 @@ export default class ObjViewer extends Emitter { if (visitedObj) { id = visitedObj.id } else { - id = visitor.set(val) + const extra = {} + if (keyType === 'proto') { + extra.self = self + } + id = visitor.set(val, extra) this._map[id] = val } const objAbstract = getObjAbstract(val, valType) || upperFirst(t) @@ -242,12 +278,13 @@ class Visitor { this.id = 0 this.visited = [] } - set(val) { + set(val, extra) { const { visited, id } = this const obj = { id, val } + extend(obj, extra) visited.push(obj) this.id++