mirror of
https://github.com/liriliri/eruda.git
synced 2026-03-20 09:38:37 +08:00
302 lines
7.7 KiB
JavaScript
302 lines
7.7 KiB
JavaScript
import Logger from './Logger'
|
|
import Tool from '../DevTools/Tool'
|
|
import { noop, evalCss, $, Emitter } from '../lib/util'
|
|
import emitter from '../lib/emitter'
|
|
import Settings from '../Settings/Settings'
|
|
import stringify from './stringify'
|
|
|
|
export default class Console extends Tool {
|
|
constructor() {
|
|
super()
|
|
|
|
Emitter.mixin(this)
|
|
|
|
this.name = 'console'
|
|
this._scale = 1
|
|
|
|
this._registerListener()
|
|
}
|
|
init($el, container) {
|
|
super.init($el)
|
|
|
|
this._appendTpl()
|
|
|
|
this._initLogger()
|
|
this._exposeLogger()
|
|
this._rejectionHandler = e => this._logger.error(e.reason)
|
|
|
|
this._initCfg(container)
|
|
this._bindEvent(container)
|
|
}
|
|
show() {
|
|
super.show()
|
|
|
|
this._logger.render()
|
|
}
|
|
overrideConsole() {
|
|
let origConsole = (this._origConsole = {}),
|
|
winConsole = window.console
|
|
|
|
CONSOLE_METHOD.forEach(name => {
|
|
let origin = (origConsole[name] = noop)
|
|
if (winConsole[name])
|
|
origin = origConsole[name] = winConsole[name].bind(winConsole)
|
|
|
|
winConsole[name] = (...args) => {
|
|
this[name](...args)
|
|
origin(...args)
|
|
}
|
|
})
|
|
|
|
return this
|
|
}
|
|
restoreConsole() {
|
|
if (!this._origConsole) return this
|
|
|
|
CONSOLE_METHOD.forEach(
|
|
name => (window.console[name] = this._origConsole[name])
|
|
)
|
|
delete this._origConsole
|
|
|
|
return this
|
|
}
|
|
catchGlobalErr() {
|
|
this._origOnerror = window.onerror
|
|
|
|
window.onerror = (errMsg, url, lineNum, column, errObj) =>
|
|
this._logger.error(errObj ? errObj : errMsg)
|
|
window.addEventListener('unhandledrejection', this._rejectionHandler)
|
|
|
|
return this
|
|
}
|
|
ignoreGlobalErr() {
|
|
if (this._origOnerror) {
|
|
window.onerror = this._origOnerror
|
|
delete this._origOnerror
|
|
}
|
|
window.removeEventListener('unhandledrejection', this._rejectionHandler)
|
|
|
|
return this
|
|
}
|
|
destroy() {
|
|
this._logger.destroy()
|
|
super.destroy()
|
|
|
|
evalCss.remove(this._style)
|
|
this.ignoreGlobalErr()
|
|
this.restoreConsole()
|
|
this._unregisterListener()
|
|
}
|
|
_registerListener() {
|
|
this._scaleListener = scale => (this._scale = scale)
|
|
|
|
emitter.on(emitter.SCALE, this._scaleListener)
|
|
}
|
|
_unregisterListener() {
|
|
emitter.off(emitter.SCALE, this._scaleListener)
|
|
}
|
|
_appendTpl() {
|
|
let $el = this._$el
|
|
|
|
this._style = evalCss(require('./Console.scss'))
|
|
$el.append(require('./Console.hbs')())
|
|
|
|
let _$inputContainer = $el.find('.eruda-js-input'),
|
|
_$input = _$inputContainer.find('textarea'),
|
|
_$inputBtns = _$inputContainer.find('.eruda-buttons')
|
|
|
|
Object.assign(this, {
|
|
_$control: $el.find('.eruda-control'),
|
|
_$logs: $el.find('.eruda-logs'),
|
|
_$inputContainer,
|
|
_$input,
|
|
_$inputBtns
|
|
})
|
|
}
|
|
_initLogger() {
|
|
let $filter = this._$control.find('.eruda-filter'),
|
|
logger = (this._logger = new Logger(this._$logs, this))
|
|
|
|
logger.on('filter', filter =>
|
|
$filter.each(function() {
|
|
let $this = $(this),
|
|
isMatch = $this.data('filter') === filter
|
|
|
|
$this[isMatch ? 'addClass' : 'rmClass']('eruda-active')
|
|
})
|
|
)
|
|
}
|
|
_exposeLogger() {
|
|
let logger = this._logger,
|
|
methods = ['filter', 'html'].concat(CONSOLE_METHOD)
|
|
|
|
methods.forEach(
|
|
name =>
|
|
(this[name] = (...args) => {
|
|
logger[name](...args)
|
|
this.emit(name, ...args)
|
|
|
|
return this
|
|
})
|
|
)
|
|
}
|
|
_bindEvent(container) {
|
|
let $input = this._$input,
|
|
$inputBtns = this._$inputBtns,
|
|
$control = this._$control,
|
|
logger = this._logger,
|
|
config = this.config
|
|
|
|
$control
|
|
.on('click', '.eruda-clear-console', () => logger.clear())
|
|
.on('click', '.eruda-filter', function() {
|
|
logger.filter($(this).data('filter'))
|
|
})
|
|
.on('click', '.eruda-help', () => logger.help())
|
|
|
|
$inputBtns
|
|
.on('click', '.eruda-cancel', () => this._hideInput())
|
|
.on('click', '.eruda-execute', () => {
|
|
let jsInput = $input.val().trim()
|
|
if (jsInput === '') return
|
|
|
|
logger.input(jsInput)
|
|
$input
|
|
.val('')
|
|
.get(0)
|
|
.blur()
|
|
this._hideInput()
|
|
})
|
|
|
|
$input.on('focusin', () => this._showInput())
|
|
|
|
logger
|
|
.on('viewJson', data => {
|
|
let sources = container.get('sources')
|
|
if (!sources) return
|
|
|
|
sources.set('json', data)
|
|
container.showTool('sources')
|
|
})
|
|
.on('insert', log => {
|
|
let autoShow = log.type === 'error' && config.get('displayIfErr')
|
|
|
|
if (autoShow) container.showTool('console').show()
|
|
})
|
|
}
|
|
_hideInput() {
|
|
this._$inputContainer.css({
|
|
paddingTop: 0,
|
|
height: 40 * this._scale
|
|
})
|
|
|
|
this._$inputBtns.hide()
|
|
}
|
|
_showInput() {
|
|
this._$inputContainer.css({
|
|
paddingTop: 40 * this._scale,
|
|
height: '100%'
|
|
})
|
|
|
|
this._$inputBtns.show()
|
|
}
|
|
_initCfg(container) {
|
|
let sources = container.get('sources'),
|
|
logger = this._logger
|
|
|
|
let cfg = (this.config = Settings.createCfg('console', {
|
|
catchGlobalErr: true,
|
|
overrideConsole: true,
|
|
displayExtraInfo: false,
|
|
displayUnenumerable: true,
|
|
displayGetterVal: false,
|
|
lazyEvaluation: true,
|
|
viewLogInSources: false,
|
|
displayIfErr: false,
|
|
useWorker: true,
|
|
maxLogNum: 'infinite'
|
|
}))
|
|
|
|
let isWorkerSupported = !!window.Worker
|
|
|
|
let maxLogNum = cfg.get('maxLogNum')
|
|
maxLogNum = maxLogNum === 'infinite' ? maxLogNum : +maxLogNum
|
|
|
|
if (cfg.get('catchGlobalErr')) this.catchGlobalErr()
|
|
if (cfg.get('overrideConsole')) this.overrideConsole()
|
|
if (cfg.get('useWorker') && isWorkerSupported) stringify.useWorker = true
|
|
logger.displayHeader(cfg.get('displayExtraInfo'))
|
|
logger.displayUnenumerable(cfg.get('displayUnenumerable'))
|
|
logger.displayGetterVal(cfg.get('displayGetterVal'))
|
|
logger.lazyEvaluation(cfg.get('lazyEvaluation'))
|
|
if (sources) logger.viewLogInSources(cfg.get('viewLogInSources'))
|
|
logger.maxNum(maxLogNum)
|
|
|
|
cfg.on('change', (key, val) => {
|
|
switch (key) {
|
|
case 'catchGlobalErr':
|
|
return val ? this.catchGlobalErr() : this.ignoreGlobalErr()
|
|
case 'overrideConsole':
|
|
return val ? this.overrideConsole() : this.restoreConsole()
|
|
case 'maxLogNum':
|
|
return logger.maxNum(val === 'infinite' ? val : +val)
|
|
case 'displayExtraInfo':
|
|
return logger.displayHeader(val)
|
|
case 'displayUnenumerable':
|
|
return logger.displayUnenumerable(val)
|
|
case 'displayGetterVal':
|
|
return logger.displayGetterVal(val)
|
|
case 'lazyEvaluation':
|
|
return logger.lazyEvaluation(val)
|
|
case 'viewLogInSources':
|
|
return logger.viewLogInSources(val)
|
|
case 'useWorker':
|
|
stringify.useWorker = val
|
|
return
|
|
}
|
|
})
|
|
|
|
let settings = container.get('settings')
|
|
|
|
settings
|
|
.text('Console')
|
|
.switch(cfg, 'catchGlobalErr', 'Catch Global Errors')
|
|
.switch(cfg, 'overrideConsole', 'Override Console')
|
|
.switch(cfg, 'displayIfErr', 'Auto Display If Error Occurs')
|
|
.switch(cfg, 'displayExtraInfo', 'Display Extra Information')
|
|
.switch(cfg, 'displayUnenumerable', 'Display Unenumerable Properties')
|
|
.switch(cfg, 'displayGetterVal', 'Access Getter Value')
|
|
.switch(cfg, 'lazyEvaluation', 'Lazy Evaluation')
|
|
|
|
if (isWorkerSupported) settings.switch(cfg, 'useWorker', 'Use Web Worker')
|
|
if (sources)
|
|
settings.switch(cfg, 'viewLogInSources', 'View Log In Sources Panel')
|
|
|
|
settings
|
|
.select(cfg, 'maxLogNum', 'Max Log Number', [
|
|
'infinite',
|
|
'250',
|
|
'125',
|
|
'100',
|
|
'50',
|
|
'10'
|
|
])
|
|
.separator()
|
|
}
|
|
}
|
|
|
|
const CONSOLE_METHOD = [
|
|
'log',
|
|
'error',
|
|
'info',
|
|
'warn',
|
|
'dir',
|
|
'time',
|
|
'timeEnd',
|
|
'clear',
|
|
'table',
|
|
'assert',
|
|
'count',
|
|
'debug'
|
|
]
|