将devtools的代码移植过去

This commit is contained in:
xu_yanfeng
2024-01-08 19:59:08 +08:00
parent 2ad5bf6e60
commit 686b6d11ad
32 changed files with 3 additions and 9938 deletions

View File

View File

View File

@@ -1,50 +0,0 @@
module.exports = {
root: true,
globals: {
chrome: true,
},
env: {
node: true,
webextensions: true,
},
// parser: "vue-eslint-parser",
// parserOptions: {
// "parser": "babel-eslint",
// "ecmaVersion": 2020,
// ecmaFeatures: {
// legacyDecorators: true
// }
// },
parserOptions: {
parser: "@typescript-eslint/parser"
},
extends: [
"plugin:vue/essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
],
rules: {
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"prettier/prettier": "off",
"no-empty": "off",
"prefer-const": "off",
"@typescript-eslint/no-var-requires": "off",
"no-undef": "off",
"no-debugger": "off",
"no-unreachable": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-prototype-builtins": "off",
"@typescript-eslint/ban-ts-comment": "off",
"no-inner-declarations": "off",
"vue/no-unused-vars": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-this-alias": "off"
}
};

View File

@@ -1 +0,0 @@

View File

@@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="" style="width: 100%;height: 100%;margin: 0;padding: 0;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body style="width: 100%;height: 100%;margin: 0;padding: 0;">
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -1,10 +0,0 @@
import Vue from "vue"
export enum BusMsg {
ShowPlace = "ShowPlace",
RequestObjectData = "RequestObjectData",
LogData = "LogData",
FoldAllGroup = "FoldAllGroup"
}
export default new Vue();

View File

@@ -1,41 +0,0 @@
import {PluginEvent, Page, Msg} from "@/core/types";
class ConnectBackground {
connect: chrome.runtime.Port | null = null;
constructor() {
this._initConnect();
}
private _initConnect() {
if (chrome && chrome.runtime) {
this.connect = chrome.runtime.connect({name: Page.Devtools});
this.connect.onDisconnect.addListener(() => {
console.log(`%c[Connect-Dis]`, "color:red;")
this.connect = null;
})
}
}
onBackgroundMessage(cb: Function) {
if (this.connect) {
this.connect.onMessage.addListener((event, sender) => {
cb && cb(event, sender)
});
}
}
postMessageToBackground(msg: Msg, data?: any) {
if (this.connect) {
let sendData = new PluginEvent(Page.Devtools, Page.Background, msg, data)
this.connect.postMessage(sendData)
} else {
console.warn("重新和background建立链接")
this._initConnect();
this.postMessageToBackground(msg, data)
}
}
}
export const connectBackground = new ConnectBackground();

View File

@@ -1,43 +0,0 @@
.el-color-picker--mini {
width: 100% !important;
.el-color-picker__trigger {
width: 100% !important;
height: 30px !important;
padding: 0;
.el-color-picker__icon {
display: none;
}
}
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: #6d6d6d;
}
.el-tree-node__content {
.leaf {
span {
user-select: none;
}
}
}
.el-input {
input {
text-align: left !important;
}
}
.el-input-group__append {
padding: 0;
}
.el-tree {
width: 100%;
}
* {
font-family: "PingFang SC", Arial, sans-serif;
}

View File

@@ -1,539 +0,0 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@@ -1,280 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2620843" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe7b9;</span>
<div class="name">font-size</div>
<div class="code-name">&amp;#xe7b9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe626;</span>
<div class="name">车巴巴-未知项</div>
<div class="code-name">&amp;#xe626;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe649;</span>
<div class="name">节点</div>
<div class="code-name">&amp;#xe649;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe65c;</span>
<div class="name">text</div>
<div class="code-name">&amp;#xe65c;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1636725471182') format('woff2'),
url('iconfont.woff?t=1636725471182') format('woff'),
url('iconfont.ttf?t=1636725471182') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont el-icon-third-font-size"></span>
<div class="name">
font-size
</div>
<div class="code-name">.el-icon-third-font-size
</div>
</li>
<li class="dib">
<span class="icon iconfont el-icon-third-unknown"></span>
<div class="name">
车巴巴-未知项
</div>
<div class="code-name">.el-icon-third-unknown
</div>
</li>
<li class="dib">
<span class="icon iconfont el-icon-third-node"></span>
<div class="name">
节点
</div>
<div class="code-name">.el-icon-third-node
</div>
</li>
<li class="dib">
<span class="icon iconfont el-icon-third-text"></span>
<div class="name">
text
</div>
<div class="code-name">.el-icon-third-text
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont el-icon-third-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#el-icon-third-font-size"></use>
</svg>
<div class="name">font-size</div>
<div class="code-name">#el-icon-third-font-size</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#el-icon-third-unknown"></use>
</svg>
<div class="name">车巴巴-未知项</div>
<div class="code-name">#el-icon-third-unknown</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#el-icon-third-node"></use>
</svg>
<div class="name">节点</div>
<div class="code-name">#el-icon-third-node</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#el-icon-third-text"></use>
</svg>
<div class="name">text</div>
<div class="code-name">#el-icon-third-text</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@@ -1,31 +0,0 @@
@font-face {
font-family: "iconfont"; /* Project id 2620843 */
src: url('iconfont.woff2?t=1636725471182') format('woff2'),
url('iconfont.woff?t=1636725471182') format('woff'),
url('iconfont.ttf?t=1636725471182') format('truetype');
}
.iconfont ,[class='el-icon-third'],[class*=' el-icon-third']{
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.el-icon-third-font-size:before {
content: "\e7b9";
}
.el-icon-third-unknown:before {
content: "\e626";
}
.el-icon-third-node:before {
content: "\e649";
}
.el-icon-third-text:before {
content: "\e65c";
}

File diff suppressed because one or more lines are too long

View File

@@ -1,37 +0,0 @@
{
"id": "2620843",
"name": "cc-icon",
"font_family": "iconfont",
"css_prefix_text": "el-icon-third-",
"description": "",
"glyphs": [
{
"icon_id": "8794801",
"name": "font-size",
"font_class": "font-size",
"unicode": "e7b9",
"unicode_decimal": 59321
},
{
"icon_id": "1156016",
"name": "车巴巴-未知项",
"font_class": "unknown",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "6246293",
"name": "节点",
"font_class": "node",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "9785726",
"name": "text",
"font_class": "text",
"unicode": "e65c",
"unicode_decimal": 58972
}
]
}

View File

@@ -1,15 +0,0 @@
import Vue from "vue";
import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css"
import './icon-font/iconfont.css'
import "./global.less"
import index from "./ui/index.vue";
import {init} from './register-panel';
init();
Vue.use(ElementUI, {size: "mini"});
new Vue({
el: "#app",
render: h => h(index)
});

View File

@@ -1,33 +0,0 @@
import Manifest from '../manifest.json'
import {connectBackground} from "@/devtools/connectBackground";
import {PluginEvent, Msg, Page} from "@/core/types";
export function init() {
if (chrome && chrome.devtools) {
// 对应的是Elements面板的边栏
chrome.devtools.panels.elements.createSidebarPane('Cocos', function (sidebar) {
sidebar.setObject({some_data: "some data to show!"});
});
// 创建devtools-panel
chrome.devtools.panels.create("Cocos", "icons/48.png", Manifest.devtools_page, (panel: chrome.devtools.panels.ExtensionPanel) => {
console.log("[CC-Inspector] Dev Panel Created!");
panel.onShown.addListener((window) => {
// 面板显示查询是否是cocos游戏
console.log("panel show");
// connectBackground.postMessageToBackground(Msg.Support, null)
});
panel.onHidden.addListener(() => {
// 面板隐藏
console.log("panel hide");
});
panel.onSearch.addListener(function (action, query) {
// ctrl+f 查找触发
console.log("panel search!");
});
}
);
}
}

View File

@@ -1,45 +0,0 @@
const Key = "settings";
export const RefreshManual = "manual";
export const RefreshAuto = "auto";
interface SettingsData {
refreshType: string;
refreshTime: number;
}
let defaultData: SettingsData = {
refreshTime: 500,
refreshType: RefreshManual,
}
class Settings {
public data: SettingsData | null = null;
constructor() {
this.init();
}
private init() {
const data = localStorage.getItem(Key)
if (data) {
try {
this.data = JSON.parse(data)
} catch (e) {
this.data = defaultData;
}
}
this.data = Object.assign(defaultData, this.data)
}
isManualRefresh() {
return this.data?.refreshType === RefreshManual;
}
save() {
const str = JSON.stringify(this.data);
localStorage.setItem(Key, str);
}
}
export const settings = new Settings();

View File

@@ -1,631 +0,0 @@
<template>
<div id="devtools">
<el-drawer
title="settings"
direction="btt"
@close="onCloseSettings"
:visible.sync="showSettings">
<div>
<settings-vue></settings-vue>
</div>
</el-drawer>
<div class="head" v-show="iframes.length>1">
<div class="label">inspect target:</div>
<el-select v-model="frameID" placeholder="please select ..." @change="onChangeFrame" style="flex:1;">
<el-option v-for="item in iframes" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</div>
<div v-show="isShowDebug" class="find">
<div v-if="false">
<el-button type="success" @click="onMemoryTest">内存测试</el-button>
</div>
<div v-if="false">
<span>JS堆栈限制: {{ memory.performance.jsHeapSizeLimit }}</span>
<span>JS堆栈大小: {{ memory.performance.totalJSHeapSize }}</span>
<span>JS堆栈使用: {{ memory.performance.usedJSHeapSize }}</span>
</div>
<div ref="left" class="left">
<div class="tool-btn">
<div style="padding-left: 15px;flex:1;">Node Tree</div>
<el-button v-show="isShowRefreshBtn" type="success" class="el-icon-refresh"
size="mini"
@click="onBtnClickUpdateTree"></el-button>
<el-button @click="onClickSettings" class="el-icon-s-tools"></el-button>
</div>
<el-input placeholder="enter keywords to filter" v-model="filterText">
<template slot="append">
<div class="matchCase ">
<div class="iconfont el-icon-third-font-size" @click.stop="onChangeCase"
title="match case"
:style="{'color':matchCase?'red':''}">
</div>
</div>
</template>
</el-input>
<div class="treeList">
<el-tree :data="treeData"
ref="tree"
style="display: inline-block;"
:props="defaultProps"
:highlight-current="true"
:default-expand-all="false"
:default-expanded-keys="expandedKeys"
:filter-node-method="filterNode"
:expand-on-click-node="false"
node-key="uuid"
@node-expand="onNodeExpand"
@node-collapse="onNodeCollapse"
@node-click="handleNodeClick">
<!-- :render-content="renderContent"-->
<span slot-scope="{node,data}" class="leaf" :class="data.active?'leaf-show':'leaf-hide'">
<span>{{ node.label }}</span>
<!-- <el-button v-if="!!data||true"> 显示</el-button>-->
</span>
</el-tree>
</div>
</div>
<ui-divider ref="divider" @move="onDividerMove"></ui-divider>
<div ref="right" class="right">
<properties v-if="treeItemData" :data="treeItemData"></properties>
</div>
</div>
<div v-show="!isShowDebug" class="no-find">
<span>No games created by cocos creator found!</span>
<el-button type="success" class="el-icon-refresh" @click="onBtnClickUpdatePage">刷新</el-button>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import {Component, Watch} from "vue-property-decorator";
import properties from "./propertys.vue";
import {Msg, Page, PluginEvent} from "@/core/types"
import {connectBackground} from "@/devtools/connectBackground";
import {
EngineData,
FrameDetails,
Info,
NodeInfoData,
ObjectData,
ObjectItemRequestData,
TreeData
} from "@/devtools/data";
import Bus, {BusMsg} from "@/devtools/bus";
import settingsVue from "./settings.vue"
import {RefreshAuto, RefreshManual, settings} from "@/devtools/settings";
import UiDivider from "@/devtools/ui/ui-divider.vue";
@Component({
components: {
UiDivider,
properties,
settingsVue,
}
})
export default class Index extends Vue {
private isShowDebug: boolean = false;
treeItemData: NodeInfoData | null = null;
treeData: Array<TreeData> = []
expandedKeys: Array<string> = [];
selectedUUID: string | null = null;
filterText: string | null = null;
iframes: Array<{ label: string, value: number }> = []
frameID: number | null = null;
@Watch("filterText")
updateFilterText(val: any) {
(this.$refs?.tree as any)?.filter(val);
}
private matchCase = false;
onChangeCase() {
this.matchCase = !this.matchCase;
this.updateFilterText(this.filterText);
}
private showSettings = false;
onClickSettings() {
this.showSettings = true;
}
onDividerMove(event: MouseEvent) {
const leftDiv: HTMLDivElement = this.$refs.left as HTMLDivElement;
if (leftDiv) {
let width = leftDiv.clientWidth;
width += event.movementX;
if (width >= 300 && width < document.body.clientWidth - 100) {
leftDiv.style.width = `${width}px`;
}
}
}
private syncSettings() {
if (settings.data) {
const {refreshType, refreshTime} = settings.data;
switch (refreshType) {
case RefreshAuto: {
this.isShowRefreshBtn = false;
this.onEnableTreeWatch(true, refreshTime)
break;
}
case RefreshManual: {
this.isShowRefreshBtn = true;
this.onEnableTreeWatch(false)
}
}
}
}
private isShowRefreshBtn = false;
onCloseSettings() {
this.syncSettings();
}
// el-tree的渲染key
defaultProps = {
children: "children",
label: "name"
};
memory = {
performance: {},
console: {},
}
timerID: number | null = null;
private requestList: Array<{ id: string, cb: Function }> = [];
created() {
if (chrome && chrome.runtime) {
this._initChromeRuntimeConnect();
}
window.addEventListener("message", function (event) {
console.log("on vue:" + JSON.stringify(event));
}, false);
Bus.$on(BusMsg.ShowPlace, (data: EngineData) => {
console.log(data)
this._expand(data.engineUUID);
})
Bus.$on(BusMsg.RequestObjectData, (data: ObjectData, cb: Function) => {
if (!data.id || this.requestList.find(el => el.id === data.id)) {
return
}
this.requestList.push({id: data.id, cb});
this.sendMsgToContentScript(Msg.GetObjectItemData, data)
});
Bus.$on(BusMsg.LogData, (data: string[]) => {
this.sendMsgToContentScript(Msg.LogData, data);
})
}
filterNode(value: any, data: any) {
if (!value) {
return true;
} else {
if (this.matchCase) {
// 严格匹配大写
return data?.name?.indexOf(value) !== -1;
} else {
return data?.name?.toLowerCase().indexOf(value.toLowerCase()) !== -1;
}
}
}
onChangeFrame() {
this.sendMsgToContentScript(Msg.UseFrame, this.frameID)
}
_expand(uuid: string) {
let expandKeys: Array<string> = [];
function circle(array: any) {
for (let i = 0; i < array.length; i++) {
let item = array[i];
expandKeys.push(item.uuid);
if (item.uuid === uuid) {
return true
} else {
let find = circle(item.children);
if (find) {
return true;
} else {
expandKeys.pop();
}
}
}
}
circle(this.treeData)
expandKeys.forEach(key => {
if (!this.expandedKeys.find(el => el === key)) {
this.expandedKeys.push(key)
}
})
// 高亮uuid
}
renderContent(h: Function, options: any) {
let {node, data, store} = options;
return h("span", {class: ""}, data.name)
// return(<span>1111</span>)
}
_onMsgTreeInfo(treeData: Array<TreeData>) {
this.isShowDebug = true;
if (!Array.isArray(treeData)) {
treeData = [treeData]
}
this.treeData = treeData;
if (this._checkSelectedUUID()) {
this.updateNodeInfo();
this.$nextTick(() => {
//@ts-ignore
this.$refs.tree.setCurrentKey(this.selectedUUID);
})
}
}
_checkSelectedUUID() {
if (this.selectedUUID) {
const b = this._findUuidInTree(this.treeData, this.selectedUUID)
if (b) {
return true;
}
}
this.selectedUUID = null;
this.treeItemData = null;
return false;
}
_findUuidInTree(data: TreeData[], targetUUID: string) {
function circle(tree: TreeData[]) {
for (let i = 0; i < tree.length; i++) {
let item: TreeData = tree[i];
if (item.uuid === targetUUID) {
return true;
}
if (circle(item.children)) {
return true;
}
}
return false;
}
return circle(data)
}
_onMsgNodeInfo(eventData: NodeInfoData) {
this.isShowDebug = true;
this.treeItemData = eventData;
}
_onMsgMemoryInfo(eventData: any) {
this.memory = eventData;
}
_onMsgSupport(isCocosGame: boolean) {
this.isShowDebug = isCocosGame;
if (isCocosGame) {
this.syncSettings();
this.onBtnClickUpdateTree();
} else {
this._clearTimer();
this.treeData = [];
this.treeItemData = null;
this.selectedUUID = null;
}
}
mounted() {
this.syncSettings();
}
_initChromeRuntimeConnect() {
const msgFunctionMap: Record<string, Function> = {};
msgFunctionMap[Msg.TreeInfo] = this._onMsgTreeInfo;
msgFunctionMap[Msg.Support] = this._onMsgSupport;
msgFunctionMap[Msg.NodeInfo] = this._onMsgNodeInfo;
msgFunctionMap[Msg.MemoryInfo] = this._onMsgMemoryInfo;
msgFunctionMap[Msg.UpdateProperty] = this._onMsgUpdateProperty;
msgFunctionMap[Msg.UpdateFrames] = this._onMsgUpdateFrames;
msgFunctionMap[Msg.GetObjectItemData] = this._onMsgGetObjectItemData;
// 接收来自background.js的消息数据
connectBackground.onBackgroundMessage((data: PluginEvent, sender: any) => {
if (!data) {
return;
}
if (data.target === Page.Devtools) {
console.log("[Devtools]", data);
PluginEvent.finish(data);
const {msg} = data;
if (msg) {
const func = msgFunctionMap[msg];
if (func) {
func(data.data)
} else {
console.warn(`没有${msg}消息的函数`)
}
}
}
});
}
_onMsgGetObjectItemData(requestData: ObjectItemRequestData) {
if (requestData.id !== null) {
let findIndex = this.requestList.findIndex(el => el.id === requestData.id)
if (findIndex > -1) {
let del = this.requestList.splice(findIndex, 1)[0];
del.cb(requestData.data);
}
}
}
_onMsgUpdateFrames(details: FrameDetails[]) {
// 先把iframes里面无效的清空了
this.iframes = this.iframes.filter(item => {
details.find(el => el.frameID === item.value)
})
// 同步配置
details.forEach(item => {
let findItem = this.iframes.find(el => el.value === item.frameID);
if (findItem) {
findItem.label = item.url;
} else {
this.iframes.push({
label: item.url,
value: item.frameID,
})
}
})
// 第一次获取到frame配置后自动获取frame数据
if (this.frameID === null && this.iframes.length > 0 && !this.iframes.find(el => el.value === this.frameID)) {
this.frameID = this.iframes[0].value;
this.onChangeFrame();
}
}
_onMsgUpdateProperty(data: Info) {
const uuid = data.path[0];
const key = data.path[1];
const value = data.data;
let treeArray: Array<TreeData> = [];
function circle(array: Array<TreeData>) {
array.forEach(item => {
treeArray.push(item);
circle(item.children);
})
}
// 更新指定uuid节点的tree的name
circle(this.treeData)
let ret = treeArray.find(el => el.uuid === uuid);
if (ret) {
if (key === "name") {
ret.name = value;
}
if (key === "active") {
ret.active = !!value;
}
}
}
handleNodeClick(data: TreeData) {
this.selectedUUID = data.uuid;
this.updateNodeInfo();
}
private updateNodeInfo() {
if (this.selectedUUID) {
this.sendMsgToContentScript(Msg.NodeInfo, this.selectedUUID);
}
}
onEnableTreeWatch(watch: boolean, time = 300) {
if (watch) {
this._clearTimer();
this.timerID = setInterval(() => {
this.onBtnClickUpdateTree();
}, time);
} else {
this._clearTimer();
}
}
private _clearTimer() {
if (this.timerID !== null) {
clearInterval(this.timerID);
this.timerID = null;
}
}
sendMsgToContentScript(msg: Msg, data?: any) {
if (!chrome || !chrome.devtools) {
console.log("环境异常,无法执行函数");
return;
}
connectBackground.postMessageToBackground(msg, data);
}
// 问题没有上下文的权限只能操作DOM
_executeScript(para: Object) {
let tabID = chrome.devtools.inspectedWindow.tabId;
//@ts-ignore
chrome.tabs.executeScript(tabID, {code: `var CCInspectorPara='${JSON.stringify(para)}';`}, () => {
//@ts-ignore
chrome.tabs.executeScript(tabID, {file: "js/execute.js"})
});
}
_inspectedCode() {
let injectCode = "";
chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => {
if (isException) {
console.error(isException);
} else {
console.log(`执行结果:${result}`)
}
});
}
onBtnClickUpdateTree() {
this.sendMsgToContentScript(Msg.TreeInfo, this.frameID);
}
onBtnClickUpdatePage() {
this.sendMsgToContentScript(Msg.Support);
}
onMemoryTest() {
this.sendMsgToContentScript(Msg.MemoryInfo);
}
onNodeExpand(data: TreeData) {
if (data.hasOwnProperty("uuid") && data.uuid) {
this.expandedKeys.push(data.uuid)
}
}
onNodeCollapse(data: TreeData) {
if (data.hasOwnProperty("uuid")) {
let index = this.expandedKeys.findIndex(el => el === data.uuid);
if (index !== -1) {
this.expandedKeys.splice(index, 1)
}
}
}
}
</script>
<style scoped lang="less">
@import "../../index.less";
#devtools {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
.head {
display: flex;
flex-direction: row;
align-items: center;
padding: 1px 0;
border-bottom: solid 1px grey;
.label {
margin: 0 3px;
}
}
.no-find {
display: flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
span {
margin-right: 20px;
}
}
.find {
display: flex;
flex: 1;
flex-direction: row;
overflow: auto;
.left {
display: flex;
flex-direction: column;
width: 300px;
.tool-btn {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.matchCase {
width: 30px;
height: 26px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.treeList {
margin-top: 3px;
height: 100%;
border-radius: 4px;
min-height: 20px;
overflow: auto;
width: 100%;
.leaf {
width: 100%;
}
.leaf-show {
color: black;
}
.leaf-hide {
color: #c7bbbb;
text-decoration: line-through;
}
&::-webkit-scrollbar {
width: 6px;
height: 6px;
background: #999;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
background-color: #333;
border-radius: 2px;
}
}
}
.right {
flex: 1;
background: #e5e9f2;
overflow-x: hidden;
overflow-y: overlay;
&::-webkit-scrollbar {
width: 6px;
background: #999;
border-radius: 2px;
height: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: #333;
border-radius: 2px;
}
}
}
}
</style>

View File

@@ -1,88 +0,0 @@
<template>
<div class="property-group">
<div class="header" @click="onClickHeader"
@mouseenter="showLogBtn=true"
@mouseleave="showLogBtn=false">
<div style="margin: 0 5px;">
<i v-if="fold" class="el-icon-caret-right"></i>
<i v-if="!fold" class="el-icon-caret-bottom"></i>
</div>
<div style="flex:1;">
{{ group.name }}
</div>
<el-button style="margin-right: 10px;"
v-show="showLogBtn"
type="success" icon="el-icon-chat-dot-round" @click.stop="onLog">
</el-button>
</div>
<div class="content" v-show="!fold">
<ui-prop v-for="(item, index) in group.data" :key="index"
:name="item.name" :value="item.value">
</ui-prop>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import {Prop} from "vue-property-decorator";
import {Group} from "@/devtools/data";
import UiProp from "@/devtools/ui/ui-prop.vue";
import Bus, {BusMsg} from "@/devtools/bus";
@Component({
name: "property-group",
components: {UiProp}
})
export default class PropertyGroup extends Vue {
private fold = false;
private showLogBtn = false;
@Prop({
default: () => {
return new Group("test")
}
})
group!: Group;
created() {
Bus.$on(BusMsg.FoldAllGroup, (b: boolean) => {
this.fold = b;
})
}
mounted() {
}
onLog() {
Bus.$emit(BusMsg.LogData, [this.group.id]);
}
onClickHeader() {
this.fold = !this.fold;
}
}
</script>
<style scoped lang="less">
.property-group {
.header {
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
user-select: none;
cursor: pointer;
border-bottom: 1px #6d6d6d solid;
background-color: #1da1f7;
}
.header:hover {
color: #6d6d6d;
}
.content {
padding: 0 5px;
}
}
</style>

View File

@@ -1,54 +0,0 @@
<template>
<div id="prop">
<property-group v-for="(group, index) in data.group" :key="index" :group="group"></property-group>
</div>
</template>
<script lang="ts">
import Vue from "vue"
import {Component, Prop, Watch} from "vue-property-decorator"
import UiProp from "./ui-prop.vue"
import {Group, NodeInfoData} from "@/devtools/data";
import PropertyGroup from "@/devtools/ui/property-group.vue";
import Bus, {BusMsg} from "@/devtools/bus";
@Component({
components: {PropertyGroup, UiProp},
})
export default class properties extends Vue {
@Prop({
default: () => {
return {};
}
})
data!: NodeInfoData;
@Watch("data")
watchData(newValue: NodeInfoData, oldValue: NodeInfoData) {
if (newValue.uuid !== oldValue.uuid) {
// 切换node全部展开属性
Bus.$emit(BusMsg.FoldAllGroup, false)
}
}
created() {
}
_evalCode(code: string) {
if (chrome && chrome.devtools) {
chrome.devtools.inspectedWindow.eval(code);
} else {
console.log(code);
}
}
}
</script>
<style scoped lang="less">
#prop {
}
</style>

View File

@@ -1,48 +0,0 @@
<template>
<div class="settings-prop">
<span class="label">{{ label }}</span>
<slot class="slot"></slot>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import {Prop} from "vue-property-decorator";
@Component({
name: "SettingsProp",
components: {}
})
export default class SettingsProp extends Vue {
@Prop()
label!: string;
created() {
}
mounted() {
}
}
</script>
<style scoped lang="less">
.settings-prop {
display: flex;
flex-direction: row;
align-items: center;
min-width: 300px;
margin: 2px 4px;
.label {
max-width: 80px;
min-width: 80px;
text-overflow: ellipsis;
white-space: nowrap;
}
.slot {
flex: 1;
}
}
</style>

View File

@@ -1,75 +0,0 @@
<template>
<div class="settings">
<settings-prop label="refresh">
<el-select v-model="refreshType" @change="onCommonSave" style="flex:1;">
<el-option v-for="item in refreshOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</settings-prop>
<settings-prop label="refresh time: " v-show="isRefreshAuto()">
<el-input-number style="flex:1;" :min=100 v-model="refreshTime" @change="onCommonSave"></el-input-number>
<span>ms</span>
</settings-prop>
<!-- <el-dropdown>-->
<!-- <span>refresh</span>-->
<!-- <el-dropdown-menu slot="dropdown">-->
<!-- <el-dropdown-item>auto</el-dropdown-item>-->
<!-- <el-dropdown-item>Manual</el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </el-dropdown>-->
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import {Prop} from "vue-property-decorator";
import {RefreshAuto, RefreshManual, settings} from "@/devtools/settings";
import SettingsProp from "@/devtools/ui/settings-prop.vue";
@Component({
name: "Settings",
components: {SettingsProp}
})
export default class Settings extends Vue {
name: string = "settings";
refreshOptions = [
{label: "auto", value: RefreshAuto},
{label: "manual", value: RefreshManual}
]
refreshType = "";
refreshTime = 500;
isRefreshAuto() {
return this.refreshType === RefreshAuto;
}
created() {
this.refreshType = settings.data?.refreshType || "";
this.refreshTime = settings.data?.refreshTime || 500;
}
onChangeRefreshType() {
}
onCommonSave() {
if (settings.data) {
settings.data.refreshType = this.refreshType;
settings.data.refreshTime = this.refreshTime;
settings.save();
}
}
mounted() {
}
}
</script>
<style scoped lang="less">
.settings {
}
</style>

View File

@@ -1,58 +0,0 @@
<template>
<div class="ui-divider" :class="{'ui-divider-move':isMove}"
@mousedown="onDividerMouseDown">
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import {Prop, Emit} from "vue-property-decorator";
@Component({
name: "ui-divider",
components: {}
})
export default class UiDivider extends Vue {
private isMove = false;
created() {
}
mounted() {
}
@Emit("move")
onDividerMove(event: MouseEvent) {
return event;
}
onDividerMouseDown(event: MouseEvent) {
this.isMove = true;
document.addEventListener("mousemove", this.onDividerMove);
const self = this;
function onMouseUp() {
self.isMove = false;
document.removeEventListener("mouseup", onMouseUp);
document.removeEventListener("mousemove", self.onDividerMove);
}
document.addEventListener("mouseup", onMouseUp)
}
}
</script>
<style scoped lang="less">
.ui-divider {
width: 3px;
height: 100%;
cursor: ew-resize;
background-color: grey;
}
.ui-divider-move {
background-color: #eaa530;
}
</style>

View File

@@ -1,542 +0,0 @@
<template>
<div id="ui-prop">
<div class="normal-data" style="display: flex;flex-direction: row;align-items: center;min-height: 30px;margin: 0;">
<div @mousedown="onPropNameMouseDown" class="key"
@click="onClickFold"
:style="{'cursor':isArrayOrObject()?'pointer':''}"
>
<i class="data-arrow"
v-if="arrow"
:class="fold?'el-icon-caret-right':'el-icon-caret-bottom'"
:style="{'visibility':isArrayOrObject()?'visible':'hidden','margin-left':indent*10+'px'}">
</i>
<div class="text" ref="propText">
<el-popover placement="top" trigger="hover" :disabled="!isShowTooltip()">
<div>{{ name }}</div>
<span slot="reference">{{ name }}</span>
</el-popover>
</div>
</div>
<div class="value">
<div v-if="isInvalid()" class="invalid">
{{ value.data }}
</div>
<el-input v-if="isString()" v-model="value.data"
:disabled="value.readonly"
@change="onChangeValue">
</el-input>
<el-input v-if="isText()"
type="textarea"
:autosize="{minRows:3,maxRows:5}"
placeholder="请输入内容"
:disabled="value.readonly"
@change="onChangeValue"
v-model="value.data">
</el-input>
<el-input-number v-if="isNumber()"
style="width: 100%;text-align: left"
v-model="value.data"
:step="step"
:disabled="value.readonly"
@change="onChangeValue"
controls-position="right"
></el-input-number>
<div v-if="isVec2()||isVec3()" class="vec">
<ui-prop v-for="(vec, index) in value.data"
:key="index"
:arrow="false"
:value="vec.value"
:name="vec.name">
</ui-prop>
</div>
<el-select v-model="value.data"
:disabled="value.readonly"
v-if="isEnum()" style="width: 100%;"
@change="onChangeValue">
<el-option v-for="(opt, index) in value.values"
:key="index"
:label="opt.name"
:value="opt.value">
</el-option>
</el-select>
<el-checkbox v-model="value.data"
v-if="isBool()"
:disabled="value.readonly"
@change="onChangeValue">
</el-checkbox>
<div class="color" v-if="isColor()">
<el-color-picker style="position: absolute;"
:disabled="value.readonly"
v-model="value.data" @change="onChangeValue">
</el-color-picker>
<div class="hex" :style="{color:colorReverse(value.data)}">{{ value.data }}</div>
</div>
<!-- <div v-if="isArrayOrObject()" class="array-object">-->
<!-- <div class="text">-->
<!-- </div>-->
<!-- <el-button @click="onShowValueInConsole">log</el-button>-->
<!-- </div>-->
<div v-if="isImage()" class="image-property">
<el-popover v-if="isImage()" placement="top" trigger="hover">
<div
style="width: 100%;height: 100%;display: flex;flex-direction: row;align-items: center;justify-content: center;">
<img :src="value.data" alt="图片" style="max-width: 100px;max-height: 100px;object-fit: contain;">
</div>
<img :src="value.data" slot="reference" style="height: 36px;" alt="图片">
</el-popover>
<div style="flex:1;display: flex; flex-direction: row-reverse;">
<el-button @click="onShowValueInConsole">log</el-button>
</div>
</div>
<div v-if="isEngine()" class="engine">
<div class="head">
<i class="icon" :class="getEngineTypeIcon()"></i>
<div class="type">{{ value.engineType }}</div>
</div>
<div class="name">{{ value.engineName }}</div>
<el-button @click="onPlaceInTree" type="primary" icon="el-icon-place"></el-button>
</div>
<div v-if="isObject()&&fold" class="objectDesc">
{{ value.data }}
</div>
<div v-if="isArray()" class="array">
Array({{ value.data.length }})
</div>
<div class="slot" v-if="false">
<slot></slot>
</div>
</div>
</div>
<div v-if="isArrayOrObject()">
<div v-show="!fold&&subData" style="display: flex;flex-direction: column;">
<ui-prop v-for="(arr,index) in subData"
:key="index"
:indent="indent+1"
:value="arr.value"
:name="getName(isArray(),arr)"
>
</ui-prop>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue"
import {Component, Prop, Watch} from "vue-property-decorator"
import {DataType, EngineData, Info, Property} from "../data"
import {connectBackground} from "@/devtools/connectBackground";
import {Msg} from "@/core/types";
import Bus, {BusMsg} from "../bus"
@Component({
name: "UiProp",
components: {}
})
export default class UiProp extends Vue {
@Prop({default: ""})
name: string | undefined;
@Prop({default: 0})
indent!: number;
@Prop({default: true})
arrow!: boolean;
@Prop()
value!: Info;
@Watch("value")
watchValue() {
this.fold = true;
if (this.isArray()) {
this.subData = this.value.data;
} else {
this.subData = null;
}
}
isInvalid() {
return this.value && (this.value.type === DataType.Invalid);
}
isString() {
return this.value && (this.value.type === DataType.String);
}
isText() {
return this.value && (this.value.type === DataType.Text);
}
isNumber() {
return this.value && (this.value.type === DataType.Number);
}
isVec2() {
return this.value && (this.value.type === DataType.Vec2);
}
isVec3() {
return this.value && (this.value.type === DataType.Vec3);
}
isEnum() {
return this.value && (this.value.type === DataType.Enum);
}
isBool() {
return this.value && (this.value.type === DataType.Bool);
}
isColor() {
return this.value && (this.value.type === DataType.Color);
}
isArrayOrObject() {
return this.value && (this.value.type === DataType.Array || this.value.type === DataType.Object)
}
isObject() {
return this.value && (this.value.type === DataType.Object)
}
isArray() {
return this.value && (this.value.type === DataType.Array)
}
isImage() {
return this.value && (this.value.type === DataType.Image)
}
isImageValid() {
return !!this.value.data;
}
isEngine() {
return this.value && (this.value.type === DataType.Engine)
}
onPlaceInTree() {
Bus.$emit(BusMsg.ShowPlace, this.value);
}
created() {
}
mounted() {
this.watchValue();
}
isShowTooltip() {
const el: HTMLDivElement = this.$refs.propText as HTMLDivElement;
if (el) {
if (el.scrollWidth > el.offsetWidth) {
// 出现了省略号
return true;
}
}
return false;
}
getEngineTypeIcon() {
const value = this.value as EngineData;
switch (value.engineType) {
case "cc_Sprite": {
return "el-icon-picture-outline";
}
case "cc_Label": {
return "el-icon-third-text";
}
case "cc_Node": {
return "el-icon-third-node"
}
}
return "el-icon-third-unknow";
}
getName(isArray: boolean, arr: UiProp) {
const type = arr.value.type;
if (isArray) {
return `[${arr.name}]`
} else {
return arr.name;
}
}
private fold = true;
private subData: Property[] | null = null;
onClickFold() {
if (this.isObject() && this.fold && !this.subData) {
// 请求object的item数据
Bus.$emit(BusMsg.RequestObjectData, this.value, (info: Property[]) => {
this.fold = false;
this.subData = info;
})
} else {
this.fold = !this.fold;
}
}
onShowValueInConsole() {
if (Array.isArray(this.value.path)) {
let uuid = this.value.path[0];
let key = this.value.path[1]; // todo 暂时只支持一级key
if (uuid && key) {
chrome.devtools.inspectedWindow.eval(`window.CCInspector.logValue('${uuid}','${key}')`)
}
}
}
onChangeValue() {
if (!this.value.readonly) {
connectBackground.postMessageToBackground(Msg.SetProperty, this.value);
}
}
@Prop({default: 1})
step: number | undefined;
clientX: number = 0;
onPropNameMouseDown(event: MouseEvent) {
document.addEventListener("mousemove", this._onMouseMove);
document.addEventListener("mouseup", this._onMouseUp);
document.addEventListener("onselectstart", this._onSelect);
}
colorReverse(OldColorValue: string) {
OldColorValue = "0x" + OldColorValue.replace(/#/g, "");
var str = "000000" + (0xFFFFFF - parseInt(OldColorValue)).toString(16);
return "#" + str.substring(str.length - 6, str.length);
}
_onSelect() {
return false;
}
_onMouseMove(event: MouseEvent) {
let x = event.clientX;
let calcStep = this.step || 0;
if (x > this.clientX) {
calcStep = Math.abs(calcStep);
} else {
calcStep = -Math.abs(calcStep);
}
this.$emit("movestep", calcStep);
this.clientX = x;
}
_onMouseUp(event: MouseEvent) {
document.removeEventListener("mousemove", this._onMouseMove);
document.removeEventListener("mouseup", this._onMouseUp);
document.removeEventListener("onselectstart", this._onSelect);
}
};
</script>
<style scoped lang="less">
#ui-prop {
min-height: 30px;
margin: 1px 0;
display: flex;
flex-direction: column;
justify-content: center;
.normal-data {
margin: 0;
min-height: 30px;
overflow: hidden;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
.key {
flex: 1;
float: left;
text-align: left;
display: flex;
flex-direction: row;
align-items: center;
min-width: 90px;
.data-arrow {
width: 20px;
height: 16px;
font-size: 16px;
cursor: pointer;
}
.text {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
user-select: none;
font-size: 12px;
margin: 3px;
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
.value {
flex: 3;
text-align: left;
height: 100%;
overflow: hidden;
min-width: 400px;
.color {
position: relative;
height: 30px;
.hex {
line-height: 30px;
position: relative;
text-align: center;
user-select: none;
pointer-events: none;
}
}
.invalid {
color: grey;
}
.objectDesc {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
user-select: none;
}
.array {
display: flex;
flex-direction: column;
color: red;
}
.engine {
display: flex;
flex-direction: row;
border: solid #409EFF 1px;
border-radius: 5px;
align-items: center;
align-content: center;
.head {
background-color: cornflowerblue;
height: 28px;
align-items: center;
align-content: center;
display: flex;
flex-direction: row;
.icon {
font-size: 20px;
width: 20px;
margin-left: 5px;
}
.type {
display: flex;
align-content: center;
align-items: center;
margin: 0 5px;
}
}
.name {
flex: 1;
height: 28px;
padding-left: 5px;
background-color: gold;
display: flex;
align-items: center;
align-content: center;
}
}
.vec {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
#ui-prop {
margin: 0 10px;
flex: 1;
.normal-data {
.value {
min-width: 50px;
}
.key {
min-width: unset;
display: block;
margin-right: 5px;
flex: unset;
}
}
}
#ui-prop:first-child {
margin-left: 0;
}
#ui-prop:last-child {
margin-right: 0;
}
}
.array-object {
flex: 1;
max-width: 100%;
overflow: hidden;
display: flex;
flex-direction: row;
align-items: center;
.text {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.image-property {
display: flex;
flex-direction: row;
align-content: center;
align-items: center;
height: 36px;
}
.slot {
display: flex;
width: 100%;
}
}
}
}
</style>

View File

@@ -1,42 +0,0 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}

File diff suppressed because it is too large Load Diff