1
0
mirror of synced 2025-12-11 00:48:21 +08:00

Compare commits

...

8 Commits

Author SHA1 Message Date
surunzi
8a70008710 release: v1.8.0 2019-10-13 20:42:57 +08:00
surunzi
376404e235 chore: small changes 2019-10-13 20:35:14 +08:00
surunzi
8babafb6d1 feat(network): display optimization 2019-10-13 20:26:24 +08:00
surunzi
e5b8c55df7 chore: small changes 2019-10-13 16:32:01 +08:00
surunzi
0ae4b9fa66 feat: move http view from sources to network 2019-10-13 16:10:31 +08:00
surunzi
7d9445a59f fix(console): group object expansion 2019-10-13 13:33:26 +08:00
surunzi
d3476779e6 docs: update screenshot 2019-10-12 12:01:13 +08:00
surunzi
bf08ec381a docs: plugin 2019-10-12 11:37:17 +08:00
19 changed files with 1079 additions and 899 deletions

View File

@@ -1,6 +1,9 @@
{ {
"cSpell.words": [ "cSpell.words": [
"Eruda",
"callout", "callout",
"eval",
"licia",
"unenumerable" "unenumerable"
] ]
} }

View File

@@ -1,3 +1,9 @@
## v1.8.0 (13 Oct 2019)
* feat(network): display optimization
* feat: move http view from sources to network
* fix(console): group object expansion
## v1.7.2 (11 Oct 2019) ## v1.7.2 (11 Oct 2019)
* fix(console): blank bottom if js input is disabled * fix(console): blank bottom if js input is disabled

View File

@@ -26,10 +26,6 @@ Console for Mobile Browsers.
![Eruda](./doc/screenshot.jpg) ![Eruda](./doc/screenshot.jpg)
## Why
Logging things out on mobile browser is never an easy stuff. I used to include `window onerror alert` script inside pages to find out JavaScript errors, kind of stupid and inefficient. Desktop browser DevTools is great, and I wish there is a similar one on mobile side, which leads to the creation of Eruda.
## Demo ## Demo
![Demo](./doc/qrcode.png) ![Demo](./doc/qrcode.png)
@@ -107,8 +103,6 @@ eruda.init({
## Plugins ## Plugins
It is possible to enhance Eruda with more features by writing plugins. Check source code of plugins below to learn how to write your own custom tool panels. Besides, [eruda-plugin](https://github.com/liriliri/eruda-plugin) is available for plugin initialization.
* [eruda-fps](https://github.com/liriliri/eruda-fps): Display page fps info. * [eruda-fps](https://github.com/liriliri/eruda-fps): Display page fps info.
* [eruda-features](https://github.com/liriliri/eruda-features): Browser feature detections. * [eruda-features](https://github.com/liriliri/eruda-features): Browser feature detections.
* [eruda-timing](https://github.com/liriliri/eruda-timing): Show performance and resource timing. * [eruda-timing](https://github.com/liriliri/eruda-timing): Show performance and resource timing.
@@ -119,7 +113,7 @@ It is possible to enhance Eruda with more features by writing plugins. Check sou
* [eruda-dom](https://github.com/liriliri/eruda-dom): Navigate dom tree. * [eruda-dom](https://github.com/liriliri/eruda-dom): Navigate dom tree.
* [eruda-orientation](https://github.com/liriliri/eruda-orientation): Test orientation api. * [eruda-orientation](https://github.com/liriliri/eruda-orientation): Test orientation api.
When writing plugins, you can use utilities exposed by Eruda, see [docs](doc/UTIL_API.md) here. If you want to create a plugin yourself, follow the guides [here](./doc/PLUGIN.md).
## Related Projects ## Related Projects

79
doc/PLUGIN.md Normal file
View File

@@ -0,0 +1,79 @@
# Writing a Plugin
It is possible to enhance Eruda with more features by writing plugins, which means, creating your own custom panels.
## Creating a Plugin
Adding plugins is super easy for eruda. All you have to do is passing an object with a few methods implemented.
```javascript
eruda.add({
name: 'test',
init($el) {
$el.html('Hello, this is my first eruda plugin!');
this._$el = $el;
},
show() {
this._$el.show();
},
hide() {
this._$el.hide();
},
destroy() {}
});
```
## Basic Structure
### name
Every plugin must have a unique name, which will be shown as the tab name on the top.
### init
Called when plugin is added, and a document element used to display content is passed in.
The element is wrapped as a jQuery like object, provided by the [licia](https://licia.liriliri.io/docs.html) utility library.
### show
Called when switch to the panel. Usually all you need to do is to show the container element.
### hide
Called when switch to other panel. You should at least hide the container element here.
### destroy
Called when plugin is removed using `eruda.remove('plugin name')`.
## Worth Mentioning
Apart from passing an object, you can also pass in a function that returns an object. Eruda will automatically invoke the function and use the object it returns.
When writing plugins, you can use utilities exposed by Eruda, see [docs](./UTIL_API.md) here.
```javascript
eruda.add(function (eruda) {
// eruda.Tool implements those four methods.
class Test extends eruda.Tool {
constructor() {
super()
this.name = 'test';
this.style = eruda.util.evalCss('.eruda-test { background: #000; }');
}
init($el) {
super.init($el);
}
destroy() {
super.destroy();
eruda.util.evalCss.remove(this.style);
}
}
return new Test();
});
```
There is also a tool for plugin initialization, check it out [here](https://github.com/liriliri/eruda-plugin).

View File

@@ -104,8 +104,6 @@ eruda.init({
## 插件 ## 插件
你可以为 Eruda 编写插件来增强功能。关于怎么编写插件,请查看下边官方插件的源码。另外 [eruda-plugin](https://github.com/liriliri/eruda-plugin) 可以用来初始化一个新插件。
* [eruda-fps](https://github.com/liriliri/eruda-fps):展示页面的 fps 信息。 * [eruda-fps](https://github.com/liriliri/eruda-fps):展示页面的 fps 信息。
* [eruda-features](https://github.com/liriliri/eruda-features):浏览器特性检测。 * [eruda-features](https://github.com/liriliri/eruda-features):浏览器特性检测。
* [eruda-timing](https://github.com/liriliri/eruda-timing):展示性能资源数据。 * [eruda-timing](https://github.com/liriliri/eruda-timing):展示性能资源数据。
@@ -116,7 +114,7 @@ eruda.init({
* [eruda-dom](https://github.com/liriliri/eruda-dom):浏览 dom 树。 * [eruda-dom](https://github.com/liriliri/eruda-dom):浏览 dom 树。
* [eruda-orientation](https://github.com/liriliri/eruda-orientation):测试重力感应接口。 * [eruda-orientation](https://github.com/liriliri/eruda-orientation):测试重力感应接口。
编写插件的时候,你可以使用 Eruda 提供的工具函数,相关文档请点击[这里](doc/UTIL_API.md)查看 如果你想要自己编写插件,可以查看这里的[教程](./PLUGIN.md)。
## 相关项目 ## 相关项目

View File

@@ -127,7 +127,7 @@ LocalStorage, sessionStorage, cookies, scripts, styleSheets and images.
## Sources ## Sources
View json, html, js, css and http request detail. View json, html, js, and css.
### Config ### Config

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 193 KiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "eruda", "name": "eruda",
"version": "1.7.2", "version": "1.8.0",
"description": "Console for Mobile Browsers", "description": "Console for Mobile Browsers",
"main": "eruda.js", "main": "eruda.js",
"scripts": { "scripts": {

View File

@@ -281,6 +281,8 @@ export default class Log {
case 'output': case 'output':
case 'table': case 'table':
case 'dir': case 'dir':
case 'group':
case 'groupCollapsed':
if (log.src) { if (log.src) {
if (Log.showSrcInSources) { if (Log.showSrcInSources) {
return logger.emit('viewJson', log.src) return logger.emit('viewJson', log.src)
@@ -300,6 +302,8 @@ export default class Log {
Log.click(type, log, $el, logger) Log.click(type, log, $el, logger)
delete log.args delete log.args
}) })
} else if (log.type === 'group' || log.type === 'groupCollapsed') {
logger.toggleGroup(log)
} }
break break
case 'error': case 'error':

View File

@@ -322,6 +322,10 @@ export default class Logger extends Emitter {
el.scrollTop = el.scrollHeight - el.offsetHeight el.scrollTop = el.scrollHeight - el.offsetHeight
} }
toggleGroup(log) {
const { targetGroup } = log
targetGroup.collapsed ? this._openGroup(log) : this._collapseGroup(log)
}
_injectGlobal() { _injectGlobal() {
each(this._global, (val, name) => { each(this._global, (val, name) => {
if (window[name]) return if (window[name]) return

View File

@@ -4,20 +4,5 @@
<span {{{class 'icon-clear'}}}></span> <span {{{class 'icon-clear'}}}></span>
</div> </div>
</div> </div>
<ul {{{class 'requests'}}}> <ul {{{class 'requests'}}}></ul>
{{#if requests}} <div {{{class 'detail'}}}></div>
{{#each requests}}
<li class="eruda-request {{#if hasErr}}eruda-error{{/if}}" data-id="{{@key}}">
<span>{{name}}</span>
<span>{{status}}</span>
<span>{{method}}</span>
<span>{{subType}}</span>
<span>{{size}}</span>
<span>{{displayTime}}</span>
<span {{{class 'blue'}}}>{{url}}</span>
</li>
{{/each}}
{{else}}
<li><span>Empty</span></li>
{{/if}}
</ul>

View File

@@ -10,7 +10,8 @@ import {
extend, extend,
isEmpty, isEmpty,
$, $,
ms ms,
trim
} from '../lib/util' } from '../lib/util'
export default class Network extends Tool { export default class Network extends Tool {
@@ -22,6 +23,9 @@ export default class Network extends Tool {
this.name = 'network' this.name = 'network'
this._requests = {} this._requests = {}
this._tpl = require('./Network.hbs') this._tpl = require('./Network.hbs')
this._detailTpl = require('./detail.hbs')
this._requestsTpl = require('./requests.hbs')
this._datailData = {}
this._isFetchSupported = false this._isFetchSupported = false
if (window.fetch) this._isFetchSupported = isNative(window.fetch) if (window.fetch) this._isFetchSupported = isNative(window.fetch)
} }
@@ -32,6 +36,7 @@ export default class Network extends Tool {
this._bindEvent() this._bindEvent()
this._initCfg() this._initCfg()
this.overrideXhr() this.overrideXhr()
this._appendTpl()
} }
show() { show() {
super.show() super.show()
@@ -166,9 +171,29 @@ export default class Network extends Tool {
if (!data.done) return if (!data.done) return
showSources('http', data) self._showDetail(data)
}) })
.on('click', '.eruda-clear-request', () => this.clear()) .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('json', resTxt)
}
switch (data.type) {
case 'image':
return showSources('img', data.url)
}
})
function showSources(type, data) { function showSources(type, data) {
const sources = container.get('sources') const sources = container.get('sources')
@@ -187,6 +212,15 @@ export default class Network extends Tool {
this.restoreFetch() this.restoreFetch()
this._rmCfg() this._rmCfg()
} }
_showDetail(data) {
if (data.resTxt && trim(data.resTxt) === '') delete data.resTxt
if (isEmpty(data.resHeaders)) delete data.resHeaders
this._$detail.html(this._detailTpl(data)).show()
this._detailData = data
}
_hideDetail() {
this._$detail.hide()
}
_rmCfg() { _rmCfg() {
const cfg = this.config const cfg = this.config
@@ -196,6 +230,12 @@ export default class Network extends Tool {
settings.remove(cfg, 'overrideFetch').remove('Network') settings.remove(cfg, 'overrideFetch').remove('Network')
} }
_appendTpl() {
const $el = this._$el
$el.html(this._tpl())
this._$detail = $el.find('.eruda-detail')
this._$requests = $el.find('.eruda-requests')
}
_initCfg() { _initCfg() {
const cfg = (this.config = Settings.createCfg('network', { const cfg = (this.config = Settings.createCfg('network', {
overrideFetch: true overrideFetch: true
@@ -223,11 +263,11 @@ export default class Network extends Tool {
if (!isEmpty(this._requests)) renderData.requests = this._requests if (!isEmpty(this._requests)) renderData.requests = this._requests
this._renderHtml(this._tpl(renderData)) this._renderHtml(this._requestsTpl(renderData))
} }
_renderHtml(html) { _renderHtml(html) {
if (html === this._lastHtml) return if (html === this._lastHtml) return
this._lastHtml = html this._lastHtml = html
this._$el.html(html) this._$requests.html(html)
} }
} }

View File

@@ -16,7 +16,8 @@
border-bottom: 1px solid $gray-light; border-bottom: 1px solid $gray-light;
margin-bottom: 10px; margin-bottom: 10px;
li { li {
@include overflow-auto(x); display: flex;
width: 100%;
cursor: pointer; cursor: pointer;
border-top: 1px solid $gray-light; border-top: 1px solid $gray-light;
height: 41px; height: 41px;
@@ -27,18 +28,103 @@
} }
} }
span { span {
display: inline-block; display: block;
line-height: 40px; line-height: 40px;
height: 40px; height: 40px;
padding: 0 10px; padding: 0 5px;
font-size: $font-size-s; font-size: $font-size-s;
vertical-align: top; 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) { &:nth-child(even) {
background: $gray-light; background: $gray-light;
} }
} }
} }
.detail {
@include absolute();
z-index: 10;
display: none;
padding-bottom: 40px;
background: #f8f9fa;
.http {
@include overflow-auto(y);
height: 100%;
.breadcrumb {
@include breadcrumb();
}
.section {
background: #fff;
h2 {
background: $blue;
padding: $padding;
color: #fff;
font-size: $font-size;
}
margin-bottom: 10px;
table {
* {
user-select: text;
}
td {
font-size: $font-size-s;
padding: 5px 10px;
word-break: break-all;
}
.key {
white-space: nowrap;
}
}
}
.response,
.data {
user-select: text;
@include overflow-auto(x);
background: #fff;
padding: $padding;
font-size: $font-size-s;
margin-bottom: 10px;
white-space: pre-wrap;
}
}
.back {
position: absolute;
left: 0;
bottom: 0;
color: #fff;
width: 100%;
background: $blue;
display: block;
height: 40px;
line-height: 40px;
text-decoration: none;
text-align: center;
margin-top: 10px;
transition: background 0.3s;
&:active {
background: $blue-dark;
}
}
}
} }
} }
} }

View File

@@ -42,4 +42,5 @@
{{#if resTxt}} {{#if resTxt}}
<pre {{{class 'response'}}}>{{resTxt}}</pre> <pre {{{class 'response'}}}>{{resTxt}}</pre>
{{/if}} {{/if}}
</div> </div>
<div {{{class 'back'}}}>Back to the List</div>

14
src/Network/requests.hbs Normal file
View File

@@ -0,0 +1,14 @@
{{#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>Empty</span></li>
{{/if}}

View File

@@ -2,15 +2,7 @@ import Tool from '../DevTools/Tool'
import beautify from 'js-beautify' import beautify from 'js-beautify'
import JsonViewer from '../lib/JsonViewer' import JsonViewer from '../lib/JsonViewer'
import Settings from '../Settings/Settings' import Settings from '../Settings/Settings'
import { import { evalCss, ajax, escape, trim, isStr, highlight } from '../lib/util'
evalCss,
ajax,
isEmpty,
escape,
trim,
isStr,
highlight
} from '../lib/util'
export default class Sources extends Tool { export default class Sources extends Tool {
constructor() { constructor() {
@@ -112,31 +104,10 @@ export default class Sources extends Tool {
delete this._data delete this._data
} }
}) })
this._$el.on('click', '.eruda-http .eruda-response', () => {
const data = this._data.val
const resTxt = data.resTxt
switch (data.subType) {
case 'css':
return this.set('css', resTxt)
case 'html':
return this.set('html', resTxt)
case 'javascript':
return this.set('js', resTxt)
case 'json':
return this.set('json', resTxt)
}
switch (data.type) {
case 'image':
return this.set('img', data.url)
}
})
} }
_loadTpl() { _loadTpl() {
this._codeTpl = require('./code.hbs') this._codeTpl = require('./code.hbs')
this._imgTpl = require('./image.hbs') this._imgTpl = require('./image.hbs')
this._httpTpl = require('./http.hbs')
this._jsonTpl = require('./json.hbs') this._jsonTpl = require('./json.hbs')
this._rawTpl = require('./raw.hbs') this._rawTpl = require('./raw.hbs')
this._iframeTpl = require('./iframe.hbs') this._iframeTpl = require('./iframe.hbs')
@@ -192,8 +163,6 @@ export default class Sources extends Tool {
return this._renderCode() return this._renderCode()
case 'img': case 'img':
return this._renderImg() return this._renderImg()
case 'http':
return this._renderHttp()
case 'json': case 'json':
return this._renderJson() return this._renderJson()
case 'raw': case 'raw':
@@ -205,14 +174,6 @@ export default class Sources extends Tool {
_renderImg() { _renderImg() {
this._renderHtml(this._imgTpl(this._data.val)) this._renderHtml(this._imgTpl(this._data.val))
} }
_renderHttp() {
const val = this._data.val
if (val.resTxt.trim() === '') delete val.resTxt
if (isEmpty(val.resHeaders)) delete val.resHeaders
this._renderHtml(this._httpTpl(this._data.val))
}
_renderCode() { _renderCode() {
const data = this._data const data = this._data

View File

@@ -66,44 +66,6 @@
user-select: text; user-select: text;
} }
} }
.http {
.breadcrumb {
@include breadcrumb();
}
.section {
background: #fff;
h2 {
background: $blue;
padding: $padding;
color: #fff;
font-size: $font-size;
}
margin-bottom: 10px;
table {
* {
user-select: text;
}
td {
font-size: $font-size-s;
padding: 5px 10px;
word-break: break-all;
}
.key {
white-space: nowrap;
}
}
}
.response,
.data {
user-select: text;
@include overflow-auto(x);
background: #fff;
padding: $padding;
font-size: $font-size-s;
margin-bottom: 10px;
white-space: pre-wrap;
}
}
iframe { iframe {
width: 100%; width: 100%;
height: 100%; height: 100%;

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,9 @@
<li> <li>
<a href="#" id="stringify-timing">Stringify Timing</a> <a href="#" id="stringify-timing">Stringify Timing</a>
</li> </li>
<li>
<a href="#" id="log">Log</a>
</li>
</ul> </ul>
</nav> </nav>
<script> <script>
@@ -123,7 +126,42 @@
console.time('stringify window') console.time('stringify window')
eruda.util.stringifyAll(window) eruda.util.stringifyAll(window)
console.timeEnd('stringify window') console.timeEnd('stringify window')
}) });
addClickEvent('log', () => {
console.clear();
console.log('log');
console.warn('warn');
console.error(Error('test'));
console.info('info');
console.debug('debug');
console.dir(document.createElement('div'));
console.time('test');
console.timeEnd('test');
console.count('eruda');
console.count('eruda');
console.assert(true, 'assert msg');
var site1 = { name: 'Runoob', site: 'www.runoob.com' };
var site2 = { name: 'Google', site: 'www.google.com' };
var site3 = { name: 'Taobao', site: 'www.taobao.com' };
console.table([site1, site2, site3], ['site']);
console.log('%c Oh my heavens!', 'background: #222; color: #bada55');
console.log('This is the outer level');
console.group();
console.log('Level 2');
console.group();
console.log('Level 3');
console.warn('More of level 3');
console.groupEnd();
console.log('Back to level 2');
console.groupEnd();
console.log('Back to the outer level');
console.log(navigator);
console.log(location);
console.log(performance);
var arr = [];
for (var i = 0; i < 10000; i++) arr.push(i);
console.log(arr);
});
</script> </script>
<script> <script>
eruda.init(); eruda.init();