Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b875b68bc | ||
|
|
6175dfd430 | ||
|
|
d7ecb9f91d | ||
|
|
fe05016000 | ||
|
|
16d0f73509 | ||
|
|
64a3279f18 | ||
|
|
2aa61cf2dc | ||
|
|
e7e949002c | ||
|
|
82d0a1dd73 | ||
|
|
af81c74193 | ||
|
|
b8301620c6 | ||
|
|
40bd9e6ddf | ||
|
|
705b0e1915 | ||
|
|
b0ebd37c2b | ||
|
|
08ed039023 | ||
|
|
8739533aad | ||
|
|
a7bdd77c8f | ||
|
|
73be39bf98 | ||
|
|
7ada0f689f | ||
|
|
6168d2b1c8 | ||
|
|
08badcba4b |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,3 +1,25 @@
|
||||
## 2.8.3 (13 Dec 2022)
|
||||
|
||||
* fix(network): remove data grid ios outline
|
||||
* chore: update luna console and luna object viewer
|
||||
|
||||
## 2.8.2 (12 Dec 2022)
|
||||
|
||||
* fix: some variables not reset when destroy
|
||||
|
||||
## 2.8.1 (12 Dec 2022)
|
||||
|
||||
* fix: remove luna syntax highlighter
|
||||
|
||||
## 2.8.0 (11 Dec 2022)
|
||||
|
||||
* feat(info): copy
|
||||
* feat(sources): use luna syntax highlighter
|
||||
* feat(network): use luna data grid
|
||||
* feat(network): copy as curl [#220](https://github.com/liriliri/eruda/issues/220)
|
||||
* fix(network): recognize JSON [#201](https://github.com/liriliri/eruda/issues/201)
|
||||
* fix: init with shadow dom style error [#195](https://github.com/liriliri/eruda/issues/195)
|
||||
|
||||
## 2.7.4 (10 Dec 2022)
|
||||
|
||||
* fix: firefox document.body is null error [#293](https://github.com/liriliri/eruda/issues/293)
|
||||
|
||||
@@ -63,11 +63,14 @@ module.exports = {
|
||||
path.resolve(__dirname, '../node_modules/luna-console'),
|
||||
path.resolve(__dirname, '../node_modules/luna-modal'),
|
||||
path.resolve(__dirname, '../node_modules/luna-tab'),
|
||||
path.resolve(__dirname, '../node_modules/luna-data-grid'),
|
||||
path.resolve(__dirname, '../node_modules/luna-object-viewer'),
|
||||
],
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
sourceType: 'unambiguous',
|
||||
presets: ['@babel/preset-env'],
|
||||
plugins: [
|
||||
'@babel/plugin-transform-runtime',
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eruda",
|
||||
"version": "2.7.4",
|
||||
"version": "2.8.3",
|
||||
"description": "Console for Mobile Browsers",
|
||||
"main": "eruda.js",
|
||||
"browserslist": [
|
||||
@@ -44,7 +44,7 @@
|
||||
"autoprefixer": "^9.7.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.5",
|
||||
"chobitsu": "^1.4.1",
|
||||
"chobitsu": "^1.4.2",
|
||||
"core-js": "^3.26.1",
|
||||
"css-loader": "^3.4.2",
|
||||
"draggabilly": "^2.2.0",
|
||||
@@ -68,12 +68,12 @@
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"licia": "^1.37.0",
|
||||
"luna-console": "^1.1.3",
|
||||
"luna-data-grid": "^0.2.1",
|
||||
"luna-console": "^1.2.0",
|
||||
"luna-data-grid": "^0.3.1",
|
||||
"luna-dom-viewer": "^1.0.2",
|
||||
"luna-modal": "^1.0.0",
|
||||
"luna-notification": "^0.1.4",
|
||||
"luna-object-viewer": "^0.2.2",
|
||||
"luna-object-viewer": "^0.2.4",
|
||||
"luna-tab": "^0.1.2",
|
||||
"node-sass": "^7.0.1",
|
||||
"postcss-clean": "^1.1.0",
|
||||
|
||||
@@ -13,28 +13,8 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.control {
|
||||
@include absolute(100%, 40px);
|
||||
cursor: default;
|
||||
font-size: 0;
|
||||
@include control();
|
||||
padding: 10px 10px 10px 35px;
|
||||
background: var(--darker-background);
|
||||
color: var(--primary);
|
||||
line-height: 20px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
.icon-clear,
|
||||
.icon-filter,
|
||||
.icon-copy {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
font-size: $font-size-l;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
transition: color $anim-duration;
|
||||
&:active {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
.icon-clear {
|
||||
padding-right: 0px;
|
||||
left: 0;
|
||||
@@ -122,7 +102,7 @@
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
transition: background $anim-duration, color $anim-duration;
|
||||
transition: background-color $anim-duration, color $anim-duration;
|
||||
&:active {
|
||||
color: var(--select-foreground);
|
||||
background: var(--highlight);
|
||||
|
||||
@@ -43,7 +43,7 @@ export default class DevTools extends Emitter {
|
||||
this._resizeStartY = 0
|
||||
this._resizeStartSize = 0
|
||||
|
||||
this._appendTpl()
|
||||
this._initTpl()
|
||||
this._initTab()
|
||||
this._initNotification()
|
||||
this._initModal()
|
||||
@@ -228,7 +228,7 @@ export default class DevTools extends Emitter {
|
||||
|
||||
this._$el.css({ height: height + '%' })
|
||||
}
|
||||
_appendTpl() {
|
||||
_initTpl() {
|
||||
const $container = this.$container
|
||||
|
||||
$container.append(
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
.breadcrumb {
|
||||
@include breadcrumb();
|
||||
cursor: pointer;
|
||||
transition: background $anim-duration, color $anim-duration;
|
||||
transition: background-color $anim-duration, color $anim-duration;
|
||||
&:active {
|
||||
background: var(--highlight);
|
||||
color: var(--select-foreground);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<ul>
|
||||
{{#each infos}}
|
||||
<li>
|
||||
<h2 {{{class 'title'}}}>{{name}}</h2>
|
||||
<div {{{class 'content'}}}>{{{val}}}</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -5,6 +5,11 @@ import isFn from 'licia/isFn'
|
||||
import isUndef from 'licia/isUndef'
|
||||
import cloneDeep from 'licia/cloneDeep'
|
||||
import evalCss from '../lib/evalCss'
|
||||
import map from 'licia/map'
|
||||
import escape from 'licia/escape'
|
||||
import copy from 'licia/copy'
|
||||
import $ from 'licia/$'
|
||||
import { classPrefix as c } from '../lib/util'
|
||||
|
||||
export default class Info extends Tool {
|
||||
constructor() {
|
||||
@@ -13,13 +18,14 @@ export default class Info extends Tool {
|
||||
this._style = evalCss(require('./Info.scss'))
|
||||
|
||||
this.name = 'info'
|
||||
this._tpl = require('./Info.hbs')
|
||||
this._infos = []
|
||||
}
|
||||
init($el) {
|
||||
init($el, container) {
|
||||
super.init($el)
|
||||
this._container = container
|
||||
|
||||
this._addDefInfo()
|
||||
this._bindEvent()
|
||||
}
|
||||
destroy() {
|
||||
super.destroy()
|
||||
@@ -88,7 +94,26 @@ export default class Info extends Tool {
|
||||
infos.push({ name, val })
|
||||
})
|
||||
|
||||
this._renderHtml(this._tpl({ infos }))
|
||||
const html = `<ul>${map(
|
||||
infos,
|
||||
(info) =>
|
||||
`<li><h2 class="${c('title')}">${escape(info.name)}<span class="${c(
|
||||
'icon-copy copy'
|
||||
)}"></span></h2><div class="${c('content')}">${info.val}</div></li>`
|
||||
).join('')}</ul>`
|
||||
|
||||
this._renderHtml(html)
|
||||
}
|
||||
_bindEvent() {
|
||||
const container = this._container
|
||||
|
||||
this._$el.on('click', c('.copy'), function () {
|
||||
const $li = $(this).parent().parent()
|
||||
const name = $li.find(c('.title')).text()
|
||||
const content = $li.find(c('.content')).text()
|
||||
copy(`${name}: ${content}`)
|
||||
container.notify('Copied')
|
||||
})
|
||||
}
|
||||
_renderHtml(html) {
|
||||
if (html === this._lastHtml) return
|
||||
|
||||
@@ -11,14 +11,26 @@
|
||||
padding: $padding;
|
||||
}
|
||||
.title {
|
||||
position: relative;
|
||||
padding-bottom: 0;
|
||||
font-size: $font-size-l;
|
||||
color: var(--accent);
|
||||
.icon-copy {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 14px;
|
||||
color: var(--primary);
|
||||
cursor: pointer;
|
||||
transition: color $anim-duration;
|
||||
&:active {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
margin: 0;
|
||||
user-select: text;
|
||||
color: var(--foreground);
|
||||
font-size: $font-size-s;
|
||||
word-break: break-all;
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
164
src/Network/Detail.js
Normal file
164
src/Network/Detail.js
Normal file
@@ -0,0 +1,164 @@
|
||||
import trim from 'licia/trim'
|
||||
import isEmpty from 'licia/isEmpty'
|
||||
import map from 'licia/map'
|
||||
import escape from 'licia/escape'
|
||||
import copy from 'licia/copy'
|
||||
import extend from 'licia/extend'
|
||||
import isJson from 'licia/isJson'
|
||||
import { classPrefix as c } from '../lib/util'
|
||||
import { curlStr } from './util'
|
||||
|
||||
export default class Detail {
|
||||
constructor($container, devtools) {
|
||||
this._$container = $container
|
||||
this._devtools = devtools
|
||||
|
||||
this._detailData = {}
|
||||
this._bindEvent()
|
||||
}
|
||||
show(data) {
|
||||
if (data.resTxt && trim(data.resTxt) === '') {
|
||||
delete data.resTxt
|
||||
}
|
||||
if (isEmpty(data.resHeaders)) {
|
||||
delete data.resHeaders
|
||||
}
|
||||
if (isEmpty(data.reqHeaders)) {
|
||||
delete data.reqHeaders
|
||||
}
|
||||
|
||||
let postData = ''
|
||||
if (data.data) {
|
||||
postData = `<pre class="${c('data')}">${escape(data.data)}</pre>`
|
||||
}
|
||||
|
||||
let reqHeaders = '<tr><td>Empty</td></tr>'
|
||||
if (data.reqHeaders) {
|
||||
reqHeaders = map(data.reqHeaders, (val, key) => {
|
||||
return `<tr>
|
||||
<td class="${c('key')}">${escape(key)}</td>
|
||||
<td>${escape(val)}</td>
|
||||
</tr>`
|
||||
}).join('')
|
||||
}
|
||||
|
||||
let resHeaders = '<tr><td>Empty</td></tr>'
|
||||
if (data.resHeaders) {
|
||||
resHeaders = map(data.resHeaders, (val, key) => {
|
||||
return `<tr>
|
||||
<td class="${c('key')}">${escape(key)}</td>
|
||||
<td>${escape(val)}</td>
|
||||
</tr>`
|
||||
}).join('')
|
||||
}
|
||||
|
||||
let resTxt = ''
|
||||
if (data.resTxt) {
|
||||
resTxt = `<pre class="${c('response')}">${escape(data.resTxt)}</pre>`
|
||||
}
|
||||
|
||||
const html = `<div class="${c('control')}">
|
||||
<span class="${c('icon-arrow-left back')}"></span>
|
||||
<span class="${c('url')}">${escape(data.url)}</span>
|
||||
<span class="${c('icon-copy copy-curl')}"></span>
|
||||
</div>
|
||||
<div class="${c('http')}">
|
||||
${postData}
|
||||
<div class="${c('section')}">
|
||||
<h2>Response Headers</h2>
|
||||
<table class="${c('headers')}">
|
||||
<tbody>
|
||||
${resHeaders}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="${c('section')}">
|
||||
<h2>Request Headers</h2>
|
||||
<table class="${c('headers')}">
|
||||
<tbody>
|
||||
${reqHeaders}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
${resTxt}
|
||||
</div>`
|
||||
|
||||
this._$container.html(html).show()
|
||||
this._detailData = data
|
||||
}
|
||||
hide() {
|
||||
this._$container.hide()
|
||||
}
|
||||
_copyCurl = () => {
|
||||
const detailData = this._detailData
|
||||
|
||||
copy(
|
||||
curlStr({
|
||||
requestMethod: detailData.method,
|
||||
url() {
|
||||
return detailData.url
|
||||
},
|
||||
requestFormData() {
|
||||
return detailData.data
|
||||
},
|
||||
requestHeaders() {
|
||||
const reqHeaders = detailData.reqHeaders || {}
|
||||
extend(reqHeaders, {
|
||||
'User-Agent': navigator.userAgent,
|
||||
Referer: location.href,
|
||||
})
|
||||
|
||||
return map(reqHeaders, (value, name) => {
|
||||
return {
|
||||
name,
|
||||
value,
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
this._devtools.notify('Copied')
|
||||
}
|
||||
_bindEvent() {
|
||||
const devtools = this._devtools
|
||||
|
||||
this._$container
|
||||
.on('click', c('.back'), () => this.hide())
|
||||
.on('click', c('.copy-curl'), this._copyCurl)
|
||||
.on('click', c('.http .response'), () => {
|
||||
const data = this._detailData
|
||||
const resTxt = data.resTxt
|
||||
|
||||
if (isJson(resTxt)) {
|
||||
return showSources('object', 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)
|
||||
}
|
||||
})
|
||||
|
||||
const showSources = (type, data) => {
|
||||
const sources = devtools.get('sources')
|
||||
if (!sources) {
|
||||
return
|
||||
}
|
||||
|
||||
sources.set(type, data)
|
||||
|
||||
devtools.showTool('sources')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<div {{{class 'title'}}}>
|
||||
Request
|
||||
<div {{{class 'btn clear-request'}}}>
|
||||
<span {{{class 'icon-clear'}}}></span>
|
||||
</div>
|
||||
</div>
|
||||
<ul {{{class 'requests'}}}></ul>
|
||||
<div {{{class 'detail'}}}></div>
|
||||
@@ -1,13 +1,15 @@
|
||||
import Tool from '../DevTools/Tool'
|
||||
import isEmpty from 'licia/isEmpty'
|
||||
import $ from 'licia/$'
|
||||
import ms from 'licia/ms'
|
||||
import trim from 'licia/trim'
|
||||
import each from 'licia/each'
|
||||
import last from 'licia/last'
|
||||
import { getFileName } from '../lib/util'
|
||||
import Detail from './Detail'
|
||||
import throttle from 'licia/throttle'
|
||||
import { getFileName, classPrefix as c } from '../lib/util'
|
||||
import evalCss from '../lib/evalCss'
|
||||
import chobitsu from '../lib/chobitsu'
|
||||
import LunaDataGrid from 'luna-data-grid'
|
||||
import ResizeSensor from 'licia/ResizeSensor'
|
||||
import { getType } from './util'
|
||||
|
||||
export default class Network extends Tool {
|
||||
constructor() {
|
||||
@@ -17,26 +19,63 @@ export default class Network extends Tool {
|
||||
|
||||
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._initTpl()
|
||||
this._detail = new Detail(this._$detail, container)
|
||||
this._requestDataGrid = new LunaDataGrid(this._$requests.get(0), {
|
||||
columns: [
|
||||
{
|
||||
id: 'name',
|
||||
title: 'Name',
|
||||
sortable: true,
|
||||
weight: 30,
|
||||
},
|
||||
{
|
||||
id: 'method',
|
||||
title: 'Method',
|
||||
sortable: true,
|
||||
weight: 14,
|
||||
},
|
||||
{
|
||||
id: 'status',
|
||||
title: 'Status',
|
||||
sortable: true,
|
||||
weight: 14,
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
title: 'Type',
|
||||
sortable: true,
|
||||
weight: 14,
|
||||
},
|
||||
{
|
||||
id: 'size',
|
||||
title: 'Size',
|
||||
sortable: true,
|
||||
weight: 14,
|
||||
},
|
||||
{
|
||||
id: 'time',
|
||||
title: 'Time',
|
||||
sortable: true,
|
||||
weight: 14,
|
||||
},
|
||||
],
|
||||
})
|
||||
this._resizeSensor = new ResizeSensor($el.get(0))
|
||||
this._bindEvent()
|
||||
this._appendTpl()
|
||||
}
|
||||
show() {
|
||||
super.show()
|
||||
|
||||
this._render()
|
||||
this._updateDataGridHeight()
|
||||
}
|
||||
clear() {
|
||||
this._requests = {}
|
||||
this._render()
|
||||
this._requestDataGrid.clear()
|
||||
}
|
||||
requests() {
|
||||
const ret = []
|
||||
@@ -45,8 +84,13 @@ export default class Network extends Tool {
|
||||
})
|
||||
return ret
|
||||
}
|
||||
_updateDataGridHeight() {
|
||||
const height = this._$el.offset().height - 41
|
||||
this._requestDataGrid.setOption('minHeight', height)
|
||||
this._requestDataGrid.setOption('maxHeight', height)
|
||||
}
|
||||
_reqWillBeSent = (params) => {
|
||||
this._requests[params.requestId] = {
|
||||
const request = {
|
||||
name: getFileName(params.request.url),
|
||||
url: params.request.url,
|
||||
status: 'pending',
|
||||
@@ -62,106 +106,103 @@ export default class Network extends Tool {
|
||||
reqHeaders: params.request.headers || {},
|
||||
resHeaders: {},
|
||||
}
|
||||
let node
|
||||
request.render = () => {
|
||||
const data = {
|
||||
name: request.name,
|
||||
method: request.method,
|
||||
status: request.status,
|
||||
type: request.subType,
|
||||
size: request.size,
|
||||
time: request.displayTime,
|
||||
}
|
||||
if (node) {
|
||||
node.data = data
|
||||
node.render()
|
||||
} else {
|
||||
node = this._requestDataGrid.append(data, { selectable: true })
|
||||
$(node.container).data('id', params.requestId)
|
||||
}
|
||||
if (request.hasErr) {
|
||||
$(node.container).addClass(c('request-error'))
|
||||
}
|
||||
}
|
||||
request.render()
|
||||
this._requests[params.requestId] = request
|
||||
}
|
||||
_resReceivedExtraInfo = (params) => {
|
||||
const target = this._requests[params.requestId]
|
||||
if (!target) {
|
||||
const request = this._requests[params.requestId]
|
||||
if (!request) {
|
||||
return
|
||||
}
|
||||
|
||||
target.resHeaders = params.headers
|
||||
request.resHeaders = params.headers
|
||||
|
||||
this._updateType(target)
|
||||
this._render()
|
||||
this._updateType(request)
|
||||
request.render()
|
||||
}
|
||||
_updateType(target) {
|
||||
const contentType = target.resHeaders['content-type'] || ''
|
||||
_updateType(request) {
|
||||
const contentType = request.resHeaders['content-type'] || ''
|
||||
const { type, subType } = getType(contentType)
|
||||
target.type = type
|
||||
target.subType = subType
|
||||
request.type = type
|
||||
request.subType = subType
|
||||
}
|
||||
_resReceived = (params) => {
|
||||
const target = this._requests[params.requestId]
|
||||
if (!target) {
|
||||
const request = this._requests[params.requestId]
|
||||
if (!request) {
|
||||
return
|
||||
}
|
||||
|
||||
const { response } = params
|
||||
const { status, headers } = response
|
||||
target.status = status
|
||||
request.status = status
|
||||
if (status < 200 || status >= 300) {
|
||||
target.hasErr = true
|
||||
request.hasErr = true
|
||||
}
|
||||
if (headers) {
|
||||
target.resHeaders = headers
|
||||
this._updateType(target)
|
||||
request.resHeaders = headers
|
||||
this._updateType(request)
|
||||
}
|
||||
|
||||
this._render()
|
||||
request.render()
|
||||
}
|
||||
_loadingFinished = (params) => {
|
||||
const target = this._requests[params.requestId]
|
||||
if (!target) {
|
||||
const request = this._requests[params.requestId]
|
||||
if (!request) {
|
||||
return
|
||||
}
|
||||
|
||||
const time = params.timestamp * 1000
|
||||
target.time = time - target.startTime
|
||||
target.displayTime = ms(target.time)
|
||||
request.time = time - request.startTime
|
||||
request.displayTime = ms(request.time)
|
||||
|
||||
target.size = params.encodedDataLength
|
||||
target.done = true
|
||||
target.resTxt = chobitsu.domain('Network').getResponseBody({
|
||||
request.size = params.encodedDataLength
|
||||
request.done = true
|
||||
request.resTxt = chobitsu.domain('Network').getResponseBody({
|
||||
requestId: params.requestId,
|
||||
}).body
|
||||
|
||||
this._render()
|
||||
request.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]
|
||||
$el.on('click', c('.clear-request'), () => this.clear())
|
||||
|
||||
if (!data.done) return
|
||||
this._requestDataGrid.on('select', (node) => {
|
||||
const id = $(node.container).data('id')
|
||||
const request = self._requests[id]
|
||||
if (!request.done) {
|
||||
return
|
||||
}
|
||||
self._detail.show(request)
|
||||
})
|
||||
|
||||
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')
|
||||
}
|
||||
this._resizeSensor.addListener(
|
||||
throttle(() => this._updateDataGridHeight(), 15)
|
||||
)
|
||||
|
||||
chobitsu.domain('Network').enable()
|
||||
|
||||
@@ -174,6 +215,7 @@ export default class Network extends Tool {
|
||||
destroy() {
|
||||
super.destroy()
|
||||
|
||||
this._resizeSensor.destroy()
|
||||
evalCss.remove(this._style)
|
||||
|
||||
const network = chobitsu.domain('Network')
|
||||
@@ -182,51 +224,19 @@ export default class Network extends Tool {
|
||||
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() {
|
||||
_initTpl() {
|
||||
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),
|
||||
$el.html(
|
||||
c(`<div class="title">
|
||||
Request
|
||||
<div class="btn clear-request">
|
||||
<span class="icon-clear"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="requests"></div>
|
||||
<div class="detail"></div>`)
|
||||
)
|
||||
this._$detail = $el.find(c('.detail'))
|
||||
this._$requests = $el.find(c('.requests'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,79 +2,56 @@
|
||||
@import '../style/mixin';
|
||||
|
||||
#network {
|
||||
padding-top: 36px;
|
||||
padding-top: 40px;
|
||||
.title {
|
||||
@include absolute(100%, 36px);
|
||||
@include absolute(100%, 40px);
|
||||
@include right-btn();
|
||||
background: var(--darker-background);
|
||||
padding: $padding;
|
||||
color: var(--primary);
|
||||
height: 36px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
height: 40px;
|
||||
}
|
||||
.requests {
|
||||
@include overflow-auto(y);
|
||||
height: 100%;
|
||||
border-bottom: 1px solid var(--border);
|
||||
margin-bottom: 10px;
|
||||
li {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid var(--border);
|
||||
height: 41px;
|
||||
color: var(--foreground);
|
||||
white-space: nowrap;
|
||||
&.error {
|
||||
span {
|
||||
color: var(--console-error-foreground);
|
||||
}
|
||||
}
|
||||
span {
|
||||
display: block;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
padding: 0 5px;
|
||||
font-size: $font-size-s;
|
||||
vertical-align: top;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.name {
|
||||
flex: 1;
|
||||
padding-left: $padding;
|
||||
}
|
||||
.status {
|
||||
width: 40px;
|
||||
}
|
||||
.method,
|
||||
.type {
|
||||
width: 50px;
|
||||
}
|
||||
.size {
|
||||
width: 70px;
|
||||
}
|
||||
.time {
|
||||
width: 60px;
|
||||
padding-right: $padding;
|
||||
}
|
||||
&:nth-child(even) {
|
||||
background: var(--contrast);
|
||||
.request-error {
|
||||
color: var(--console-error-foreground);
|
||||
}
|
||||
.luna-data-grid:focus {
|
||||
.luna-data-grid-data-container {
|
||||
.request-error.luna-data-grid-selected {
|
||||
background: var(--console-error-background);
|
||||
}
|
||||
}
|
||||
}
|
||||
.luna-data-grid {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
.detail {
|
||||
@include absolute();
|
||||
z-index: 10;
|
||||
display: none;
|
||||
padding-bottom: 40px;
|
||||
padding-top: 40px;
|
||||
background: var(--background);
|
||||
.control {
|
||||
@include control();
|
||||
padding: 10px 35px;
|
||||
.url {
|
||||
font-size: $font-size-s;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
.icon-arrow-left {
|
||||
left: 0;
|
||||
}
|
||||
.icon-copy {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
.http {
|
||||
@include overflow-auto(y);
|
||||
height: 100%;
|
||||
.breadcrumb {
|
||||
@include breadcrumb();
|
||||
}
|
||||
.section {
|
||||
border-top: 1px solid var(--border);
|
||||
border-bottom: 1px solid var(--border);
|
||||
@@ -84,6 +61,7 @@
|
||||
padding: $padding;
|
||||
font-size: $font-size;
|
||||
}
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
table {
|
||||
color: var(--foreground);
|
||||
@@ -108,32 +86,12 @@
|
||||
@include overflow-auto(x);
|
||||
padding: $padding;
|
||||
font-size: $font-size-s;
|
||||
margin-bottom: 10px;
|
||||
margin: 10px 0;
|
||||
white-space: pre-wrap;
|
||||
border-top: 1px solid var(--border);
|
||||
color: var(--foreground);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
}
|
||||
.back {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
color: var(--foreground);
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--darker-background);
|
||||
display: block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
transition: background 0.3s;
|
||||
cursor: pointer;
|
||||
&:active {
|
||||
color: var(--select-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<div {{{class 'http'}}}>
|
||||
<div {{{class 'breadcrumb'}}}>{{url}}</div>
|
||||
{{#if data}}
|
||||
<pre {{{class 'data'}}}>{{data}}</pre>
|
||||
{{/if}}
|
||||
<div {{{class 'section'}}}>
|
||||
<h2>Request Headers</h2>
|
||||
<table {{{class 'headers'}}}>
|
||||
<tbody>
|
||||
{{#if reqHeaders}}
|
||||
{{#each reqHeaders}}
|
||||
<tr>
|
||||
<td {{{class 'key'}}}>{{@key}}</td>
|
||||
<td>{{.}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr>
|
||||
<td>Empty</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Response Headers</h2>
|
||||
<table {{{class 'headers'}}}>
|
||||
<tbody>
|
||||
{{#if resHeaders}}
|
||||
{{#each resHeaders}}
|
||||
<tr>
|
||||
<td {{{class 'key'}}}>{{@key}}</td>
|
||||
<td>{{.}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr>
|
||||
<td>Empty</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{#if resTxt}}
|
||||
<pre {{{class 'response'}}}>{{resTxt}}</pre>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div {{{class 'back'}}}>Back to the List</div>
|
||||
@@ -1,14 +0,0 @@
|
||||
{{#if requests}}
|
||||
{{#each requests}}
|
||||
<li class="eruda-request {{#if hasErr}}eruda-error{{/if}}" data-id="{{@key}}">
|
||||
<span {{{class 'name'}}}>{{name}}</span>
|
||||
<span {{{class 'status'}}}>{{status}}</span>
|
||||
<span {{{class 'method'}}}>{{method}}</span>
|
||||
<span {{{class 'type'}}}>{{subType}}</span>
|
||||
<span {{{class 'size'}}}>{{size}}</span>
|
||||
<span {{{class 'time'}}}>{{displayTime}}</span>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<li><span {{{class 'name'}}}>Empty</span></li>
|
||||
{{/if}}
|
||||
107
src/Network/util.js
Normal file
107
src/Network/util.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import last from 'licia/last'
|
||||
import detectOs from 'licia/detectOs'
|
||||
import arrToMap from 'licia/arrToMap'
|
||||
|
||||
export function getType(contentType) {
|
||||
if (!contentType) return 'unknown'
|
||||
|
||||
const type = contentType.split(';')[0].split('/')
|
||||
|
||||
return {
|
||||
type: type[0],
|
||||
subType: last(type),
|
||||
}
|
||||
}
|
||||
|
||||
export function curlStr(request) {
|
||||
let platform = detectOs()
|
||||
if (platform === 'windows') {
|
||||
platform = 'win'
|
||||
}
|
||||
/* eslint-disable */
|
||||
let command = []
|
||||
const ignoredHeaders = arrToMap([
|
||||
'accept-encoding',
|
||||
'host',
|
||||
'method',
|
||||
'path',
|
||||
'scheme',
|
||||
'version',
|
||||
])
|
||||
|
||||
function escapeStringWin(str) {
|
||||
const encapsChars = /[\r\n]/.test(str) ? '^"' : '"'
|
||||
return (
|
||||
encapsChars +
|
||||
str
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/[^a-zA-Z0-9\s_\-:=+~'\/.',?;()*`&]/g, '^$&')
|
||||
.replace(/%(?=[a-zA-Z0-9_])/g, '%^')
|
||||
.replace(/\r?\n/g, '^\n\n') +
|
||||
encapsChars
|
||||
)
|
||||
}
|
||||
|
||||
function escapeStringPosix(str) {
|
||||
function escapeCharacter(x) {
|
||||
const code = x.charCodeAt(0)
|
||||
let hexString = code.toString(16)
|
||||
while (hexString.length < 4) {
|
||||
hexString = '0' + hexString
|
||||
}
|
||||
|
||||
return '\\u' + hexString
|
||||
}
|
||||
|
||||
if (/[\0-\x1F\x7F-\x9F!]|\'/.test(str)) {
|
||||
return (
|
||||
"$'" +
|
||||
str
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/\'/g, "\\'")
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/[\0-\x1F\x7F-\x9F!]/g, escapeCharacter) +
|
||||
"'"
|
||||
)
|
||||
}
|
||||
return "'" + str + "'"
|
||||
}
|
||||
|
||||
const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix
|
||||
|
||||
command.push(escapeString(request.url()).replace(/[[{}\]]/g, '\\$&'))
|
||||
|
||||
let inferredMethod = 'GET'
|
||||
const data = []
|
||||
const formData = request.requestFormData()
|
||||
if (formData) {
|
||||
data.push('--data-raw ' + escapeString(formData))
|
||||
ignoredHeaders['content-length'] = true
|
||||
inferredMethod = 'POST'
|
||||
}
|
||||
|
||||
if (request.requestMethod !== inferredMethod) {
|
||||
command.push('-X ' + escapeString(request.requestMethod))
|
||||
}
|
||||
|
||||
const requestHeaders = request.requestHeaders()
|
||||
for (let i = 0; i < requestHeaders.length; i++) {
|
||||
const header = requestHeaders[i]
|
||||
const name = header.name.replace(/^:/, '')
|
||||
if (ignoredHeaders[name.toLowerCase()]) {
|
||||
continue
|
||||
}
|
||||
command.push('-H ' + escapeString(name + ': ' + header.value))
|
||||
}
|
||||
command = command.concat(data)
|
||||
command.push('--compressed')
|
||||
|
||||
return (
|
||||
'curl ' +
|
||||
command.join(
|
||||
command.length >= 3 ? (platform === 'win' ? ' ^\n ' : ' \\\n ') : ' '
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{{#each snippets}}
|
||||
<div class="eruda-section eruda-run" data-idx="{{@index}}">
|
||||
<h2 class="eruda-name">{{name}}
|
||||
<div class="eruda-btn">
|
||||
<span class="eruda-icon-play"></span>
|
||||
</div>
|
||||
</h2>
|
||||
<div class="eruda-description">
|
||||
{{desc}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
@@ -2,7 +2,10 @@ import Tool from '../DevTools/Tool'
|
||||
import defSnippets from './defSnippets'
|
||||
import $ from 'licia/$'
|
||||
import each from 'licia/each'
|
||||
import escape from 'licia/escape'
|
||||
import map from 'licia/map'
|
||||
import evalCss from '../lib/evalCss'
|
||||
import { classPrefix as c } from '../lib/util'
|
||||
|
||||
export default class Snippets extends Tool {
|
||||
constructor() {
|
||||
@@ -13,7 +16,6 @@ export default class Snippets extends Tool {
|
||||
this.name = 'snippets'
|
||||
|
||||
this._snippets = []
|
||||
this._tpl = require('./Snippets.hbs')
|
||||
}
|
||||
init($el) {
|
||||
super.init($el)
|
||||
@@ -77,11 +79,20 @@ export default class Snippets extends Tool {
|
||||
})
|
||||
}
|
||||
_render() {
|
||||
this._renderHtml(
|
||||
this._tpl({
|
||||
snippets: this._snippets,
|
||||
})
|
||||
)
|
||||
const html = map(this._snippets, (snippet, idx) => {
|
||||
return `<div class="${c('section run')}" data-idx="${idx}">
|
||||
<h2 class="${c('name')}">${escape(snippet.name)}
|
||||
<div class="${c('btn')}">
|
||||
<span class="${c('icon-play')}"></span>
|
||||
</div>
|
||||
</h2>
|
||||
<div class="${c('description')}">
|
||||
${escape(snippet.desc)}
|
||||
</div>
|
||||
</div>`
|
||||
}).join('')
|
||||
|
||||
this._renderHtml(html)
|
||||
}
|
||||
_renderHtml(html) {
|
||||
if (html === this._lastHtml) return
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
padding: $padding;
|
||||
color: var(--primary);
|
||||
background: var(--darker-background);
|
||||
transition: background $anim-duration;
|
||||
transition: background-color $anim-duration;
|
||||
.btn {
|
||||
margin-left: 10px;
|
||||
float: right;
|
||||
@@ -31,6 +31,7 @@
|
||||
}
|
||||
}
|
||||
.description {
|
||||
font-size: $font-size-s;
|
||||
color: var(--foreground);
|
||||
padding: $padding;
|
||||
transition: background $anim-duration;
|
||||
|
||||
@@ -2,11 +2,13 @@ import Tool from '../DevTools/Tool'
|
||||
import LunaObjectViewer from 'luna-object-viewer'
|
||||
import Settings from '../Settings/Settings'
|
||||
import ajax from 'licia/ajax'
|
||||
import isStr from 'licia/isStr'
|
||||
import escape from 'licia/escape'
|
||||
import trim from 'licia/trim'
|
||||
import isStr from 'licia/isStr'
|
||||
import map from 'licia/map'
|
||||
import highlight from 'licia/highlight'
|
||||
import evalCss from '../lib/evalCss'
|
||||
import { classPrefix as c } from '../lib/util'
|
||||
|
||||
export default class Sources extends Tool {
|
||||
constructor() {
|
||||
@@ -16,8 +18,6 @@ export default class Sources extends Tool {
|
||||
|
||||
this.name = 'sources'
|
||||
this._showLineNum = true
|
||||
|
||||
this._loadTpl()
|
||||
}
|
||||
init($el, container) {
|
||||
super.init($el)
|
||||
@@ -108,13 +108,6 @@ export default class Sources extends Tool {
|
||||
}
|
||||
})
|
||||
}
|
||||
_loadTpl() {
|
||||
this._codeTpl = require('./code.hbs')
|
||||
this._imgTpl = require('./image.hbs')
|
||||
this._objTpl = require('./object.hbs')
|
||||
this._rawTpl = require('./raw.hbs')
|
||||
this._iframeTpl = require('./iframe.hbs')
|
||||
}
|
||||
_rmCfg() {
|
||||
const cfg = this.config
|
||||
|
||||
@@ -166,7 +159,15 @@ export default class Sources extends Tool {
|
||||
}
|
||||
}
|
||||
_renderImg() {
|
||||
this._renderHtml(this._imgTpl(this._data.val))
|
||||
const { width, height, src } = this._data.val
|
||||
|
||||
this._renderHtml(`<div class="${c('image')}">
|
||||
<div class="${c('breadcrumb')}">${escape(src)}</div>
|
||||
<div class="${c('img-container')}" data-exclude="true">
|
||||
<img src="${escape(src)}">
|
||||
</div>
|
||||
<div class="${c('img-info')}">${escape(width)} × ${escape(height)}</div>
|
||||
</div>`)
|
||||
}
|
||||
_renderCode() {
|
||||
const data = this._data
|
||||
@@ -188,7 +189,9 @@ export default class Sources extends Tool {
|
||||
code = escape(code)
|
||||
}
|
||||
|
||||
if (len < MAX_LINE_NUM_LEN && this._showLineNum) {
|
||||
const showLineNum = len < MAX_LINE_NUM_LEN && this._showLineNum
|
||||
|
||||
if (showLineNum) {
|
||||
code = code.split('\n').map((line, idx) => {
|
||||
if (trim(line) === '') line = ' '
|
||||
|
||||
@@ -199,16 +202,35 @@ export default class Sources extends Tool {
|
||||
})
|
||||
}
|
||||
|
||||
this._renderHtml(
|
||||
this._codeTpl({
|
||||
code,
|
||||
showLineNum: len < MAX_LINE_NUM_LEN && this._showLineNum,
|
||||
})
|
||||
)
|
||||
let html
|
||||
if (showLineNum) {
|
||||
const lineNum = map(code, ({ idx }) => {
|
||||
return `<div class="${c('line-num')}">${idx}</div>`
|
||||
}).join('')
|
||||
const codeLine = map(code, ({ val }) => {
|
||||
return `<pre class="${c('code-line')}">${val}</pre>`
|
||||
}).join('')
|
||||
html = `<div class="${c('code-wrapper')}">
|
||||
<table class="${c('code')}">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="${c('gutter')}">${lineNum}</td>
|
||||
<td class="${c('content')}">${codeLine}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`
|
||||
} else {
|
||||
html = `<div class="${c('code-wrapper')}">
|
||||
<pre class="${c('code')}">${code}</pre>
|
||||
</div>`
|
||||
}
|
||||
|
||||
this._renderHtml(html)
|
||||
}
|
||||
_renderObj() {
|
||||
// Using cache will keep binding events to the same elements.
|
||||
this._renderHtml(this._objTpl(), false)
|
||||
this._renderHtml(`<ul class="${c('json')}"></ul>`, false)
|
||||
|
||||
let val = this._data.val
|
||||
|
||||
@@ -229,10 +251,12 @@ export default class Sources extends Tool {
|
||||
objViewer.set(val)
|
||||
}
|
||||
_renderRaw() {
|
||||
this._renderHtml(this._rawTpl({ val: this._data.val }))
|
||||
this._renderHtml(`<div class="${c('raw-wrapper')}">
|
||||
<div class="${c('raw')}">${escape(this._data.val)}</div>
|
||||
</div>`)
|
||||
}
|
||||
_renderIframe() {
|
||||
this._renderHtml(this._iframeTpl({ src: this._data.val }))
|
||||
this._renderHtml(`<iframe src="${escape(this._data.val)}"></iframe>`)
|
||||
}
|
||||
_renderHtml(html, cache = true) {
|
||||
if (cache && html === this._lastHtml) return
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@import '../style/mixin';
|
||||
|
||||
#sources {
|
||||
font-size: 0;
|
||||
@include overflow-auto(y);
|
||||
color: var(--foreground);
|
||||
.code-wrapper,
|
||||
@@ -11,6 +12,7 @@
|
||||
min-height: 100%;
|
||||
}
|
||||
.raw {
|
||||
font-size: $font-size-s;
|
||||
user-select: text;
|
||||
padding: $padding;
|
||||
}
|
||||
@@ -40,6 +42,7 @@
|
||||
}
|
||||
}
|
||||
.image {
|
||||
font-size: $font-size-s;
|
||||
.breadcrumb {
|
||||
@include breadcrumb();
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{{#if showLineNum}}
|
||||
<div {{{class 'code-wrapper'}}}>
|
||||
<table {{{class 'code'}}}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td {{{class 'gutter'}}}>
|
||||
{{#each code}}
|
||||
<div {{{class 'line-num'}}}>{{idx}}</div>
|
||||
{{/each}}
|
||||
</td>
|
||||
<td {{{class 'content'}}}>
|
||||
{{#each code}}
|
||||
<pre {{{class 'code-line'}}}>{{{val}}}</pre>
|
||||
{{/each}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<div {{{class 'code-wrapper'}}}>
|
||||
<pre {{{class 'code'}}}>{{{code}}}</pre>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1 +0,0 @@
|
||||
<iframe src="{{{src}}}"></iframe>
|
||||
@@ -1,7 +0,0 @@
|
||||
<div {{{class 'image'}}}>
|
||||
<div {{{class 'breadcrumb'}}}>{{src}}</div>
|
||||
<div {{{class 'img-container'}}} data-exclude="true">
|
||||
<img src="{{src}}">
|
||||
</div>
|
||||
<div {{{class 'img-info'}}}>{{width}} × {{height}}</div>
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
<ul {{{class 'json'}}}></ul>
|
||||
@@ -1,3 +0,0 @@
|
||||
<div {{{class 'raw-wrapper'}}}>
|
||||
<div {{{class 'raw'}}}>{{val}}</div>
|
||||
</div>
|
||||
32
src/eruda.js
32
src/eruda.js
@@ -103,9 +103,11 @@ export default {
|
||||
this._entryBtn.destroy()
|
||||
delete this._entryBtn
|
||||
this._unregisterListener()
|
||||
this._$el.remove()
|
||||
$(this._container).remove()
|
||||
evalCss.clear()
|
||||
this._isInit = false
|
||||
this._container = null
|
||||
this._shadowRoot = null
|
||||
},
|
||||
scale(s) {
|
||||
if (isNum(s)) {
|
||||
@@ -148,19 +150,23 @@ export default {
|
||||
if (!this._isInit) logger.error('Please call "eruda.init()" first')
|
||||
return this._isInit
|
||||
},
|
||||
_initContainer(el, useShadowDom) {
|
||||
if (!el) {
|
||||
el = document.createElement('div')
|
||||
document.documentElement.appendChild(el)
|
||||
el.style.all = 'initial'
|
||||
_initContainer(container, useShadowDom) {
|
||||
if (!container) {
|
||||
container = document.createElement('div')
|
||||
document.documentElement.appendChild(container)
|
||||
}
|
||||
|
||||
container.id = 'eruda'
|
||||
container.style.all = 'initial'
|
||||
this._container = container
|
||||
|
||||
let shadowRoot
|
||||
let el
|
||||
if (useShadowDom) {
|
||||
if (el.attachShadow) {
|
||||
shadowRoot = el.attachShadow({ mode: 'open' })
|
||||
} else if (el.createShadowRoot) {
|
||||
shadowRoot = el.createShadowRoot()
|
||||
if (container.attachShadow) {
|
||||
shadowRoot = container.attachShadow({ mode: 'open' })
|
||||
} else if (container.createShadowRoot) {
|
||||
shadowRoot = container.createShadowRoot()
|
||||
}
|
||||
if (shadowRoot) {
|
||||
// font-face doesn't work inside shadow dom.
|
||||
@@ -174,8 +180,12 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._shadowRoot) {
|
||||
el = document.createElement('div')
|
||||
container.appendChild(el)
|
||||
}
|
||||
|
||||
extend(el, {
|
||||
id: 'eruda',
|
||||
className: 'eruda-container',
|
||||
contentEditable: false
|
||||
})
|
||||
|
||||
@@ -190,8 +190,6 @@ export function safeStorage(type, memReplacement) {
|
||||
export function getFileName(url) {
|
||||
let ret = last(url.split('/'))
|
||||
|
||||
if (ret.indexOf('?') > -1) ret = trim(ret.split('?')[0])
|
||||
|
||||
if (ret === '') {
|
||||
url = new Url(url)
|
||||
ret = url.hostname
|
||||
|
||||
@@ -94,6 +94,22 @@
|
||||
.luna-console-code {
|
||||
@include luna-console-highlight();
|
||||
}
|
||||
.luna-console-log-content {
|
||||
.luna-console-undefined,
|
||||
.luna-console-null {
|
||||
color: var(--operator-color);
|
||||
}
|
||||
.luna-console-number {
|
||||
color: var(--number-color);
|
||||
}
|
||||
.luna-console-boolean {
|
||||
color: var(--keyword-color);
|
||||
}
|
||||
.luna-console-symbol,
|
||||
.luna-console-regexp {
|
||||
color: var(--var-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.luna-console-preview {
|
||||
@@ -132,12 +148,6 @@
|
||||
border-top-color: transparent;
|
||||
border-left-color: var(--foreground);
|
||||
}
|
||||
.luna-object-viewer-icon-caret-right {
|
||||
top: 0;
|
||||
}
|
||||
.luna-object-viewer-icon-caret-down {
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.luna-notification {
|
||||
pointer-events: none !important;
|
||||
@@ -166,6 +176,13 @@
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
border-color: var(--border);
|
||||
&:focus {
|
||||
.luna-data-grid-data-container {
|
||||
.luna-data-grid-node.luna-data-grid-selected {
|
||||
background: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
th,
|
||||
td {
|
||||
border-color: var(--border);
|
||||
@@ -173,12 +190,17 @@
|
||||
th {
|
||||
background: var(--darker-background);
|
||||
&.luna-data-grid-sortable {
|
||||
&:hover {
|
||||
background: var(--darker-background);
|
||||
&:hover,
|
||||
&:active {
|
||||
color: var(--select-foreground);
|
||||
background: var(--highlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
.luna-data-grid-data-container {
|
||||
.luna-data-grid-node.luna-data-grid-selected {
|
||||
background: var(--highlight);
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background: var(--contrast);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,29 @@
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
@mixin control {
|
||||
@include absolute(100%, 40px);
|
||||
cursor: default;
|
||||
font-size: 0;
|
||||
background: var(--darker-background);
|
||||
color: var(--primary);
|
||||
line-height: 20px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
[class^='icon-'],
|
||||
[class*=' icon-'] {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
font-size: $font-size-l;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
transition: color $anim-duration;
|
||||
&:active {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin clear-float {
|
||||
&:after {
|
||||
content: '';
|
||||
|
||||
@@ -36,6 +36,13 @@
|
||||
h4 {
|
||||
margin: 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: $font-size;
|
||||
[class^='icon-'],
|
||||
[class*=' icon-'] {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@@ -69,10 +76,3 @@
|
||||
.string-color {
|
||||
color: var(--string-color);
|
||||
}
|
||||
|
||||
h2 {
|
||||
[class^='icon-'],
|
||||
[class*=' icon-'] {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,11 @@
|
||||
addClickEvent('log', function () {
|
||||
console.clear()
|
||||
console.log('log')
|
||||
console.log('number:', 5)
|
||||
console.log('boolean:', true, false)
|
||||
console.log('null:', null)
|
||||
console.log('undefined:', undefined)
|
||||
console.log('regexp:', /test/gi)
|
||||
for (var i = 0; i < 10; i++) {
|
||||
console.log('repeat log')
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('network', function () {
|
||||
it('xhr', function (done) {
|
||||
$('.eruda-clear-xhr').click()
|
||||
util.ajax.get(window.location.toString(), function () {
|
||||
expect($('.eruda-requests li')).toHaveLength(1)
|
||||
expect($('.eruda-requests .luna-data-grid-node')).toHaveLength(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,10 +6,8 @@ describe('sources', function () {
|
||||
eruda.show('sources')
|
||||
})
|
||||
|
||||
describe('js', function () {
|
||||
it('highlight', function () {
|
||||
tool.set('js', '/* test */')
|
||||
expect($tool.find('.eruda-content')).toContainHtml('/* test */')
|
||||
})
|
||||
it('raw', function () {
|
||||
tool.set('raw', '/* test */')
|
||||
expect($tool.find('.eruda-raw')).toContainHtml('/* test */')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user