mirror of
https://github.com/liriliri/eruda.git
synced 2026-03-20 09:38:37 +08:00
chore: use luna object viewer
This commit is contained in:
@@ -16,7 +16,8 @@ const postcssLoader = {
|
||||
options: {
|
||||
plugins: [
|
||||
prefixer({
|
||||
prefix: '_'
|
||||
prefix: '_',
|
||||
ignore: [/luna-object-viewer/]
|
||||
}),
|
||||
autoprefixer,
|
||||
clean()
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^4.0.2",
|
||||
"licia": "^1.19.0",
|
||||
"luna-object-viewer": "^0.1.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"postcss-clean": "^1.1.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import origGetAbstract from '../lib/getAbstract'
|
||||
import beautify from 'js-beautify'
|
||||
import JsonViewer from '../lib/JsonViewer'
|
||||
import ObjViewer from '../lib/ObjViewer'
|
||||
import LunaObjectViewer from 'luna-object-viewer'
|
||||
import {
|
||||
isObj,
|
||||
isStr,
|
||||
@@ -210,16 +209,18 @@ export default class Log extends Emitter {
|
||||
if ($json.hasClass('eruda-hidden')) {
|
||||
if ($json.data('init') !== 'true') {
|
||||
if (src) {
|
||||
const jsonViewer = new JsonViewer(src, $json)
|
||||
jsonViewer.on('change', () => this.updateSize(false))
|
||||
const staticViewer = new LunaObjectViewer.Static($json.get(0))
|
||||
staticViewer.set(src)
|
||||
staticViewer.on('change', () => this.updateSize(false))
|
||||
} else {
|
||||
if (type === 'table' || args.length === 1) {
|
||||
if (isObj(args[0])) args = args[0]
|
||||
}
|
||||
const objViewer = new ObjViewer(args, $json, {
|
||||
showUnenumerable: Log.showUnenumerable,
|
||||
showGetterVal: Log.showGetterVal
|
||||
const objViewer = new LunaObjectViewer($json.get(0), {
|
||||
unenumerable: Log.showUnenumerable,
|
||||
accessGetter: Log.showGetterVal
|
||||
})
|
||||
objViewer.set(args)
|
||||
objViewer.on('change', () => this.updateSize(false))
|
||||
}
|
||||
$json.data('init', 'true')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Tool from '../DevTools/Tool'
|
||||
import beautify from 'js-beautify'
|
||||
import ObjViewer from '../lib/ObjViewer'
|
||||
import LunaObjectViewer from 'luna-object-viewer'
|
||||
import Settings from '../Settings/Settings'
|
||||
import { ajax, escape, trim, isStr, highlight } from '../lib/util'
|
||||
import evalCss from '../lib/evalCss'
|
||||
@@ -247,10 +247,14 @@ export default class Sources extends Tool {
|
||||
/* eslint-disable no-empty */
|
||||
} catch (e) {}
|
||||
|
||||
new ObjViewer(val, this._$el.find('.eruda-json'), {
|
||||
showUnenumerable: true,
|
||||
showGetterVal: true
|
||||
})
|
||||
const objViewer = new LunaObjectViewer(
|
||||
this._$el.find('.eruda-json').get(0),
|
||||
{
|
||||
unenumerable: true,
|
||||
accessGetter: true
|
||||
}
|
||||
)
|
||||
objViewer.set(val)
|
||||
}
|
||||
_renderRaw() {
|
||||
this._renderHtml(this._rawTpl({ val: this._data.val }))
|
||||
|
||||
@@ -198,6 +198,7 @@ export default {
|
||||
}
|
||||
|
||||
evalCss(
|
||||
require('luna-object-viewer/luna-object-viewer.css') +
|
||||
require('./style/style.scss') +
|
||||
require('./style/reset.scss') +
|
||||
require('./style/icon.css')
|
||||
|
||||
@@ -1,338 +0,0 @@
|
||||
import {
|
||||
$,
|
||||
startWith,
|
||||
isObj,
|
||||
uniqId,
|
||||
upperFirst,
|
||||
toNum,
|
||||
toStr,
|
||||
escape,
|
||||
chunk,
|
||||
each,
|
||||
isNaN,
|
||||
isNum,
|
||||
isBool,
|
||||
keys,
|
||||
trim,
|
||||
lowerCase,
|
||||
Emitter
|
||||
} from './util'
|
||||
import evalCss from './evalCss'
|
||||
|
||||
let hasEvalCss = false
|
||||
|
||||
export default class JsonViewer extends Emitter {
|
||||
constructor(data, $el) {
|
||||
super()
|
||||
|
||||
if (!hasEvalCss) {
|
||||
evalCss(require('./json.scss'))
|
||||
hasEvalCss = true
|
||||
}
|
||||
|
||||
this._data = {
|
||||
id: uniqId('json'),
|
||||
enumerable: {
|
||||
0: data
|
||||
}
|
||||
}
|
||||
this._$el = $el
|
||||
this._map = {}
|
||||
createMap(this._map, this._data)
|
||||
|
||||
this._appendTpl()
|
||||
this._bindEvent()
|
||||
}
|
||||
_jsonToHtml(data, firstLevel) {
|
||||
let ret = ''
|
||||
|
||||
each(['enumerable', 'unenumerable', 'symbol'], type => {
|
||||
if (!data[type]) return
|
||||
|
||||
const typeKeys = keys(data[type])
|
||||
typeKeys.sort(sortObjName)
|
||||
for (let i = 0, len = typeKeys.length; i < len; i++) {
|
||||
const key = typeKeys[i]
|
||||
ret += this._createEl(key, data[type][key], type, firstLevel)
|
||||
}
|
||||
})
|
||||
|
||||
if (data.proto) {
|
||||
if (ret === '') {
|
||||
ret = this._jsonToHtml(data.proto)
|
||||
} else {
|
||||
ret += this._createEl('__proto__', data.proto, 'proto')
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
_createEl(key, val, keyType, firstLevel = false) {
|
||||
let type = typeof val
|
||||
|
||||
if (val === null) {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-null">null</span></li>`
|
||||
} else if (isNum(val) || isBool(val)) {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${type}">${encode(
|
||||
val
|
||||
)}</span></li>`
|
||||
}
|
||||
|
||||
if (val.type === 'RegExp') type = 'regexp'
|
||||
if (val.type === 'Number') type = 'number'
|
||||
|
||||
if (val.type === 'Number' || val.type === 'RegExp') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${type}">${encode(
|
||||
val.value
|
||||
)}</span></li>`
|
||||
} else if (val.type === 'Undefined' || val.type === 'Symbol') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-special">${lowerCase(
|
||||
val.type
|
||||
)}</span></li>`
|
||||
} else if (val === '(...)') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-special">${val}</span></li>`
|
||||
} else if (isObj(val)) {
|
||||
const id = val.id
|
||||
const referenceId = val.reference
|
||||
const objAbstract = getObjAbstract(val) || upperFirst(type)
|
||||
|
||||
let obj = `<li ${
|
||||
firstLevel ? 'data-first-level="true"' : ''
|
||||
} ${'data-object-id="' + (referenceId || id) + '"'}><span class="${
|
||||
firstLevel ? '' : 'eruda-expanded eruda-collapsed'
|
||||
}"></span>${wrapKey(key)}<span class="eruda-open">${
|
||||
firstLevel ? '' : objAbstract
|
||||
}</span><ul class="eruda-${type}" ${
|
||||
firstLevel ? '' : 'style="display:none"'
|
||||
}>`
|
||||
|
||||
if (firstLevel) obj += this._jsonToHtml(this._map[id])
|
||||
|
||||
return obj + '</ul><span class="eruda-close"></span></li>'
|
||||
}
|
||||
|
||||
function wrapKey(key) {
|
||||
if (firstLevel) return ''
|
||||
if (isObj(val) && val.jsonSplitArr) return ''
|
||||
|
||||
let keyClass = 'eruda-key'
|
||||
if (
|
||||
keyType === 'unenumerable' ||
|
||||
keyType === 'proto' ||
|
||||
keyType === 'symbol'
|
||||
) {
|
||||
keyClass = 'eruda-key-lighter'
|
||||
}
|
||||
|
||||
return `<span class="${keyClass}">${encode(key)}</span>: `
|
||||
}
|
||||
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${typeof val}">"${encode(
|
||||
val
|
||||
)}"</span></li>`
|
||||
}
|
||||
_appendTpl() {
|
||||
const data = this._map[this._data.id]
|
||||
|
||||
this._$el.html(this._jsonToHtml(data, true))
|
||||
}
|
||||
_bindEvent() {
|
||||
const map = this._map
|
||||
|
||||
const self = this
|
||||
|
||||
this._$el.on('click', 'li', function(e) {
|
||||
const $this = $(this)
|
||||
const circularId = $this.data('object-id')
|
||||
const $firstSpan = $(this)
|
||||
.find('span')
|
||||
.eq(0)
|
||||
|
||||
if ($this.data('first-level')) return
|
||||
if (circularId) {
|
||||
$this.find('ul').html(self._jsonToHtml(map[circularId], false))
|
||||
$this.rmAttr('data-object-id')
|
||||
}
|
||||
|
||||
e.stopImmediatePropagation()
|
||||
|
||||
if (!$firstSpan.hasClass('eruda-expanded')) return
|
||||
|
||||
const $ul = $this.find('ul').eq(0)
|
||||
if ($firstSpan.hasClass('eruda-collapsed')) {
|
||||
$firstSpan.rmClass('eruda-collapsed')
|
||||
$ul.show()
|
||||
} else {
|
||||
$firstSpan.addClass('eruda-collapsed')
|
||||
$ul.hide()
|
||||
}
|
||||
|
||||
self.emit('change')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createMap(map, data) {
|
||||
const id = data.id
|
||||
|
||||
if (!id && id !== 0) return
|
||||
|
||||
const isArr = data.type && startWith(data.type, 'Array')
|
||||
if (isArr && data.enumerable) {
|
||||
const arr = objToArr(data, id, data.type)
|
||||
if (arr.length > 100) data = splitBigArr(arr)
|
||||
}
|
||||
map[id] = data
|
||||
|
||||
const values = []
|
||||
each(['enumerable', 'unenumerable', 'symbol'], type => {
|
||||
if (!data[type]) return
|
||||
for (const key in data[type]) {
|
||||
values.push(data[type][key])
|
||||
}
|
||||
})
|
||||
if (data.proto) {
|
||||
values.push(data.proto)
|
||||
}
|
||||
for (let i = 0, len = values.length; i < len; i++) {
|
||||
const val = values[i]
|
||||
if (isObj(val)) createMap(map, val)
|
||||
}
|
||||
}
|
||||
|
||||
function splitBigArr(data) {
|
||||
let idx = 0
|
||||
const enumerable = {}
|
||||
each(chunk(data, 100), val => {
|
||||
const obj = {}
|
||||
const startIdx = idx
|
||||
obj.type = '[' + startIdx
|
||||
obj.enumerable = {}
|
||||
each(val, val => {
|
||||
obj.enumerable[idx] = val
|
||||
idx += 1
|
||||
})
|
||||
const endIdx = idx - 1
|
||||
obj.type += (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']'
|
||||
obj.id = uniqId('json')
|
||||
obj.jsonSplitArr = true
|
||||
enumerable[idx] = obj
|
||||
})
|
||||
|
||||
const ret = {}
|
||||
ret.enumerable = enumerable
|
||||
ret.id = data.id
|
||||
ret.type = data.type
|
||||
if (data.unenumerable) ret.unenumerable = data.unenumerable
|
||||
if (data.symbol) ret.symbol = data.symbol
|
||||
if (data.proto) ret.proto = data.proto
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
function objToArr(data, id, type) {
|
||||
const ret = []
|
||||
|
||||
const enumerable = {}
|
||||
each(data.enumerable, (val, key) => {
|
||||
const idx = toNum(key)
|
||||
if (!isNaN(idx)) {
|
||||
ret[idx] = val
|
||||
} else {
|
||||
enumerable[key] = val
|
||||
}
|
||||
})
|
||||
|
||||
ret.enumerable = enumerable
|
||||
ret.type = type
|
||||
ret.id = id
|
||||
if (data.unenumerable) ret.unenumerable = data.unenumerable
|
||||
if (data.symbol) ret.symbol = data.symbol
|
||||
if (data.proto) ret.proto = data.proto
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
export const encode = str => {
|
||||
return escape(toStr(str))
|
||||
.replace(/\n/g, '↵')
|
||||
.replace(/\f|\r|\t/g, '')
|
||||
}
|
||||
|
||||
// $, 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)) {
|
||||
if (numA > numB) return 1
|
||||
if (numA < numB) return -1
|
||||
return 0
|
||||
}
|
||||
|
||||
if (startWith(a, 'get ') || startWith(a, 'set ')) a = a.slice(4)
|
||||
if (startWith(b, 'get ') || startWith(b, 'set ')) b = b.slice(4)
|
||||
|
||||
const lenA = a.length
|
||||
const lenB = b.length
|
||||
const len = lenA > lenB ? lenB : lenA
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const codeA = a.charCodeAt(i)
|
||||
const codeB = b.charCodeAt(i)
|
||||
const cmpResult = cmpCode(codeA, codeB)
|
||||
|
||||
if (cmpResult !== 0) return cmpResult
|
||||
}
|
||||
|
||||
if (lenA > lenB) return 1
|
||||
if (lenA < lenB) return -1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function cmpCode(a, b) {
|
||||
a = transCode(a)
|
||||
b = transCode(b)
|
||||
|
||||
if (a > b) return 1
|
||||
if (a < b) return -1
|
||||
return 0
|
||||
}
|
||||
|
||||
function transCode(code) {
|
||||
// _ should be placed after lowercase chars.
|
||||
if (code === 95) return 123
|
||||
return code
|
||||
}
|
||||
|
||||
export function getObjAbstract(data) {
|
||||
const { type, value } = data
|
||||
if (!type) return
|
||||
|
||||
if (type === 'Function') {
|
||||
return getFnAbstract(value)
|
||||
}
|
||||
if (type === 'Array' && data.unenumerable) {
|
||||
return `Array(${data.unenumerable.length})`
|
||||
}
|
||||
|
||||
return data.type
|
||||
}
|
||||
|
||||
const regFnHead = /function(.*?)\((.*?)\)/
|
||||
|
||||
function extractFnHead(str) {
|
||||
const fnHead = str.match(regFnHead)
|
||||
|
||||
if (fnHead) return fnHead[0]
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
export function getFnAbstract(str) {
|
||||
if (str.length > 500) str = str.slice(0, 500) + '...'
|
||||
|
||||
return 'ƒ ' + trim(extractFnHead(str).replace('function', ''))
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
import {
|
||||
extend,
|
||||
Emitter,
|
||||
getProto,
|
||||
isNum,
|
||||
isBool,
|
||||
lowerCase,
|
||||
isObj,
|
||||
isArr,
|
||||
upperFirst,
|
||||
keys,
|
||||
each,
|
||||
toSrc,
|
||||
isPromise,
|
||||
type,
|
||||
$,
|
||||
difference,
|
||||
allKeys,
|
||||
filter,
|
||||
chunk
|
||||
} from './util'
|
||||
import { encode, getFnAbstract, sortObjName } from './JsonViewer'
|
||||
import evalCss from './evalCss'
|
||||
|
||||
let hasEvalCss = false
|
||||
|
||||
export default class ObjViewer extends Emitter {
|
||||
constructor(
|
||||
data,
|
||||
$el,
|
||||
{ showUnenumerable = false, showGetterVal = false } = {}
|
||||
) {
|
||||
super()
|
||||
|
||||
if (!hasEvalCss) {
|
||||
evalCss(require('./json.scss'))
|
||||
hasEvalCss = true
|
||||
}
|
||||
|
||||
this._data = [data]
|
||||
this._$el = $el
|
||||
this._visitor = new Visitor()
|
||||
this._map = {}
|
||||
this._showUnenumerable = showUnenumerable
|
||||
this._showGetterVal = showGetterVal
|
||||
|
||||
this._appendTpl()
|
||||
this._bindEvent()
|
||||
}
|
||||
_objToHtml(data, firstLevel) {
|
||||
const visitor = this._visitor
|
||||
let self = data
|
||||
let isBigArr = false
|
||||
const visitedObj = visitor.get(data)
|
||||
if (visitedObj && visitedObj.self) {
|
||||
self = visitedObj.self
|
||||
}
|
||||
|
||||
let ret = ''
|
||||
|
||||
const types = ['enumerable']
|
||||
let enumerableKeys = keys(data)
|
||||
let unenumerableKeys = []
|
||||
let symbolKeys = []
|
||||
let virtualKeys = []
|
||||
const virtualData = {}
|
||||
|
||||
if (this._showUnenumerable && !firstLevel) {
|
||||
types.push('unenumerable')
|
||||
types.push('symbol')
|
||||
unenumerableKeys = difference(
|
||||
allKeys(data, {
|
||||
prototype: false,
|
||||
unenumerable: true
|
||||
}),
|
||||
enumerableKeys
|
||||
)
|
||||
symbolKeys = filter(
|
||||
allKeys(data, {
|
||||
prototype: false,
|
||||
symbol: true
|
||||
}),
|
||||
key => {
|
||||
return typeof key === 'symbol'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (isArr(data) && data.length > 100) {
|
||||
types.unshift('virtual')
|
||||
isBigArr = true
|
||||
let idx = 0
|
||||
const map = {}
|
||||
each(chunk(data, 100), val => {
|
||||
const obj = Object.create(null)
|
||||
const startIdx = idx
|
||||
let key = '[' + startIdx
|
||||
each(val, val => {
|
||||
obj[idx] = val
|
||||
map[idx] = true
|
||||
idx++
|
||||
})
|
||||
const endIdx = idx - 1
|
||||
key += (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']'
|
||||
virtualData[key] = obj
|
||||
})
|
||||
virtualKeys = keys(virtualData)
|
||||
enumerableKeys = filter(enumerableKeys, val => !map[val])
|
||||
}
|
||||
|
||||
each(types, type => {
|
||||
let typeKeys = []
|
||||
if (type === 'symbol') {
|
||||
typeKeys = symbolKeys
|
||||
} else if (type === 'unenumerable') {
|
||||
typeKeys = unenumerableKeys
|
||||
} else if (type === 'virtual') {
|
||||
typeKeys = virtualKeys
|
||||
} else {
|
||||
typeKeys = enumerableKeys
|
||||
}
|
||||
if (!isBigArr) {
|
||||
typeKeys.sort(sortObjName)
|
||||
}
|
||||
for (let i = 0, len = typeKeys.length; i < len; i++) {
|
||||
const key = typeKeys[i]
|
||||
let val = ''
|
||||
const descriptor = Object.getOwnPropertyDescriptor(data, key)
|
||||
const hasGetter = descriptor && descriptor.get
|
||||
const hasSetter = descriptor && descriptor.set
|
||||
if (hasGetter && !this._showGetterVal) {
|
||||
val = '(...)'
|
||||
} else {
|
||||
try {
|
||||
if (type === 'virtual') {
|
||||
val = virtualData[key]
|
||||
} else {
|
||||
val = self[key]
|
||||
}
|
||||
if (isPromise(val)) {
|
||||
val.catch(() => {})
|
||||
}
|
||||
} catch (e) {
|
||||
val = e.message
|
||||
}
|
||||
}
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const proto = getProto(data)
|
||||
if (!firstLevel && proto) {
|
||||
if (ret === '') {
|
||||
const id = visitor.set(proto, {
|
||||
self: data
|
||||
})
|
||||
this._map[id] = proto
|
||||
ret = this._objToHtml(proto)
|
||||
} else {
|
||||
ret += this._createEl('__proto__', self || data, proto, 'proto')
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
_createEl(key, self, val, keyType, firstLevel = false) {
|
||||
const visitor = this._visitor
|
||||
let t = typeof val
|
||||
let valType = type(val, false)
|
||||
if (keyType === 'virtual') valType = key
|
||||
|
||||
if (val === null) {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-null">null</span></li>`
|
||||
} else if (isNum(val) || isBool(val)) {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${t}">${encode(
|
||||
val
|
||||
)}</span></li>`
|
||||
}
|
||||
|
||||
if (valType === 'RegExp') t = 'regexp'
|
||||
if (valType === 'Number') t = 'number'
|
||||
|
||||
if (valType === 'Number' || valType === 'RegExp') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${t}">${encode(
|
||||
val.value
|
||||
)}</span></li>`
|
||||
} else if (valType === 'Undefined' || valType === 'Symbol') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-special">${lowerCase(
|
||||
valType
|
||||
)}</span></li>`
|
||||
} else if (val === '(...)') {
|
||||
return `<li>${wrapKey(key)}<span class="eruda-special">${val}</span></li>`
|
||||
} else if (isObj(val)) {
|
||||
const visitedObj = visitor.get(val)
|
||||
let id
|
||||
if (visitedObj) {
|
||||
id = visitedObj.id
|
||||
} else {
|
||||
const extra = {}
|
||||
if (keyType === 'proto') {
|
||||
extra.self = self
|
||||
}
|
||||
id = visitor.set(val, extra)
|
||||
this._map[id] = val
|
||||
}
|
||||
const objAbstract = getObjAbstract(val, valType) || upperFirst(t)
|
||||
|
||||
let obj = `<li ${
|
||||
firstLevel ? 'data-first-level="true"' : ''
|
||||
} ${'data-object-id="' + id + '"'}><span class="${
|
||||
firstLevel ? '' : 'eruda-expanded eruda-collapsed'
|
||||
}"></span>${wrapKey(key)}<span class="eruda-open">${
|
||||
firstLevel ? '' : objAbstract
|
||||
}</span><ul class="eruda-${t}" ${
|
||||
firstLevel ? '' : 'style="display:none"'
|
||||
}>`
|
||||
|
||||
if (firstLevel) obj += this._objToHtml(val)
|
||||
|
||||
return obj + '</ul><span class="eruda-close"></span></li>'
|
||||
}
|
||||
|
||||
function wrapKey(key) {
|
||||
if (firstLevel) return ''
|
||||
if (isObj(val) && keyType === 'virtual') return ''
|
||||
|
||||
let keyClass = 'eruda-key'
|
||||
if (
|
||||
keyType === 'unenumerable' ||
|
||||
keyType === 'proto' ||
|
||||
keyType === 'symbol'
|
||||
) {
|
||||
keyClass = 'eruda-key-lighter'
|
||||
}
|
||||
|
||||
return `<span class="${keyClass}">${encode(key)}</span>: `
|
||||
}
|
||||
|
||||
return `<li>${wrapKey(key)}<span class="eruda-${typeof val}">"${encode(
|
||||
val
|
||||
)}"</span></li>`
|
||||
}
|
||||
_appendTpl() {
|
||||
this._$el.html(this._objToHtml(this._data, true))
|
||||
}
|
||||
_bindEvent() {
|
||||
const map = this._map
|
||||
|
||||
const self = this
|
||||
|
||||
this._$el.on('click', 'li', function(e) {
|
||||
const $this = $(this)
|
||||
const circularId = $this.data('object-id')
|
||||
const $firstSpan = $(this)
|
||||
.find('span')
|
||||
.eq(0)
|
||||
|
||||
if ($this.data('first-level')) return
|
||||
if (circularId) {
|
||||
$this.find('ul').html(self._objToHtml(map[circularId], false))
|
||||
$this.rmAttr('data-object-id')
|
||||
}
|
||||
|
||||
e.stopImmediatePropagation()
|
||||
|
||||
if (!$firstSpan.hasClass('eruda-expanded')) return
|
||||
|
||||
const $ul = $this.find('ul').eq(0)
|
||||
if ($firstSpan.hasClass('eruda-collapsed')) {
|
||||
$firstSpan.rmClass('eruda-collapsed')
|
||||
$ul.show()
|
||||
} else {
|
||||
$firstSpan.addClass('eruda-collapsed')
|
||||
$ul.hide()
|
||||
}
|
||||
|
||||
self.emit('change')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getObjAbstract(data, type) {
|
||||
if (!type) return
|
||||
|
||||
if (type === 'Function') {
|
||||
return getFnAbstract(toSrc(data))
|
||||
}
|
||||
if (type === 'Array') {
|
||||
return `Array(${data.length})`
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
class Visitor {
|
||||
constructor() {
|
||||
this.id = 0
|
||||
this.visited = []
|
||||
}
|
||||
set(val, extra) {
|
||||
const { visited, id } = this
|
||||
const obj = {
|
||||
id,
|
||||
val
|
||||
}
|
||||
extend(obj, extra)
|
||||
visited.push(obj)
|
||||
|
||||
this.id++
|
||||
|
||||
return id
|
||||
}
|
||||
get(val) {
|
||||
const { visited } = this
|
||||
|
||||
for (let i = 0, len = visited.length; i < len; i++) {
|
||||
const obj = visited[i]
|
||||
if (val === obj.val) return obj
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -74,10 +74,7 @@ function resetStyle({ css, el }) {
|
||||
css = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px')
|
||||
css = css.replace(/_/g, 'eruda-')
|
||||
each(cssMap, (val, key) => {
|
||||
css = css.replace(
|
||||
new RegExp(escapeRegExp(`$${val}:`), 'g'),
|
||||
key + ':'
|
||||
)
|
||||
css = css.replace(new RegExp(escapeRegExp(`$${val}:`), 'g'), key + ':')
|
||||
})
|
||||
const _keys = keys(themes.Light)
|
||||
each(_keys, key => {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
@import '../style/variable';
|
||||
@import '../style/mixin';
|
||||
|
||||
.container .json {
|
||||
@include overflow-auto(x);
|
||||
cursor: default;
|
||||
font-size: $font-size-s;
|
||||
line-height: 1.2;
|
||||
min-height: 100%;
|
||||
color: var(--primary);
|
||||
&,
|
||||
ul {
|
||||
list-style: none !important;
|
||||
}
|
||||
ul {
|
||||
padding: 0 !important;
|
||||
padding-left: 15px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
li {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
line-height: 16px;
|
||||
min-height: 16px;
|
||||
}
|
||||
& > li > .key {
|
||||
display: none;
|
||||
}
|
||||
& > li {
|
||||
padding: $padding 0;
|
||||
}
|
||||
.array .object .key {
|
||||
display: inline;
|
||||
}
|
||||
.null {
|
||||
color: var(--operator-color);
|
||||
}
|
||||
.string,
|
||||
.regexp {
|
||||
color: var(--string-color);
|
||||
}
|
||||
.number {
|
||||
color: var(--number-color);
|
||||
}
|
||||
.boolean {
|
||||
color: var(--keyword-color);
|
||||
}
|
||||
.special {
|
||||
color: var(--operator-color);
|
||||
}
|
||||
.key,
|
||||
.key-lighter {
|
||||
color: var(--var-color);
|
||||
}
|
||||
.key-lighter {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.expanded:before {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
position: absolute;
|
||||
border-top-color: var(--foreground);
|
||||
left: -12px;
|
||||
top: 6px;
|
||||
}
|
||||
.collapsed:before {
|
||||
content: '';
|
||||
border-left-color: var(--foreground);
|
||||
border-top-color: transparent;
|
||||
left: -10px;
|
||||
top: 4px;
|
||||
}
|
||||
li .collapsed ~ .close:before {
|
||||
color: #999;
|
||||
}
|
||||
.hidden ~ ul {
|
||||
display: none;
|
||||
}
|
||||
span {
|
||||
position: static !important;
|
||||
}
|
||||
}
|
||||
37
src/style/luna.scss
Normal file
37
src/style/luna.scss
Normal file
@@ -0,0 +1,37 @@
|
||||
@import './variable';
|
||||
|
||||
.luna-object-viewer {
|
||||
color: var(--primary);
|
||||
font-size: 12px !important;
|
||||
& > li {
|
||||
padding: $padding 0 !important;
|
||||
}
|
||||
}
|
||||
.luna-object-viewer-null {
|
||||
color: var(--operator-color);
|
||||
}
|
||||
.luna-object-viewer-string,
|
||||
.luna-object-viewer-regexp {
|
||||
color: var(--string-color);
|
||||
}
|
||||
.luna-object-viewer-number {
|
||||
color: var(--number-color);
|
||||
}
|
||||
.luna-object-viewer-boolean {
|
||||
color: var(--keyword-color);
|
||||
}
|
||||
.luna-object-viewer-special {
|
||||
color: var(--operator-color);
|
||||
}
|
||||
.luna-object-viewer-key,
|
||||
.luna-object-viewer-key-lighter {
|
||||
color: var(--var-color);
|
||||
}
|
||||
.luna-object-viewer-expanded:before {
|
||||
border-color: transparent;
|
||||
border-top-color: var(--foreground);
|
||||
}
|
||||
.luna-object-viewer-collapsed:before {
|
||||
border-top-color: transparent;
|
||||
border-left-color: var(--foreground);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@import 'variable';
|
||||
@import 'mixin';
|
||||
@import 'luna';
|
||||
|
||||
.container {
|
||||
pointer-events: none;
|
||||
|
||||
Reference in New Issue
Block a user