From fbea217734316e01343d41c845007c0a5e601646 Mon Sep 17 00:00:00 2001 From: surunzi Date: Mon, 27 Jun 2016 09:10:17 +0800 Subject: [PATCH] Add: Elements dom object access --- src/Console/Log.es6 | 163 +----------------------------------- src/Elements/Elements.es6 | 14 ++++ src/Elements/Elements.hbs | 2 +- src/Elements/Elements.scss | 12 ++- src/Sources/Sources.scss | 8 +- src/lib/highlight.es6 | 2 +- src/lib/stringify.es6 | 167 +++++++++++++++++++++++++++++++++++++ src/style/mixin.scss | 16 ++-- webpack.config.js | 2 +- 9 files changed, 209 insertions(+), 177 deletions(-) create mode 100644 src/lib/stringify.es6 diff --git a/src/Console/Log.es6 b/src/Console/Log.es6 index 8ed30d9..0673dd0 100644 --- a/src/Console/Log.es6 +++ b/src/Console/Log.es6 @@ -1,4 +1,5 @@ import util from '../lib/util' +import stringify from '../lib/stringify.es6' import highlight from '../lib/highlight.es6' import beautify from 'js-beautify' @@ -365,168 +366,6 @@ function extractSrc(args) var extractObj = (obj, simple) => JSON.parse(stringify(obj, null, obj, simple)); -// Modified from: https://jsconsole.com/ -function stringify(obj, visited, topObj, simple) -{ - let json = '', - type = '', - parts = [], - names = [], - proto, - circular = false; - - visited = visited || []; - topObj = topObj || obj; - - 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 (let i = 0, len = visited.length; i < len; i++) - { - if (obj === visited[i]) - { - circular = true; - break; - } - } - - if (circular) - { - json = '"[circular]"'; - } else if (isStr) - { - json = `"${escapeJsonStr(obj)}"`; - } else if (isArr) - { - visited.push(obj); - - json = '['; - util.each(obj, val => parts.push(`${stringify(val, visited, null, simple)}`)); - json += parts.join(', ') + ']'; - } else if (isObj || isFn) - { - visited.push(obj); - - names = Object.getOwnPropertyNames(obj); - proto = Object.getPrototypeOf(obj); - if (proto === Object.prototype || isFn || simple) proto = null; - if (proto) proto = `"erudaProto": ${stringify(proto, visited, topObj)}`; - names.sort(sortObjName); - if (isFn) - { - // We don't these properties to be display for functions. - names = names.filter(val => ['arguments', 'caller', 'name', 'length', 'prototype'].indexOf(val) < 0); - } - if (names.length === 0 && isFn) - { - json = `"${escapeJsonStr(obj.toString())}"`; - } else - { - json = '{'; - if (isFn) - { - // Function length is restricted to 500 for performance reason. - var fnStr = obj.toString(); - if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...'; - parts.push(`"erudaObjAbstract": "${escapeJsonStr(fnStr)}"`); - } - util.each(names, name => - { - parts.push(`"${escapeJsonStr(name)}": ${stringify(obj[name], visited, null, simple)}`); - }); - if (proto) parts.push(proto); - json += parts.join(', ') + '}'; - } - } else if (isNum) - { - json = obj + ''; - if (util.endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"`; - } else if (isBool) - { - json = obj ? 'true' : 'false'; - } else if (obj === null) - { - json = 'null'; - } else if (isSymbol) - { - json = '"Symbol"'; - } else if (obj === undefined) - { - json = '"undefined"'; - } else - { - try - { - visited.push(obj); - - json = '{\n'; - if (!simple) parts.push(`"erudaObjAbstract": "${type.replace(/(\[object )|]/g, '')}"`); - names = Object.getOwnPropertyNames(obj); - proto = Object.getPrototypeOf(obj); - if (proto === Object.prototype || simple) proto = null; - if (proto) - { - try - { - proto = `"erudaProto": ${stringify(proto, visited, topObj)}`; - } catch(e) - { - proto = `"erudaProto": "${escapeJsonStr(e.message)}"`; - } - } - names.sort(sortObjName); - util.each(names, name => - { - let val = topObj[name]; - - try - { - parts.push(`"${escapeJsonStr(name)}": ${stringify(val, visited, null, simple)}`); - } catch (e) - { - parts.push(`"${escapeJsonStr(name)}": "${escapeJsonStr(e.message)}"`); - } - }); - if (proto) parts.push(proto); - json += parts.join(',\n') + '\n}'; - } catch (e) { - json = `"${obj}"`; - } - } - - return json; -} - -var escapeJsonStr = str => str.replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\f|\n|\r|\t/g, ''); - -var sortObjName = (a, b) => -{ - let codeA = a.charCodeAt(0), - codeB = b.charCodeAt(0); - - if (isLetter(codeA) && !isLetter(codeB)) return -1; - if (!isLetter(codeA) && isLetter(codeB)) return 1; - - return a > b ? 1 : -1; -}; - -var isLetter = code => (code > 64 && code < 90) || (code > 96 && code < 123); - - var transMultipleMsg = args => args.map(val => transMsg(val)).join(' '); var txtToHtml = str => str.replace(/\n/g, '
') diff --git a/src/Elements/Elements.es6 b/src/Elements/Elements.es6 index c30bc1b..88dde63 100644 --- a/src/Elements/Elements.es6 +++ b/src/Elements/Elements.es6 @@ -1,5 +1,6 @@ import Tool from '../DevTools/Tool.es6' import CssStore from './CssStore.es6' +import stringify from '../lib/stringify.es6' import Highlight from './Highlight.es6' import Select from './Select.es6' import util from '../lib/util' @@ -126,6 +127,18 @@ export default class Elements extends Tool sources.set('js', text); parent.showTool('sources'); } + }).on('click', '.eruda-breadcrumb', () => + { + let data = this._elData || JSON.parse(stringify(this._curEl, null, this._curEl, false)), + sources = parent.get('sources'); + + this._elData = data; + + if (sources) + { + sources.set('json', data); + parent.showTool('sources'); + } }).on('click', '.toggle-all-computed-style', () => this._toggleAllComputedStyle()); var $bottomBar = this._$el.find('.eruda-bottom-bar'); @@ -173,6 +186,7 @@ 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/Elements/Elements.hbs b/src/Elements/Elements.hbs index bc45674..499ed83 100644 --- a/src/Elements/Elements.hbs +++ b/src/Elements/Elements.hbs @@ -1,4 +1,4 @@ -
+
{{{name}}}
{{#if children}} diff --git a/src/Elements/Elements.scss b/src/Elements/Elements.scss index 27e6764..5157cc0 100644 --- a/src/Elements/Elements.scss +++ b/src/Elements/Elements.scss @@ -9,7 +9,17 @@ @include overflow-auto(y); height: 100%; } - @include breadcrumb(); + .breadcrumb { + @include breadcrumb(); + transition: background $anim-duration, color $anim-duration; + &:active { + background: $blue; + color: #fff; + span { + color: #fff; + } + } + } .section { h2 { background: $blue; diff --git a/src/Sources/Sources.scss b/src/Sources/Sources.scss index b69f205..cb4117f 100644 --- a/src/Sources/Sources.scss +++ b/src/Sources/Sources.scss @@ -15,7 +15,9 @@ font-size: $font-size-s; } .image { - @include breadcrumb(); + .breadcrumb { + @include breadcrumb(); + } .img-container { text-align: center; img { @@ -30,7 +32,9 @@ } } .http { - @include breadcrumb(); + .breadcrumb { + @include breadcrumb(); + } .section { background: #fff; h2 { diff --git a/src/lib/highlight.es6 b/src/lib/highlight.es6 index 98d270e..bfac6cd 100644 --- a/src/lib/highlight.es6 +++ b/src/lib/highlight.es6 @@ -37,7 +37,7 @@ export default function highlight(str, lang) tag = (!end? $0.substr(3) : $0.substr(6)).replace(/_/g,''), lastTag = lvls.length > 0 ? lvls[lvls.length - 1] : null; - if(!end && (lastTag == null || tag == lastTag || (lastTag != null && lang[lastTag].embed != undefined && lang[lastTag].embed.indexOf(tag) > -1))) + if(!end && (lastTag == null || tag == lastTag || (lastTag != null && lang[lastTag] && lang[lastTag].embed != undefined && lang[lastTag].embed.indexOf(tag) > -1))) { lvls.push(tag); diff --git a/src/lib/stringify.es6 b/src/lib/stringify.es6 new file mode 100644 index 0000000..5038b84 --- /dev/null +++ b/src/lib/stringify.es6 @@ -0,0 +1,167 @@ +import util from './util' + +// Modified from: https://jsconsole.com/ +export default function stringify(obj, visited, topObj, simple) +{ + let json = '', + type = '', + parts = [], + names = [], + proto, + circular = false; + + visited = visited || []; + topObj = topObj || obj; + + 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 (let i = 0, len = visited.length; i < len; i++) + { + if (obj === visited[i]) + { + circular = true; + break; + } + } + + if (circular) + { + json = '"[circular]"'; + } else if (isStr) + { + json = `"${escapeJsonStr(obj)}"`; + } else if (isArr) + { + visited.push(obj); + + json = '['; + util.each(obj, val => parts.push(`${stringify(val, visited, null, simple)}`)); + json += parts.join(', ') + ']'; + } else if (isObj || isFn) + { + visited.push(obj); + + names = Object.getOwnPropertyNames(obj); + proto = Object.getPrototypeOf(obj); + if (proto === Object.prototype || isFn || simple) proto = null; + if (proto) proto = `"erudaProto": ${stringify(proto, visited, topObj)}`; + names.sort(sortObjName); + if (isFn) + { + // We don't these properties to be display for functions. + names = names.filter(val => ['arguments', 'caller', 'name', 'length', 'prototype'].indexOf(val) < 0); + } + if (names.length === 0 && isFn) + { + json = `"${escapeJsonStr(obj.toString())}"`; + } else + { + json = '{'; + if (isFn) + { + // Function length is restricted to 500 for performance reason. + var fnStr = obj.toString(); + if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...'; + parts.push(`"erudaObjAbstract": "${escapeJsonStr(fnStr)}"`); + } + util.each(names, name => + { + parts.push(`"${escapeJsonStr(name)}": ${stringify(obj[name], visited, null, simple)}`); + }); + if (proto) parts.push(proto); + json += parts.join(', ') + '}'; + } + } else if (isNum) + { + json = obj + ''; + if (util.endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"`; + } else if (isBool) + { + json = obj ? 'true' : 'false'; + } else if (obj === null) + { + json = 'null'; + } else if (isSymbol) + { + json = '"Symbol"'; + } else if (obj === undefined) + { + json = '"undefined"'; + } else if (type === '[object HTMLAllCollection]') + { + // https://docs.webplatform.org/wiki/dom/HTMLAllCollection + // Might cause a performance issue when stringify a dom element. + json = '"[object HTMLAllCollection]"'; + } else + { + try + { + visited.push(obj); + + json = '{\n'; + if (!simple) parts.push(`"erudaObjAbstract": "${type.replace(/(\[object )|]/g, '')}"`); + names = Object.getOwnPropertyNames(obj); + proto = Object.getPrototypeOf(obj); + if (proto === Object.prototype || simple) proto = null; + if (proto) + { + try + { + proto = `"erudaProto": ${stringify(proto, visited, topObj)}`; + } catch(e) + { + proto = `"erudaProto": "${escapeJsonStr(e.message)}"`; + } + } + names.sort(sortObjName); + util.each(names, name => + { + let val = topObj[name]; + + try + { + parts.push(`"${escapeJsonStr(name)}": ${stringify(val, visited, null, simple)}`); + } catch (e) + { + parts.push(`"${escapeJsonStr(name)}": "${escapeJsonStr(e.message)}"`); + } + }); + if (proto) parts.push(proto); + json += parts.join(',\n') + '\n}'; + } catch (e) { + json = `"${obj}"`; + } + } + + return json; +} + +var escapeJsonStr = str => str.replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\f|\n|\r|\t/g, ''); + +var sortObjName = (a, b) => +{ + let codeA = a.charCodeAt(0), + codeB = b.charCodeAt(0); + + if (isLetter(codeA) && !isLetter(codeB)) return -1; + if (!isLetter(codeA) && isLetter(codeB)) return 1; + + return a > b ? 1 : -1; +}; + +var isLetter = code => (code > 64 && code < 90) || (code > 96 && code < 123); diff --git a/src/style/mixin.scss b/src/style/mixin.scss index d291e91..b477953 100644 --- a/src/style/mixin.scss +++ b/src/style/mixin.scss @@ -18,15 +18,13 @@ } @mixin breadcrumb { - .breadcrumb { - background: #fff; - margin-bottom: 10px; - word-break: break-all; - padding: $padding; - font-size: $font-size-l; - min-height: 40px; - border-bottom: 1px solid $gray-light; - } + background: #fff; + margin-bottom: 10px; + word-break: break-all; + padding: $padding; + font-size: $font-size-l; + min-height: 40px; + border-bottom: 1px solid $gray-light; } @mixin clear-float { diff --git a/webpack.config.js b/webpack.config.js index 7943e2e..8548320 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,7 +8,7 @@ var nodeModDir = path.resolve('./node_modules/') + '/', banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage; module.exports = { - devtool: 'source-map', + devtool: false, entry: './src/index.es6', devServer: { contentBase: './test'