1
0
mirror of synced 2025-11-06 04:21:11 +08:00

feat(resources): use luna data grid

This commit is contained in:
redhoodsu
2023-01-19 17:59:53 +08:00
parent fb01c16254
commit eee1278385
8 changed files with 245 additions and 173 deletions

View File

@@ -201,7 +201,6 @@ export default class DevTools extends Emitter {
const store = safeStorage('local')
const data = JSON.parse(JSON.stringify(store))
console.log(data)
each(data, (val, key) => {
if (!isStr(val)) {
return

View File

@@ -46,9 +46,9 @@ export default [
{
name: 'Backers',
val() {
return `<a rel="noreferrer noopener" href="https://opencollective.com/eruda" target="_blank"><img style="width: 100%;"src="https://opencollective.com/eruda/backers.svg?width=${
return `<a rel="noreferrer noopener" href="https://opencollective.com/eruda" target="_blank"><img data-exclude="true" style="width: 100%;"src="https://opencollective.com/eruda/backers.svg?width=${
window.innerWidth * 1.5
}"></a>`
}&exclude=true"></a>`
},
},
]

View File

@@ -1,11 +1,10 @@
import map from 'licia/map'
import isEmpty from 'licia/isEmpty'
import $ from 'licia/$'
import trim from 'licia/trim'
import isNull from 'licia/isNull'
import escape from 'licia/escape'
import each from 'licia/each'
import LunaModal from 'luna-modal'
import { setState, getState, filterData } from './util'
import LunaDataGrid from 'luna-data-grid'
import { setState, getState } from './util'
import chobitsu from '../lib/chobitsu'
import { classPrefix as c } from '../lib/util'
@@ -13,70 +12,110 @@ export default class Cookie {
constructor($container, devtools) {
this._$container = $container
this._devtools = devtools
this._filter = ''
this._selectedItem = null
this._initTpl()
this._dataGrid = new LunaDataGrid(this._$dataGrid.get(0), {
columns: [
{
id: 'key',
title: 'Key',
weight: 30,
},
{
id: 'value',
title: 'Value',
weight: 90,
},
],
minHeight: 60,
maxHeight: 223,
})
this._bindEvent()
}
refresh() {
const $container = this._$container
const filter = this._filter
const dataGrid = this._dataGrid
const { cookies } = chobitsu.domain('Network').getCookies()
let cookieData = map(cookies, ({ name, value }) => ({
const cookieData = map(cookies, ({ name, value }) => ({
key: name,
val: value,
}))
cookieData = filterData(cookieData, filter)
dataGrid.clear()
each(cookieData, ({ key, val }) => {
dataGrid.append(
{
key,
value: val,
},
{
selectable: true,
}
)
})
const cookieState = getState('cookie', cookieData.length)
setState($container, cookieState)
}
_initTpl() {
const $container = this._$container
let cookieDataHtml = '<tr><td>Empty</td></tr>'
if (!isEmpty(cookieData)) {
cookieDataHtml = map(cookieData, ({ key, val }) => {
key = escape(key)
$container.html(
c(`<h2 class="title">
Cookie
<div class="btn refresh-cookie">
<span class="icon-refresh"></span>
</div>
<div class="btn show-detail btn-disabled">
<span class="icon icon-eye"></span>
</div>
<div class="btn delete-cookie btn-disabled">
<span class="icon icon-delete"></span>
</div>
<div class="btn clear-cookie">
<span class="icon-clear"></span>
</div>
<div class="btn filter" data-type="cookie">
<span class="icon-filter"></span>
</div>
<div class="btn filter-text"></div>
</h2>
<div class="data-grid"></div>`)
)
return `<tr>
<td class="${c('key')}">${key}</td>
<td>${escape(val)}</td>
<td class="${c('control')}">
<span class="${c(
'icon-delete delete-cookie'
)}" data-key="${key}"></span>
</td>
</tr>`
}).join('')
this._$dataGrid = $container.find(c('.data-grid'))
this._$filterText = $container.find(c('.filter-text'))
}
_updateButtons() {
const $container = this._$container
const $showDetail = $container.find(c('.show-detail'))
const $deleteCookie = $container.find(c('.delete-cookie'))
const btnDisabled = c('btn-disabled')
$showDetail.addClass(btnDisabled)
$deleteCookie.addClass(btnDisabled)
if (this._selectedItem) {
$showDetail.rmClass(btnDisabled)
$deleteCookie.rmClass(btnDisabled)
}
}
_getVal(key) {
const { cookies } = chobitsu.domain('Network').getCookies()
for (let i = 0, len = cookies.length; i < len; i++) {
if (cookies[i].name === key) {
return cookies[i].value
}
}
setState($container, cookieState)
$container.html(`<h2 class="${c('title')}">
Cookie
<div class="${c('btn refresh-cookie')}">
<span class="${c('icon-refresh')}"></span>
</div>
<div class="${c('btn clear-cookie')}">
<span class="${c('icon-clear')}"></span>
</div>
<div class="${c('btn filter')}" data-type="cookie">
<span class="${c('icon-filter')}"></span>
</div>
${
filter
? `<div class="${c('btn filter-text')}">${escape(filter)}</div>`
: ''
}
</h2>
<div class="${c('content')}">
<table>
<tbody>
${cookieDataHtml}
</tbody>
</table>
</div>`)
return ''
}
_bindEvent() {
const devtools = this._devtools
const self = this
this._$container
.on('click', c('.refresh-cookie'), () => {
@@ -89,19 +128,51 @@ export default class Cookie {
})
this.refresh()
})
.on('click', c('.delete-cookie'), function () {
const key = $(this).data('key')
.on('click', c('.delete-cookie'), () => {
const key = this._selectedItem
chobitsu.domain('Network').deleteCookies({ name: key })
self.refresh()
this.refresh()
})
.on('click', c('.show-detail'), () => {
const key = this._selectedItem
const val = this._getVal(key)
try {
showSources('object', JSON.parse(val))
} catch (e) {
showSources('raw', val)
}
})
.on('click', c('.filter'), () => {
LunaModal.prompt('Filter').then((filter) => {
if (isNull(filter)) return
filter = trim(filter)
this._filter = filter
this.refresh()
this._$filterText.text(filter)
this._dataGrid.setOption('filter', filter)
})
})
function showSources(type, data) {
const sources = devtools.get('sources')
if (!sources) return
sources.set(type, data)
devtools.showTool('sources')
return true
}
this._dataGrid
.on('select', (node) => {
this._selectedItem = node.data.key
this._updateButtons()
})
.on('deselect', () => {
this._selectedItem = null
this._updateButtons()
})
}
}

View File

@@ -3,6 +3,7 @@ import Settings from '../Settings/Settings'
import $ from 'licia/$'
import escape from 'licia/escape'
import isEmpty from 'licia/isEmpty'
import contain from 'licia/contain'
import unique from 'licia/unique'
import each from 'licia/each'
import sameOrigin from 'licia/sameOrigin'
@@ -202,6 +203,9 @@ export default class Resources extends Tool {
const entries = this._performance.getEntries()
entries.forEach((entry) => {
if (entry.initiatorType === 'img' || isImg(entry.name)) {
if (contain(entry.name, 'exclude=true')) {
return
}
imageData.push(entry.name)
}
})
@@ -210,7 +214,9 @@ export default class Resources extends Tool {
const $this = $(this)
const src = $this.attr('src')
if ($this.data('exclude') === 'true') return
if ($this.data('exclude') === 'true') {
return
}
imageData.push(src)
})

View File

@@ -9,10 +9,6 @@
margin-bottom: 10px;
overflow: hidden;
border: 1px solid var(--border);
.content {
@include overflow-auto(y);
max-height: 400px;
}
&.warn {
border: 1px solid var(--console-warn-border);
.title {
@@ -27,6 +23,15 @@
color: var(--console-error-foreground);
}
}
&.local-storage,
&.session-storage,
&.cookie {
border: none;
.title {
border: 1px solid var(--border);
border-bottom: none;
}
}
}
.title {
@include right-btn();
@@ -68,41 +73,4 @@
}
}
}
table {
color: var(--foreground);
border-collapse: collapse;
width: 100%;
font-size: $font-size-s;
tr:nth-child(even) {
background: var(--contrast);
}
td {
padding: 10px;
word-break: break-all;
&.key {
@include overflow-auto(x);
white-space: nowrap;
max-width: 120px;
}
&.control {
padding: 0;
font-size: 0;
width: 40px;
.icon-delete {
cursor: pointer;
color: var(--primary);
font-size: $font-size;
display: inline-block;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
transition: color $anim-duration;
&:active {
color: var(--accent);
}
}
}
}
}
}

View File

@@ -1,16 +1,12 @@
import isEmpty from 'licia/isEmpty'
import map from 'licia/map'
import each from 'licia/each'
import isStr from 'licia/isStr'
import startWith from 'licia/startWith'
import truncate from 'licia/truncate'
import escape from 'licia/escape'
import $ from 'licia/$'
import LunaModal from 'luna-modal'
import LunaDataGrid from 'luna-data-grid'
import isNull from 'licia/isNull'
import trim from 'licia/trim'
import { safeStorage, classPrefix as c } from '../lib/util'
import { filterData } from './util'
export default class Storage {
constructor($container, devtools, resources, type) {
@@ -18,58 +14,46 @@ export default class Storage {
this._$container = $container
this._devtools = devtools
this._resources = resources
this._filter = ''
this._selectedItem = null
this._storeData = []
this._initTpl()
this._dataGrid = new LunaDataGrid(this._$dataGrid.get(0), {
columns: [
{
id: 'key',
title: 'Key',
weight: 30,
},
{
id: 'value',
title: 'Value',
weight: 90,
},
],
minHeight: 60,
maxHeight: 223,
})
this._bindEvent()
}
refresh() {
const filter = this._filter
const dataGrid = this._dataGrid
this._refreshStorage()
dataGrid.clear()
const storeData = filterData(this._storeData, filter)
let storeDataHtml = '<tr><td>Empty</td></tr>'
if (!isEmpty(storeData)) {
storeDataHtml = map(storeData, ({ key, val }) => {
key = escape(key)
return `<tr>
<td class="${c('key')}">${key}</td>
<td class="${c('storage-val')}" data-key="${key}">${escape(val)}</td>
<td class="${c('control')}">
<span class="${c(
'icon-delete delete-storage'
)}" data-key="${key}"></span>
</td>
</tr>`
}).join('')
}
this._$container.html(`<h2 class="${c('title')}">
Local Storage
<div class="${c('btn refresh-storage')}">
<span class="${c('icon-refresh')}"></span>
</div>
<div class="${c('btn clear-storage')}">
<span class="${c('icon-clear')}"></span>
</div>
<div class="${c('btn filter')}">
<span class="${c('icon-filter')}"></span>
</div>
${
filter
? `<div class="${c('btn filter-text')}">${escape(filter)}</div>`
: ''
}
</h2>
<div class="${c('content')}">
<table>
<tbody>
${storeDataHtml}
</tbody>
</table>
</div>`)
each(this._storeData, ({ key, val }) => {
dataGrid.append(
{
key,
value: val,
},
{
selectable: true,
}
)
})
}
_refreshStorage() {
const resources = this._resources
@@ -99,29 +83,71 @@ export default class Storage {
this._storeData = storeData
}
_updateButtons() {
const $container = this._$container
const $showDetail = $container.find(c('.show-detail'))
const $deleteStorage = $container.find(c('.delete-storage'))
const btnDisabled = c('btn-disabled')
$showDetail.addClass(btnDisabled)
$deleteStorage.addClass(btnDisabled)
if (this._selectedItem) {
$showDetail.rmClass(btnDisabled)
$deleteStorage.rmClass(btnDisabled)
}
}
_initTpl() {
const $container = this._$container
const type = this._type
$container.html(
c(`<h2 class="title">
${type === 'local' ? 'Local' : 'Session'} Storage
<div class="btn refresh-storage">
<span class="icon icon-refresh"></span>
</div>
<div class="btn show-detail btn-disabled">
<span class="icon icon-eye"></span>
</div>
<div class="btn delete-storage btn-disabled">
<span class="icon icon-delete"></span>
</div>
<div class="btn clear-storage">
<span class="icon icon-clear"></span>
</div>
<div class="btn filter">
<span class="icon icon-filter"></span>
</div>
<div class="btn filter-text"></div>
</h2>
<div class="data-grid"></div>`)
)
this._$dataGrid = $container.find(c('.data-grid'))
this._$filterText = $container.find(c('.filter-text'))
}
_bindEvent() {
const type = this._type
const devtools = this._devtools
const self = this
this._$container
.on('click', c('.refresh-storage'), () => {
devtools.notify('Refreshed')
this.refresh()
})
.on('click', c('.clear-storage'), function () {
each(self._storeData, (val) => {
.on('click', c('.clear-storage'), () => {
each(this._storeData, (val) => {
if (type === 'local') {
localStorage.removeItem(val.key)
} else {
sessionStorage.removeItem(val.key)
}
})
self.refresh()
this.refresh()
})
.on('click', c('.storage-val'), function () {
const $this = $(this)
const key = $this.data('key')
.on('click', c('.show-detail'), () => {
const key = this._selectedItem
const val =
type === 'local'
@@ -138,13 +164,12 @@ export default class Storage {
LunaModal.prompt('Filter').then((filter) => {
if (isNull(filter)) return
filter = trim(filter)
this._filter = filter
this.refresh()
this._$filterText.text(filter)
this._dataGrid.setOption('filter', filter)
})
})
.on('click', c('.delete-storage'), function () {
const $this = $(this)
const key = $this.data('key')
.on('click', c('.delete-storage'), () => {
const key = this._selectedItem
if (type === 'local') {
localStorage.removeItem(key)
@@ -152,7 +177,7 @@ export default class Storage {
sessionStorage.removeItem(key)
}
self.refresh()
this.refresh()
})
function showSources(type, data) {
@@ -165,5 +190,15 @@ export default class Storage {
return true
}
this._dataGrid
.on('select', (node) => {
this._selectedItem = node.data.key
this._updateButtons()
})
.on('deselect', () => {
this._selectedItem = null
this._updateButtons()
})
}
}

View File

@@ -1,18 +1,5 @@
import lowerCase from 'licia/lowerCase'
import contain from 'licia/contain'
import filter from 'licia/filter'
import { classPrefix as c } from '../lib/util'
export function filterData(data, keyword) {
keyword = lowerCase(keyword)
if (!keyword) return data
return filter(data, ({ key, val }) => {
return contain(lowerCase(key), keyword) || contain(lowerCase(val), keyword)
})
}
export function setState($el, state) {
$el
.rmClass(c('ok'))

View File

@@ -83,5 +83,11 @@
&:active {
color: var(--accent);
}
&.btn-disabled {
color: inherit !important;
cursor: default !important;
pointer-events: none;
opacity: 0.5;
}
}
}