mirror of
https://github.com/liriliri/eruda.git
synced 2026-05-20 08:47:20 +08:00
refactor(elements): use luna box model
This commit is contained in:
@@ -7,8 +7,6 @@ const path = require('path')
|
|||||||
|
|
||||||
process.traceDeprecation = true
|
process.traceDeprecation = true
|
||||||
|
|
||||||
const nodeModDir = path.resolve('./node_modules/') + '/'
|
|
||||||
const srcDir = path.resolve('./src') + '/'
|
|
||||||
const banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage
|
const banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage
|
||||||
|
|
||||||
const postcssLoader = {
|
const postcssLoader = {
|
||||||
@@ -69,6 +67,7 @@ module.exports = {
|
|||||||
path.resolve(__dirname, '../node_modules/luna-dom-viewer'),
|
path.resolve(__dirname, '../node_modules/luna-dom-viewer'),
|
||||||
path.resolve(__dirname, '../node_modules/luna-text-viewer'),
|
path.resolve(__dirname, '../node_modules/luna-text-viewer'),
|
||||||
path.resolve(__dirname, '../node_modules/luna-setting'),
|
path.resolve(__dirname, '../node_modules/luna-setting'),
|
||||||
|
path.resolve(__dirname, '../node_modules/luna-box-model'),
|
||||||
],
|
],
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^5.0.0",
|
"karma-webpack": "^5.0.0",
|
||||||
"licia": "^1.37.1",
|
"licia": "^1.37.1",
|
||||||
|
"luna-box-model": "^0.1.0",
|
||||||
"luna-console": "^1.3.0",
|
"luna-console": "^1.3.0",
|
||||||
"luna-data-grid": "^0.4.0",
|
"luna-data-grid": "^0.4.0",
|
||||||
"luna-dom-viewer": "^1.2.3",
|
"luna-dom-viewer": "^1.2.3",
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ import escape from 'licia/escape'
|
|||||||
import startWith from 'licia/startWith'
|
import startWith from 'licia/startWith'
|
||||||
import contain from 'licia/contain'
|
import contain from 'licia/contain'
|
||||||
import unique from 'licia/unique'
|
import unique from 'licia/unique'
|
||||||
import isStr from 'licia/isStr'
|
|
||||||
import isNaN from 'licia/isNaN'
|
|
||||||
import isNum from 'licia/isNum'
|
|
||||||
import each from 'licia/each'
|
import each from 'licia/each'
|
||||||
import keys from 'licia/keys'
|
import keys from 'licia/keys'
|
||||||
import isNull from 'licia/isNull'
|
import isNull from 'licia/isNull'
|
||||||
@@ -19,13 +16,15 @@ import isFn from 'licia/isFn'
|
|||||||
import isBool from 'licia/isBool'
|
import isBool from 'licia/isBool'
|
||||||
import safeGet from 'licia/safeGet'
|
import safeGet from 'licia/safeGet'
|
||||||
import $ from 'licia/$'
|
import $ from 'licia/$'
|
||||||
|
import h from 'licia/h'
|
||||||
import MutationObserver from 'licia/MutationObserver'
|
import MutationObserver from 'licia/MutationObserver'
|
||||||
import CssStore from './CssStore'
|
import CssStore from './CssStore'
|
||||||
import Settings from '../Settings/Settings'
|
import Settings from '../Settings/Settings'
|
||||||
import LunaModal from 'luna-modal'
|
import LunaModal from 'luna-modal'
|
||||||
|
import LunaBoxModel from 'luna-box-model'
|
||||||
import chobitsu from '../lib/chobitsu'
|
import chobitsu from '../lib/chobitsu'
|
||||||
import { formatNodeName } from './util'
|
import { formatNodeName } from './util'
|
||||||
import { pxToNum, isErudaEl, classPrefix as c } from '../lib/util'
|
import { isErudaEl, classPrefix as c } from '../lib/util'
|
||||||
|
|
||||||
export default class Detail {
|
export default class Detail {
|
||||||
constructor($container, devtools) {
|
constructor($container, devtools) {
|
||||||
@@ -35,6 +34,7 @@ export default class Detail {
|
|||||||
this._bindEvent()
|
this._bindEvent()
|
||||||
this._initObserver()
|
this._initObserver()
|
||||||
this._initCfg()
|
this._initCfg()
|
||||||
|
this._initTpl()
|
||||||
}
|
}
|
||||||
show(el) {
|
show(el) {
|
||||||
this._curEl = el
|
this._curEl = el
|
||||||
@@ -87,6 +87,33 @@ export default class Detail {
|
|||||||
if (this._origAddEvent) winEventProto.addEventListener = this._origAddEvent
|
if (this._origAddEvent) winEventProto.addEventListener = this._origAddEvent
|
||||||
if (this._origRmEvent) winEventProto.removeEventListener = this._origRmEvent
|
if (this._origRmEvent) winEventProto.removeEventListener = this._origRmEvent
|
||||||
}
|
}
|
||||||
|
_initTpl() {
|
||||||
|
const $container = this._$container
|
||||||
|
|
||||||
|
const html = `<div class="${c('control')}">
|
||||||
|
<span class="${c('icon-arrow-left back')}"></span>
|
||||||
|
<span class="${c('element-name')}"></span>
|
||||||
|
<span class="${c('icon-refresh refresh')}"></span>
|
||||||
|
</div>
|
||||||
|
<div class="${c('element')}">
|
||||||
|
<div class="${c('attributes section')}"></div>
|
||||||
|
<div class="${c('styles section')}"></div>
|
||||||
|
<div class="${c('computed-style section')}"></div>
|
||||||
|
<div class="${c('listeners section')}"></div>
|
||||||
|
</div>`
|
||||||
|
|
||||||
|
$container.html(html)
|
||||||
|
|
||||||
|
this._$elementName = $container.find(c('.element-name'))
|
||||||
|
this._$attributes = $container.find(c('.attributes'))
|
||||||
|
this._$styles = $container.find(c('.styles'))
|
||||||
|
this._$listeners = $container.find(c('.listeners'))
|
||||||
|
this._$computedStyle = $container.find(c('.computed-style'))
|
||||||
|
|
||||||
|
const boxModelContainer = h('div')
|
||||||
|
this._$boxModel = $(boxModelContainer)
|
||||||
|
this._boxModel = new LunaBoxModel(boxModelContainer)
|
||||||
|
}
|
||||||
_toggleAllComputedStyle() {
|
_toggleAllComputedStyle() {
|
||||||
this._rmDefComputedStyle = !this._rmDefComputedStyle
|
this._rmDefComputedStyle = !this._rmDefComputedStyle
|
||||||
|
|
||||||
@@ -94,26 +121,32 @@ export default class Detail {
|
|||||||
}
|
}
|
||||||
_render() {
|
_render() {
|
||||||
const data = this._getData(this._curEl)
|
const data = this._getData(this._curEl)
|
||||||
|
const $attributes = this._$attributes
|
||||||
|
const $elementName = this._$elementName
|
||||||
|
const $styles = this._$styles
|
||||||
|
const $computedStyle = this._$computedStyle
|
||||||
|
const $listeners = this._$listeners
|
||||||
|
|
||||||
let attribute = '<tr><td>Empty</td></tr>'
|
$elementName.html(data.name)
|
||||||
|
|
||||||
|
let attributes = '<tr><td>Empty</td></tr>'
|
||||||
if (!isEmpty(data.attributes)) {
|
if (!isEmpty(data.attributes)) {
|
||||||
attribute = map(data.attributes, ({ name, value }) => {
|
attributes = map(data.attributes, ({ name, value }) => {
|
||||||
return `<tr>
|
return `<tr>
|
||||||
<td class="${c('attribute-name-color')}">${escape(name)}</td>
|
<td class="${c('attribute-name-color')}">${escape(name)}</td>
|
||||||
<td class="${c('string-color')}">${value}</td>
|
<td class="${c('string-color')}">${value}</td>
|
||||||
</tr>`
|
</tr>`
|
||||||
}).join('')
|
}).join('')
|
||||||
}
|
}
|
||||||
attribute = `<div class="${c('attributes section')}">
|
attributes = `<h2>Attributes</h2>
|
||||||
<h2>Attributes</h2>
|
<div class="${c('table-wrapper')}">
|
||||||
<div class="${c('table-wrapper')}">
|
<table>
|
||||||
<table>
|
<tbody>
|
||||||
<tbody>
|
${attributes}
|
||||||
${attribute}
|
</tbody>
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>`
|
</div>`
|
||||||
|
$attributes.html(attributes)
|
||||||
|
|
||||||
let styles = ''
|
let styles = ''
|
||||||
if (!isEmpty(data.styles)) {
|
if (!isEmpty(data.styles)) {
|
||||||
@@ -129,12 +162,13 @@ export default class Detail {
|
|||||||
<div>}</div>
|
<div>}</div>
|
||||||
</div>`
|
</div>`
|
||||||
}).join('')
|
}).join('')
|
||||||
styles = `<div class="${c('styles section')}">
|
styles = `<h2>Styles</h2>
|
||||||
<h2>Styles</h2>
|
<div class="${c('style-wrapper')}">
|
||||||
<div class="${c('style-wrapper')}">
|
${style}
|
||||||
${style}
|
|
||||||
</div>
|
|
||||||
</div>`
|
</div>`
|
||||||
|
$styles.html(styles).show()
|
||||||
|
} else {
|
||||||
|
$styles.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
let computedStyle = ''
|
let computedStyle = ''
|
||||||
@@ -148,59 +182,39 @@ export default class Detail {
|
|||||||
</div>`)
|
</div>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const boxModel = data.boxModel
|
computedStyle = `<h2>
|
||||||
// prettier-ignore
|
Computed Style
|
||||||
const boxModelHtml = [`<div class="${c('box-model')}">`,
|
${toggleButton}
|
||||||
boxModel.position ? `<div class="${c('position')}">` : '',
|
<div class="${c('btn computed-style-search')}">
|
||||||
boxModel.position ? `<div class="${c('label')}">position</div><div class="${c('top')}">${boxModel.position.top}</div><br><div class="${c('left')}">${boxModel.position.left}</div>` : '',
|
<span class="${c('icon-filter')}"></span>
|
||||||
`<div class="${c('margin')}">`,
|
|
||||||
`<div class="${c('label')}">margin</div><div class="${c('top')}">${boxModel.margin.top}</div><br><div class="${c('left')}">${boxModel.margin.left}</div>`,
|
|
||||||
`<div class="${c('border')}">`,
|
|
||||||
`<div class="${c('label')}">border</div><div class="${c('top')}">${boxModel.border.top}</div><br><div class="${c('left')}">${boxModel.border.left}</div>`,
|
|
||||||
`<div class="${c('padding')}">`,
|
|
||||||
`<div class="${c('label')}">padding</div><div class="${c('top')}">${boxModel.padding.top}</div><br><div class="${c('left')}">${boxModel.padding.left}</div>`,
|
|
||||||
`<div class="${c('content')}">`,
|
|
||||||
`<span>${boxModel.content.width}</span> × <span>${boxModel.content.height}</span>`,
|
|
||||||
'</div>',
|
|
||||||
`<div class="${c('right')}">${boxModel.padding.right}</div><br><div class="${c('bottom')}">${boxModel.padding.bottom}</div>`,
|
|
||||||
'</div>',
|
|
||||||
`<div class="${c('right')}">${boxModel.border.right}</div><br><div class="${c('bottom')}">${boxModel.border.bottom}</div>`,
|
|
||||||
'</div>',
|
|
||||||
`<div class="${c('right')}">${boxModel.margin.right}</div><br><div class="${c('bottom')}">${boxModel.margin.bottom}</div>`,
|
|
||||||
'</div>',
|
|
||||||
boxModel.position ? `<div class="${c('right')}">${boxModel.position.right}</div><br><div class="${c('bottom')}">${boxModel.position.bottom}</div>` : '',
|
|
||||||
boxModel.position ? '</div>' : '',
|
|
||||||
'</div>'].join('')
|
|
||||||
|
|
||||||
computedStyle = `<div class="${c('computed-style section')}">
|
|
||||||
<h2>
|
|
||||||
Computed Style
|
|
||||||
${toggleButton}
|
|
||||||
<div class="${c('btn computed-style-search')}">
|
|
||||||
<span class="${c('icon-filter')}"></span>
|
|
||||||
</div>
|
|
||||||
${
|
|
||||||
data.computedStyleSearchKeyword
|
|
||||||
? `<div class="${c('btn filter-text')}">${escape(
|
|
||||||
data.computedStyleSearchKeyword
|
|
||||||
)}</div>`
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
</h2>
|
|
||||||
${boxModelHtml}
|
|
||||||
<div class="${c('table-wrapper')}">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
${map(data.computedStyle, (val, key) => {
|
|
||||||
return `<tr>
|
|
||||||
<td class="${c('key')}">${escape(key)}</td>
|
|
||||||
<td>${val}</td>
|
|
||||||
</tr>`
|
|
||||||
}).join('')}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
${
|
||||||
|
data.computedStyleSearchKeyword
|
||||||
|
? `<div class="${c('btn filter-text')}">${escape(
|
||||||
|
data.computedStyleSearchKeyword
|
||||||
|
)}</div>`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</h2>
|
||||||
|
<div class="${c('box-model')}"></div>
|
||||||
|
<div class="${c('table-wrapper')}">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
${map(data.computedStyle, (val, key) => {
|
||||||
|
return `<tr>
|
||||||
|
<td class="${c('key')}">${escape(key)}</td>
|
||||||
|
<td>${val}</td>
|
||||||
|
</tr>`
|
||||||
|
}).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
|
$computedStyle.html(computedStyle).show()
|
||||||
|
this._boxModel.setOption('element', this._curEl)
|
||||||
|
$computedStyle.find(c('.box-model')).append(this._$boxModel.get(0))
|
||||||
|
} else {
|
||||||
|
$computedStyle.text('').hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
let listeners = ''
|
let listeners = ''
|
||||||
@@ -218,27 +232,16 @@ export default class Detail {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>`
|
</div>`
|
||||||
}).join('')
|
}).join('')
|
||||||
listeners = `<div class="${c('listeners section')}">
|
listeners = `<h2>Event Listeners</h2>
|
||||||
<h2>Event Listeners</h2>
|
<div class="${c('listener-wrapper')}">
|
||||||
<div class="${c('listener-wrapper')}">
|
${listeners}
|
||||||
${listeners}
|
|
||||||
</div>
|
|
||||||
</div>`
|
</div>`
|
||||||
|
$listeners.html(listeners).show()
|
||||||
|
} else {
|
||||||
|
$listeners.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = `<div class="${c('control')}">
|
this._$container.show()
|
||||||
<span class="${c('icon-arrow-left back')}"></span>
|
|
||||||
<span class="${c('element-name')}">${data.name}</span>
|
|
||||||
<span class="${c('icon-refresh refresh')}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="${c('element')}">
|
|
||||||
${attribute}
|
|
||||||
${styles}
|
|
||||||
${computedStyle}
|
|
||||||
${listeners}
|
|
||||||
</div>`
|
|
||||||
|
|
||||||
this._$container.html(html).show()
|
|
||||||
}
|
}
|
||||||
_getData(el) {
|
_getData(el) {
|
||||||
const ret = {}
|
const ret = {}
|
||||||
@@ -258,34 +261,6 @@ export default class Detail {
|
|||||||
|
|
||||||
let computedStyle = cssStore.getComputedStyle()
|
let computedStyle = cssStore.getComputedStyle()
|
||||||
|
|
||||||
function getBoxModelValue(type) {
|
|
||||||
let keys = ['top', 'left', 'right', 'bottom']
|
|
||||||
if (type !== 'position') keys = map(keys, (key) => `${type}-${key}`)
|
|
||||||
if (type === 'border') keys = map(keys, (key) => `${key}-width`)
|
|
||||||
|
|
||||||
return {
|
|
||||||
top: boxModelValue(computedStyle[keys[0]], type),
|
|
||||||
left: boxModelValue(computedStyle[keys[1]], type),
|
|
||||||
right: boxModelValue(computedStyle[keys[2]], type),
|
|
||||||
bottom: boxModelValue(computedStyle[keys[3]], type),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const boxModel = {
|
|
||||||
margin: getBoxModelValue('margin'),
|
|
||||||
border: getBoxModelValue('border'),
|
|
||||||
padding: getBoxModelValue('padding'),
|
|
||||||
content: {
|
|
||||||
width: boxModelValue(computedStyle['width']),
|
|
||||||
height: boxModelValue(computedStyle['height']),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if (computedStyle['position'] !== 'static') {
|
|
||||||
boxModel.position = getBoxModelValue('position')
|
|
||||||
}
|
|
||||||
ret.boxModel = boxModel
|
|
||||||
|
|
||||||
const styles = cssStore.getMatchedCSSRules()
|
const styles = cssStore.getMatchedCSSRules()
|
||||||
styles.unshift(getInlineStyle(el.style))
|
styles.unshift(getInlineStyle(el.style))
|
||||||
styles.forEach((style) => processStyleRules(style.style))
|
styles.forEach((style) => processStyleRules(style.style))
|
||||||
@@ -480,19 +455,6 @@ const needNoStyle = (tagName) =>
|
|||||||
|
|
||||||
const wrapLink = (link) => `<a href="${link}" target="_blank">${link}</a>`
|
const wrapLink = (link) => `<a href="${link}" target="_blank">${link}</a>`
|
||||||
|
|
||||||
function boxModelValue(val, type) {
|
|
||||||
if (isNum(val)) return val
|
|
||||||
|
|
||||||
if (!isStr(val)) return '‒'
|
|
||||||
|
|
||||||
const ret = pxToNum(val)
|
|
||||||
if (isNaN(ret)) return val
|
|
||||||
|
|
||||||
if (type === 'position') return ret
|
|
||||||
|
|
||||||
return ret === 0 ? '‒' : ret
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEvent(el, type, listener, useCapture = false) {
|
function addEvent(el, type, listener, useCapture = false) {
|
||||||
if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return
|
if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return
|
||||||
|
|
||||||
|
|||||||
@@ -136,60 +136,9 @@
|
|||||||
}
|
}
|
||||||
.box-model {
|
.box-model {
|
||||||
@include overflow-auto(x);
|
@include overflow-auto(x);
|
||||||
color: #222;
|
|
||||||
font-size: $font-size-s;
|
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
|
||||||
border-bottom: 1px solid var(--color);
|
border-bottom: 1px solid var(--color);
|
||||||
.label {
|
|
||||||
position: absolute;
|
|
||||||
margin-left: 3px;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
.top,
|
|
||||||
.left,
|
|
||||||
.right,
|
|
||||||
.bottom {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.left,
|
|
||||||
.right {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.position,
|
|
||||||
.margin,
|
|
||||||
.border,
|
|
||||||
.padding,
|
|
||||||
.content {
|
|
||||||
position: relative;
|
|
||||||
background: #fff;
|
|
||||||
display: inline-block;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding: 3px;
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
.position {
|
|
||||||
border: 1px grey dotted;
|
|
||||||
}
|
|
||||||
.margin {
|
|
||||||
border: 1px dashed;
|
|
||||||
background: rgba(246, 178, 107, 0.66);
|
|
||||||
}
|
|
||||||
.border {
|
|
||||||
border: 1px #000 solid;
|
|
||||||
background: rgba(255, 229, 153, 0.66);
|
|
||||||
}
|
|
||||||
.padding {
|
|
||||||
border: 1px grey dashed;
|
|
||||||
background: rgba(147, 196, 125, 0.55);
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
border: 1px grey solid;
|
|
||||||
min-width: 100px;
|
|
||||||
background: rgba(111, 168, 220, 0.66);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.computed-style {
|
.computed-style {
|
||||||
font-size: $font-size-s;
|
font-size: $font-size-s;
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ export default {
|
|||||||
require('luna-tab/luna-tab.css') +
|
require('luna-tab/luna-tab.css') +
|
||||||
require('luna-text-viewer/luna-text-viewer.css') +
|
require('luna-text-viewer/luna-text-viewer.css') +
|
||||||
require('luna-setting/luna-setting.css') +
|
require('luna-setting/luna-setting.css') +
|
||||||
|
require('luna-box-model/luna-box-model.css') +
|
||||||
require('./style/style.scss') +
|
require('./style/style.scss') +
|
||||||
require('./style/icon.css')
|
require('./style/icon.css')
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -440,3 +440,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.luna-box-model {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luna-box-model-position {
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user