eruda2
Version:
Console for Mobile Browsers
227 lines (196 loc) • 5.61 kB
JavaScript
import Tool from '../DevTools/Tool'
import { getFileName, isEmpty, $, ms, trim, each, last } from '../lib/util'
import evalCss from '../lib/evalCss'
import chobitsu from 'chobitsu'
chobitsu.domain('Network').enable()
export default class Network extends Tool {
constructor() {
super()
this._style = evalCss(require('./Network.scss'))
this.name = 'network'
this._requests = {}
this._tpl = require('./Network.hbs')
this._detailTpl = require('./detail.hbs')
this._requestsTpl = require('./requests.hbs')
this._detailData = {}
}
init($el, container) {
super.init($el)
this._container = container
this._bindEvent()
this._appendTpl()
}
show() {
super.show()
this._render()
}
clear() {
this._requests = {}
this._render()
}
requests() {
const ret = []
each(this._requests, (request) => {
ret.push(request)
})
return ret
}
_reqWillBeSent = (params) => {
this._requests[params.requestId] = {
name: getFileName(params.request.url),
url: params.request.url,
status: 'pending',
type: 'unknown',
subType: 'unknown',
size: 0,
data: params.request.postData,
method: params.request.method,
startTime: params.timestamp * 1000,
time: 0,
resTxt: '',
done: false,
reqHeaders: params.request.headers || {},
resHeaders: {},
}
}
_resReceivedExtraInfo = (params) => {
const target = this._requests[params.requestId]
if (!target) {
return
}
target.resHeaders = params.headers
this._updateType(target)
this._render()
}
_updateType(target) {
const contentType = target.resHeaders['content-type'] || ''
const { type, subType } = getType(contentType)
target.type = type
target.subType = subType
}
_resReceived = (params) => {
const target = this._requests[params.requestId]
if (!target) {
return
}
const { response } = params
const { status, headers } = response
target.status = status
if (status < 200 || status >= 300) {
target.hasErr = true
}
if (headers) {
target.resHeaders = headers
this._updateType(target)
}
this._render()
}
_loadingFinished = (params) => {
const target = this._requests[params.requestId]
if (!target) {
return
}
const time = params.timestamp * 1000
target.time = time - target.startTime
target.displayTime = ms(target.time)
target.size = params.encodedDataLength
target.done = true
target.resTxt = chobitsu.domain('Network').getResponseBody({
requestId: params.requestId,
}).body
this._render()
}
_bindEvent() {
const $el = this._$el
const container = this._container
const self = this
$el
.on('click', '.eruda-request', function () {
const id = $(this).data('id')
const data = self._requests[id]
if (!data.done) return
self._showDetail(data)
})
.on('click', '.eruda-clear-request', () => this.clear())
.on('click', '.eruda-back', () => this._hideDetail())
.on('click', '.eruda-http .eruda-response', () => {
const data = this._detailData
const resTxt = data.resTxt
switch (data.subType) {
case 'css':
return showSources('css', resTxt)
case 'html':
return showSources('html', resTxt)
case 'javascript':
return showSources('js', resTxt)
case 'json':
return showSources('object', resTxt)
}
switch (data.type) {
case 'image':
return showSources('img', data.url)
}
})
function showSources(type, data) {
const sources = container.get('sources')
if (!sources) return
sources.set(type, data)
container.showTool('sources')
}
const network = chobitsu.domain('Network')
network.on('requestWillBeSent', this._reqWillBeSent)
network.on('responseReceivedExtraInfo', this._resReceivedExtraInfo)
network.on('responseReceived', this._resReceived)
network.on('loadingFinished', this._loadingFinished)
}
destroy() {
super.destroy()
evalCss.remove(this._style)
const network = chobitsu.domain('Network')
network.off('requestWillBeSent', this._reqWillBeSent)
network.off('responseReceivedExtraInfo', this._resReceivedExtraInfo)
network.off('responseReceived', this._resReceived)
network.off('loadingFinished', this._loadingFinished)
}
_showDetail(data) {
if (data.resTxt && trim(data.resTxt) === '') {
delete data.resTxt
}
if (isEmpty(data.resHeaders)) {
delete data.resHeaders
}
if (isEmpty(data.reqHeaders)) {
delete data.reqHeaders
}
this._$detail.html(this._detailTpl(data)).show()
this._detailData = data
}
_hideDetail() {
this._$detail.hide()
}
_appendTpl() {
const $el = this._$el
$el.html(this._tpl())
this._$detail = $el.find('.eruda-detail')
this._$requests = $el.find('.eruda-requests')
}
_render() {
if (!this.active) return
const renderData = {}
if (!isEmpty(this._requests)) renderData.requests = this._requests
this._renderHtml(this._requestsTpl(renderData))
}
_renderHtml(html) {
if (html === this._lastHtml) return
this._lastHtml = html
this._$requests.html(html)
}
}
function getType(contentType) {
if (!contentType) return 'unknown'
const type = contentType.split(';')[0].split('/')
return {
type: type[0],
subType: last(type),
}
}