1
0
mirror of synced 2025-12-10 08:28:08 +08:00

Compare commits

...

20 Commits

Author SHA1 Message Date
surunzi
8dac00318f release: v3.4.1 2024-11-10 22:37:33 +08:00
surunzi
05b1ceda93 fix: theme not updated if system theme changed 2024-11-10 22:33:32 +08:00
surunzi
c7190499df fix: fetch remains pending when error occurs 2024-11-10 22:04:36 +08:00
redhoodsu
786c515bfe chore: small changes 2024-10-24 12:25:37 +08:00
redhoodsu
d92cbe2c58 fix: no copy and delete for shadow root 2024-10-11 09:13:50 +08:00
redhoodsu
1d4764dd4c chore: update dependencies 2024-10-10 10:57:13 +08:00
redhoodsu
c6b3e4ff62 chore: small changes 2024-10-08 23:01:21 +08:00
redhoodsu
f8315c2971 docs: simplify readme 2024-10-08 15:23:08 +08:00
redhoodsu
1b8929b9a5 release: v3.4.0 2024-09-27 19:03:35 +08:00
redhoodsu
ddac0c9353 feat: shadow dom support 2024-09-27 18:57:31 +08:00
redhoodsu
600ea6213a fix: quirks mode table rendering 2024-09-20 18:52:09 +08:00
redhoodsu
27b85b4834 chore: use licia pointerEvent 2024-09-20 16:12:03 +08:00
redhoodsu
ce3f6aef38 release: v3.3.0 2024-09-09 13:28:52 +08:00
surunzi
d99b38e725 chore: small changes 2024-09-08 22:30:21 +08:00
redhoodsu
588dba7b74 chore: update luna-box-model 2024-09-06 19:38:32 +08:00
redhoodsu
8c05dba355 chore: update vue plugin version 2024-09-04 19:45:41 +08:00
Rohit Kushvaha
6cd4259c49 Fixed url string 2024-08-22 14:30:04 +08:00
redhoodsu
a402cc5fd5 docs: fix image link 2024-08-22 14:28:05 +08:00
redhoodsu
a8dbc49907 chore: update vue plugin version 2024-08-16 18:10:36 +08:00
redhoodsu
becfd98fef feat: add eruda-vue 2024-08-15 11:41:25 +08:00
18 changed files with 172 additions and 204 deletions

View File

@@ -1,32 +0,0 @@
# Contributing Guide
## Development Setup
[Node.js](https://nodejs.org/en/) is needed for the development of eruda.
After cloning the repo, run:
```bash
# install npm dependencies.
npm install
# copy jasmine lib from node_modules to test folder.
npm run setup
```
## Commonly used NPM scripts
```bash
# watch and auto re-build.
npm run dev
# build eruda.js
npm run build
# lint, build and test.
npm run ci
```
## Project Structure
- **doc**: documents.
- **build**: webpack configuration, and some other useful scripts.
- **src**: source code, written in es2015.
- **test**: contain pages for testing.

View File

@@ -14,22 +14,15 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: '18.x'
- run: |
npm install -g @liriliri/lsla
npm i
npm run ci
- run: |
npm install -g codecov
codecov --disable=gcov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -11,20 +11,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- name: Build eruda
run: |
- run: |
npm i -g @liriliri/lsla
npm i
npm run build
- name: Publish package on NPM
working-directory: dist
- working-directory: dist
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -1,3 +1,18 @@
## 3.4.1 (10 Nov 2024)
* fix: no copy and delete for shadow root
* fix: fetch remains pending when error occurs
* fix: theme not updated if system theme changed
## 3.4.0 (27 Sep 2024)
* feat: support shadow dom [#158](https://github.com/liriliri/eruda/issues/158)
* fix: quirks mode table rendering [#459](https://github.com/liriliri/eruda/issues/459)
## 3.3.0 (9 Sep 2024)
* feat: add vue devtools plugin
## 3.2.3 (10 AUG 2024)
* fix: WebSocket message base64 encoded [#447](https://github.com/liriliri/eruda/issues/447)

View File

@@ -29,29 +29,13 @@ Console for Mobile Browsers.
[license-image]: https://img.shields.io/npm/l/eruda?style=flat-square
[donate-image]: https://img.shields.io/badge/$-donate-0070ba.svg?style=flat-square
<img src="https://eruda.liriliri.io/img/screenshot.jpg" style="width:100%">
<img src="https://eruda.liriliri.io/screenshot.jpg" style="width:100%">
## Demo
![Demo](https://eruda.liriliri.io/img/qrcode.png)
![Demo](https://eruda.liriliri.io/qrcode.png)
Browse it on your phone: [https://eruda.liriliri.io/](https://eruda.liriliri.io/)
In order to try it for different sites, execute the script below on browser address bar.
```javascript
javascript:(function () { var script = document.createElement('script'); script.src="https://cdn.jsdelivr.net/npm/eruda"; document.body.append(script); script.onload = function () { eruda.init(); } })();
```
## Features
* [Console](https://eruda.liriliri.io/docs/api.html#console): Display JavaScript logs.
* [Elements](https://eruda.liriliri.io/docs/api.html#elements): Check dom state.
* [Network](https://eruda.liriliri.io/docs/api.html#network): Show requests status.
* [Resources](https://eruda.liriliri.io/docs/api.html#resources): Show localStorage, cookie information.
* [Info](https://eruda.liriliri.io/docs/api.html#info): Show url, user agent info.
* [Snippets](https://eruda.liriliri.io/docs/api.html#snippets): Include snippets used most often.
* [Sources](https://eruda.liriliri.io/docs/api.html#sources): Html, js, css source viewer.
Browse it on your phone: [eruda.liriliri.io](https://eruda.liriliri.io/)
## Install
@@ -71,61 +55,11 @@ Add this script to your page.
It's also available on [jsDelivr](http://www.jsdelivr.com/projects/eruda) and [cdnjs](https://cdnjs.com/libraries/eruda).
```html
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>
```
The JavaScript file size is quite huge(about 100kb gzipped) and therefore not suitable to include in mobile pages. It's recommended to make sure eruda is loaded only when eruda is set to true on url(http://example.com/?eruda=true), for example:
```javascript
;(function () {
var src = '//cdn.jsdelivr.net/npm/eruda';
if (!/eruda=true/.test(window.location) && localStorage.getItem('active-eruda') != 'true') return;
document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
document.write('<scr' + 'ipt>eruda.init();</scr' + 'ipt>');
})();
```
If you are using modern JavaScript tooling, you can dynamically import it.
```javascript
if (import.meta.env.MODE === 'development') {
import('eruda').then(eruda => eruda.default.init());
}
```
## Configuration
When initialization, a configuration object can be passed in.
* container: Container element. If not set, it will append an element directly
under html root element.
* tool: Choose which default tools you want, by default all will be added.
For more information, please check the [documentation](https://eruda.liriliri.io/docs/api.html).
```javascript
let el = document.createElement('div');
document.body.appendChild(el);
eruda.init({
container: el,
tool: ['console', 'elements']
});
```
## Plugins
* [eruda-monitor](https://github.com/liriliri/eruda-monitor): Display page fps and memory.
* [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-code](https://github.com/liriliri/eruda-code): Run JavaScript code.
* [eruda-benchmark](https://github.com/liriliri/eruda-benchmark): Run JavaScript benchmarks.
* [eruda-geolocation](https://github.com/liriliri/eruda-geolocation): Test geolocation.
* [eruda-orientation](https://github.com/liriliri/eruda-orientation): Test orientation api.
* [eruda-touches](https://github.com/liriliri/eruda-touches): Visualize screen touches.
If you want to create a plugin yourself, follow the guides [here](https://eruda.liriliri.io/docs/plugin.html).
For more detailed usage instructions, please read the documentation at [eruda.liriliri.io](https://eruda.liriliri.io/docs/)!
## Related Projects
@@ -148,4 +82,4 @@ If you want to create a plugin yourself, follow the guides [here](https://eruda.
## Contribution
Read [Contributing Guide](.github/CONTRIBUTING.md) for development setup instructions.
Read [Contributing Guide](https://eruda.liriliri.io/docs/contributing.html) for development setup instructions.

View File

@@ -1,6 +1,6 @@
{
"name": "eruda",
"version": "3.2.3",
"version": "3.4.1",
"description": "Console for Mobile Browsers",
"main": "eruda.js",
"browserslist": [
@@ -45,7 +45,7 @@
"autoprefixer": "^9.7.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.5",
"chobitsu": "^1.5.1",
"chobitsu": "^1.8.4",
"core-js": "^3.37.1",
"css-loader": "^3.4.2",
"es-check": "^6.2.1",
@@ -61,11 +61,11 @@
"karma-jquery": "^0.2.4",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^5.0.0",
"licia": "^1.41.0",
"luna-box-model": "^0.1.0",
"luna-console": "^1.3.4",
"luna-data-grid": "^0.6.0",
"luna-dom-viewer": "^1.3.0",
"licia": "^1.44.0",
"luna-box-model": "^1.0.0",
"luna-console": "^1.3.5",
"luna-data-grid": "^1.0.0",
"luna-dom-viewer": "^1.4.0",
"luna-modal": "^1.2.3",
"luna-notification": "^0.3.2",
"luna-object-viewer": "^0.3.1",

View File

@@ -10,11 +10,13 @@ import isNum from 'licia/isNum'
import nextTick from 'licia/nextTick'
import $ from 'licia/$'
import toNum from 'licia/toNum'
import isDarkMode from 'licia/isDarkMode'
import extend from 'licia/extend'
import isStr from 'licia/isStr'
import theme from 'licia/theme'
import upperFirst from 'licia/upperFirst'
import startWith from 'licia/startWith'
import ready from 'licia/ready'
import pointerEvent from 'licia/pointerEvent'
import evalCss from '../lib/evalCss'
import emitter from '../lib/emitter'
import { isDarkTheme } from '../lib/themes'
@@ -23,7 +25,6 @@ import LunaModal from 'luna-modal'
import LunaTab from 'luna-tab'
import {
classPrefix as c,
drag,
eventClient,
hasSafeArea,
safeStorage,
@@ -265,19 +266,19 @@ export default class DevTools extends Emitter {
$container.rmClass(c('safe-area'))
}
}
_setTheme(theme) {
_setTheme(t) {
const { $container } = this
if (theme === 'System preference') {
theme = isDarkMode() ? 'Dark' : 'Light'
if (t === 'System preference') {
t = upperFirst(theme.get())
}
if (isDarkTheme(theme)) {
if (isDarkTheme(t)) {
$container.addClass(c('dark'))
} else {
$container.rmClass(c('dark'))
}
evalCss.setTheme(theme)
evalCss.setTheme(t)
}
_setTransparency(opacity) {
if (!isNum(opacity)) return
@@ -358,8 +359,8 @@ export default class DevTools extends Emitter {
$resizer.css('height', '100%')
$document.on(drag('move'), moveListener)
$document.on(drag('end'), endListener)
$document.on(pointerEvent('move'), moveListener)
$document.on(pointerEvent('up'), endListener)
}
const moveListener = (e) => {
if (!this._isResizing) {
@@ -385,16 +386,23 @@ export default class DevTools extends Emitter {
$resizer.css('height', 10)
$document.off(drag('move'), moveListener)
$document.off(drag('end'), endListener)
$document.off(pointerEvent('move'), moveListener)
$document.off(pointerEvent('up'), endListener)
}
$resizer.css('height', 10)
$resizer.on(drag('start'), startListener)
$resizer.on(pointerEvent('down'), startListener)
$navBar.on('contextmenu', (e) => e.preventDefault())
this.$container.on('click', (e) => e.stopPropagation())
window.addEventListener('resize', this._checkSafeArea)
emitter.on(emitter.SCALE, this._updateTabHeight)
theme.on('change', () => {
const t = this.config.get('theme')
if (t === 'System preference') {
this._setTheme(t)
}
})
}
}

View File

@@ -17,6 +17,7 @@ import isBool from 'licia/isBool'
import safeGet from 'licia/safeGet'
import $ from 'licia/$'
import h from 'licia/h'
import extend from 'licia/extend'
import MutationObserver from 'licia/MutationObserver'
import CssStore from './CssStore'
import Settings from '../Settings/Settings'
@@ -31,10 +32,10 @@ export default class Detail {
this._$container = $container
this._devtools = devtools
this._curEl = document.documentElement
this._bindEvent()
this._initObserver()
this._initCfg()
this._initTpl()
this._bindEvent()
}
show(el) {
this._curEl = el
@@ -42,18 +43,7 @@ export default class Detail {
this._computedStyleSearchKeyword = ''
this._enableObserver()
this._render()
const { nodeId } = chobitsu.domain('DOM').getNodeId({ node: el })
chobitsu.domain('Overlay').highlightNode({
nodeId,
highlightConfig: {
showInfo: true,
contentColor: 'rgba(111, 168, 220, .66)',
paddingColor: 'rgba(147, 196, 125, .55)',
borderColor: 'rgba(255, 229, 153, .66)',
marginColor: 'rgba(246, 178, 107, .66)',
},
})
this._highlight()
}
hide = () => {
this._$container.hide()
@@ -87,6 +77,36 @@ export default class Detail {
if (this._origAddEvent) winEventProto.addEventListener = this._origAddEvent
if (this._origRmEvent) winEventProto.removeEventListener = this._origRmEvent
}
_highlight = (type) => {
const el = this._curEl
const highlightConfig = {
showInfo: false,
}
if (!type || type === 'all') {
extend(highlightConfig, {
showInfo: true,
contentColor: 'rgba(111, 168, 220, .66)',
paddingColor: 'rgba(147, 196, 125, .55)',
borderColor: 'rgba(255, 229, 153, .66)',
marginColor: 'rgba(246, 178, 107, .66)',
})
} else if (type === 'margin') {
highlightConfig.marginColor = 'rgba(246, 178, 107, .66)'
} else if (type === 'border') {
highlightConfig.borderColor = 'rgba(255, 229, 153, .66)'
} else if (type === 'padding') {
highlightConfig.paddingColor = 'rgba(147, 196, 125, .55)'
} else if (type === 'content') {
highlightConfig.contentColor = 'rgba(111, 168, 220, .66)'
}
const { nodeId } = chobitsu.domain('DOM').getNodeId({ node: el })
chobitsu.domain('Overlay').highlightNode({
nodeId,
highlightConfig,
})
}
_initTpl() {
const $container = this._$container
@@ -257,7 +277,9 @@ export default class Detail {
const events = el.erudaEvents
if (events && keys(events).length !== 0) ret.listeners = events
if (needNoStyle(tagName)) return ret
if (needNoStyle(tagName)) {
return ret
}
let computedStyle = cssStore.getComputedStyle()
@@ -321,6 +343,8 @@ export default class Detail {
this._render()
devtools.notify('Refreshed', { icon: 'success' })
})
this._boxModel.on('highlight', this._highlight)
}
_initObserver() {
this._observer = new MutationObserver((mutations) => {
@@ -450,8 +474,9 @@ function rmDefComputedStyle(computedStyle, styles) {
const NO_STYLE_TAG = ['script', 'style', 'meta', 'title', 'link', 'head']
const needNoStyle = (tagName) =>
const needNoStyle = (tagName) => {
NO_STYLE_TAG.indexOf(tagName.toLowerCase()) > -1
}
const wrapLink = (link) => `<a href="${link}" target="_blank">${link}</a>`

View File

@@ -9,6 +9,7 @@ import isEmpty from 'licia/isEmpty'
import toNum from 'licia/toNum'
import copy from 'licia/copy'
import isMobile from 'licia/isMobile'
import isShadowRoot from 'licia/isShadowRoot'
import LunaDomViewer from 'luna-dom-viewer'
import { isErudaEl, classPrefix as c, isChobitsuEl } from '../lib/util'
import evalCss from '../lib/evalCss'
@@ -98,7 +99,7 @@ export default class Elements extends Tool {
const node = this._curNode
if (!node) {
if (!node || isShadowRoot(node)) {
return
}
@@ -118,7 +119,7 @@ export default class Elements extends Tool {
if (this._curNode.nodeType === Node.ELEMENT_NODE) {
this._detail.show(this._curNode)
} else {
this._detail.show(this._curNode.parentNode)
this._detail.show(this._curNode.parentNode || this._curNode.host)
}
}
_initTpl() {
@@ -309,7 +310,14 @@ function getCrumbs(el) {
idx: i++,
})
el = el.parentElement
if (isShadowRoot(el)) {
el = el.host
}
if (!el.parentElement && isShadowRoot(el.parentNode)) {
el = el.parentNode
} else {
el = el.parentElement
}
}
return ret.reverse()

View File

@@ -1,5 +1,6 @@
import each from 'licia/each'
import isStr from 'licia/isStr'
import isShadowRoot from 'licia/isShadowRoot'
import { classPrefix as c } from '../lib/util'
export function formatNodeName(node, { noAttr = false } = {}) {
@@ -7,6 +8,8 @@ export function formatNodeName(node, { noAttr = false } = {}) {
return `<span class="${c('tag-name-color')}">(text)</span>`
} else if (node.nodeType === Node.COMMENT_NODE) {
return `<span class="${c('tag-name-color')}"><!--></span>`
} else if (isShadowRoot(node)) {
return `<span class="${c('tag-name-color')}">#shadow-root</span>`
}
const { id, className, attributes } = node

View File

@@ -4,7 +4,8 @@ import Emitter from 'licia/Emitter'
import $ from 'licia/$'
import nextTick from 'licia/nextTick'
import orientation from 'licia/orientation'
import { pxToNum, classPrefix as c, drag, eventClient } from '../lib/util'
import pointerEvent from 'licia/pointerEvent'
import { pxToNum, classPrefix as c, eventClient } from '../lib/util'
import evalCss from '../lib/evalCss'
const $document = $(document)
@@ -93,8 +94,8 @@ export default class EntryBtn extends Emitter {
this._oldX = pxToNum($el.css('left'))
this._oldY = pxToNum($el.css('top'))
this._startY = eventClient('y', e)
$document.on(drag('move'), this._onDragMove)
$document.on(drag('end'), this._onDragEnd)
$document.on(pointerEvent('move'), this._onDragMove)
$document.on(pointerEvent('up'), this._onDragEnd)
}
_onDragMove = (e) => {
const btnSize = this._$el.get(0).offsetWidth
@@ -132,8 +133,8 @@ export default class EntryBtn extends Emitter {
}
this._onDragMove(e)
$document.off(drag('move'), this._onDragMove)
$document.off(drag('end'), this._onDragEnd)
$document.off(pointerEvent('move'), this._onDragMove)
$document.off(pointerEvent('up'), this._onDragEnd)
const cfg = this.config
@@ -149,7 +150,7 @@ export default class EntryBtn extends Emitter {
_bindEvent() {
const $el = this._$el
$el.on(drag('start'), this._onDragStart)
$el.on(pointerEvent('down'), this._onDragStart)
orientation.on('change', () => this._resetPos(true))
window.addEventListener('resize', () => this._resetPos())

View File

@@ -203,6 +203,22 @@ export default class Network extends Tool {
request.render()
}
_loadingFailed = (params) => {
const request = this._requests[params.requestId]
if (!this._isRecording || !request) {
return
}
const time = params.timestamp * 1000
request.time = time - request.startTime
request.displayTime = ms(request.time)
request.hasErr = true
request.status = 0
request.done = true
request.render()
}
_copyCurl = () => {
const request = this._selectedRequest
@@ -322,6 +338,7 @@ export default class Network extends Tool {
network.on('responseReceivedExtraInfo', this._resReceivedExtraInfo)
network.on('responseReceived', this._resReceived)
network.on('loadingFinished', this._loadingFinished)
network.on('loadingFailed', this._loadingFailed)
emitter.on(emitter.SCALE, this._updateScale)
}

View File

@@ -230,11 +230,10 @@ export default class Resources extends Tool {
const imageState = getState('image', imageData.length)
let imageDataHtml = '<li>Empty</li>'
if (!isEmpty(imageData)) {
// prettier-ignore
imageDataHtml = map(imageData, (image) => {
return `<li class="${c('image')}">
<img src="${escape(image)}" data-exclude="true" class="${c(
'img-link'
)}"/>
<img src="${escape(image)}" data-exclude="true" class="${c('img-link')}"/>
</li>`
}).join('')
}

View File

@@ -56,12 +56,19 @@
font-size: $font-size-s;
display: flex;
flex-wrap: wrap;
padding: $padding !important;
@include clear-float();
padding-left: $padding;
padding-top: $padding;
&::after {
content: '';
flex-grow: 1000;
}
li {
flex-grow: 1;
cursor: pointer;
overflow-y: hidden;
margin-right: $padding;
margin-bottom: $padding;
border: 1px solid var(--border);
&.image {
height: 100px;
font-size: 0;

View File

@@ -93,12 +93,19 @@ export default [
},
desc: 'Scale down the whole page to fit screen',
},
{
name: 'Load Vue Plugin',
fn() {
loadPlugin('vue')
},
desc: 'Vue devtools',
},
{
name: 'Load Monitor Plugin',
fn() {
loadPlugin('monitor')
},
desc: 'Display page fps and memory',
desc: 'Display page fps, memory and dom nodes',
},
{
name: 'Load Features Plugin',
@@ -217,7 +224,7 @@ function loadPlugin(name) {
}
const pluginVersion = {
monitor: '1.0.2',
monitor: '1.1.1',
features: '2.1.0',
timing: '2.0.1',
code: '2.2.0',
@@ -225,4 +232,5 @@ const pluginVersion = {
geolocation: '2.1.0',
orientation: '2.1.1',
touches: '2.1.0',
vue: '1.1.1',
}

View File

@@ -5,7 +5,6 @@ import isUndef from 'licia/isUndef'
import last from 'licia/last'
import map from 'licia/map'
import memStorage from 'licia/memStorage'
import root from 'licia/root'
import toNum from 'licia/toNum'
import trim from 'licia/trim'
import html from 'licia/html'
@@ -147,32 +146,6 @@ function processClass(str) {
}).join(' ')
}
const hasTouchSupport = 'ontouchstart' in root
const hasPointerSupport = 'PointerEvent' in root
const touchEvents = {
start: 'touchstart',
move: 'touchmove',
end: 'touchend',
}
const mouseEvents = {
start: 'mousedown',
move: 'mousemove',
end: 'mouseup',
}
const pointerEvents = {
start: 'pointerdown',
move: 'pointermove',
end: 'pointerup',
}
export function drag(name) {
if (hasPointerSupport) {
return pointerEvents[name]
}
return hasTouchSupport ? touchEvents[name] : mouseEvents[name]
}
export function eventClient(type, e) {
const name = type === 'x' ? 'clientX' : 'clientY'

View File

@@ -449,9 +449,14 @@
}
.luna-box-model {
background: transparent;
background: var(--background);
}
.luna-box-model-position {
.luna-box-model-position,
.luna-box-model-margin,
.luna-box-model-border,
.luna-box-model-padding,
.luna-box-model-content {
color: var(--foreground);
background: var(--background);
}

View File

@@ -116,5 +116,13 @@
table {
border-collapse: collapse;
border-spacing: 0;
color: inherit;
font-size: 1em;
font-style: inherit;
font-variant: inherit;
font-weight: inherit;
line-height: inherit;
text-decoration: inherit;
white-space: inherit;
}
}