This commit is contained in:
许彦峰 2019-03-15 10:08:39 +08:00
commit e7adf25ccf
75 changed files with 25883 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,6 @@
{
"presets": [
["env", { "modules": false }],
"stage-3"
]
}

View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

12
CocosCreatorInspector/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
.DS_Store
node_modules/
npm-debug.log
yarn-error.log
# Editor directories and files
.idea
*.suo
/dist
*.ntvs*
*.njsproj
*.sln

View File

@ -0,0 +1,42 @@
# cocos-creator-inspector
## 插件说明
本插件为chrome插件,设计该插件的初衷是方便在chrome环境下运行时调试creator游戏.
开发过程中难免翻车,为什么添加的图片看不到,为什么图片的位置有偏差,为什么.....
总之,身为程序员的我们每天都在思考:我错在了哪里?如果能在运行游戏的时候,查看游戏的节点树多好啊
so...  
![](../doc/CreatorInspector/icon.png)  
cc-inspector 插件顺势而生, 你需要的我来完成
目前插件支持运行时查看场景的节点树信息,比如坐标,缩放,颜色,透明度,附加的组件等等,其中在节点的可视状态属性里面,提供了**显示/隐藏**的操作按钮,该操作会直接影响到运行时节点的可视状态,惊不惊喜,意不意外,还有这种令人窒息的操作?
![](http://imgsrc.baidu.com/forum/pic/item/2cdeec1190ef76c6371dd3dd9616fdfaae516778.jpg)
目前版本功能虽然单薄,但是实用性非常高,在后续版本中,会陆陆续续开发新功能,比如修改节点的坐标,缩放等等属性,当然还有一个最重要的核心功能,就是节点附加的组件,如果能动态修改组件属性,执行组件的function,简直是如虎添翼啊!
好吧,总之**这是一个神奇的插件**,更多好玩的功能有待发掘,希望这只 **猫头鹰** 能作为游戏开发之旅的火眼金睛,披荆斩棘,让bug无处可藏!
### 论坛帖子地址
http://forum.cocos.com/t/chrome-creator/55669
## 插件安装
- [安装包下载](http://7xq9nm.com1.z0.glb.clouddn.com/ccInspector_v1.1.zip)
- [点击查看如何安装](../doc/CreatorInspector/install/README.md)
## 如何使用
- 在chrome浏览器中运行creator开发的游戏
- F12打开**开发者工具**你会发现多了一个cocos选项
![](../doc/CreatorInspector/scene1.png)
- 点击**刷新**按钮即可查看游戏运行时的节点目录树,左侧为节点,右侧为节点信息
![](../doc/CreatorInspector/scene3.png)
- 节点信息中有控制显示隐藏的按钮,点击该按钮将直接影响运行中的游戏效果
![](../doc/CreatorInspector/showHideNode.gif)
- 节点属性列表中显示了改节点上挂的所有组件,目前仅仅支持查看组件名称,并不能实时编辑
## 开发中使用到的技术
- chrome 插件开发
- vue+webpack
- element-ui
- cocos creator
## 寻求帮助
因为本人不是web前端开发出身,而这个插件使用了比较多的web前端技术,所以急切的寻求一个web前端小伙伴,共同完善这个插件,这也是本人将这个插件开源的一个重要原因
## 联系方式
QQ群**224756137**
### manifest.json
// 开发参考http://open.chrome.360.cn/extension_dev/overview.html
// 字段说明参考http://open.chrome.360.cn/extension_dev/manifest.html

View File

@ -0,0 +1,7 @@
# 版本更新说明
## v1.2
### 新功能
- popup页面增加**支持作者**功能,还望各位打赏一下喽!
![](../doc/CreatorInspector/package/4.png)
- 优化了很多交互,详细见下图
![](../doc/CreatorInspector/package/5.gif)

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKA+h2e8dPlzt3
RRXtRZuY3s/dhaxIz7TbiUQymqwi8vhUx3p9LzBbQSK3qOjJGifsrkf2C6TpmvWZ
lpTbDdl4hz5Z5Ljrt2GtehEGlb/IxbiuEuAKfznrljMKwDHdp809hmc6XtwZdvW0
B/0yfRtUKZ+9HH6rvQBtcDaZ4fAkX2BIcqw/j5CIzW+IyziswnFoMQkC68Cu2vS1
mNSU8foYlxQAsmttbzr/PGZkrOL92oeVoJJfPfR7eBP8JhSbVJ6GGdhw72SQTByY
5e9Pl94veUdhwryH/xtsb27YrNO8EPbwMyJvu+LYp2Im5IOC3HvChB/XpfnnqfgZ
F0aCvOIVAgMBAAECggEAIwlre4U7S8AQhb6bL3RHqMtYJPUGrPgtR3g2tkoiOcuH
K3kPcv/ItMMGyPDIMvzQ2NlfTLq3RvbjytgViCqOQbu/IisrsWI0VDicFFbLlQBJ
6BMI/XkUbBo4TxCHdYihbZ7Ob469QMNjmO5byTJul3nCpTN4esPEe7afGbBYjI4Z
SffhXI/eF5CaBEqsEOAwDunzFh3E7bE6E/JkGOU29xLQy/eryhmD1O3Cnf2i3q29
TooHe0hgh9lkVGt3sZJLp/sH2EYda5W95/Ji1yWaJ9p4M016UPLDGFn4hJvmdGfY
VVfQ47sCvvJ26zHt/+kZzreXt6YpAlKGmb6ibjVT0QKBgQDmvZtLgwmgvqvJNgx/
/b+NDq0mIWX60ASVT3wYiqidtu7xmUU6hUWFumtJB8MWELRUJ7kkzd3PfbEVzX9O
wIo4ifYWrhxxMh8kmoGmpKWZ/MUtH7RN0NXkmcPAKaBftzjooI0VB97KArSuBGeX
2Tphd+VHMPiKMaI3STa2xKo5eQKBgQDgIUlg4lVATvPWY2Vg6b5qEtzLCiIwgNZD
5Swx8wlYJApm94OJ5dMzjYFt/5vdeSJfV3ESnZ6gKSsW3vX1dGeFLvIiA7v5OBv5
0FO2VAXR+iLJje4ZWKTwhzgoM4EYSjS62bUGQ90tJt20YP2nXgYEoQ1agmWTSRPn
3BFXRXLifQKBgQDMnO8Nc1IiXXLwpyFGjrpCV/VrjspkM/scfLPK/4qu8P3K+OPP
FUelYr6osF1rP7zps6AW5wf/a7KRZv2x1EO+B3lWe2d1acD8MJcwM2k2uFQRw7+c
EcjbQw+3ZDJ3Ln8kqtrw/12tPeEDP5ytp1CCBlQnYWHFCmaTKDWAtb1N4QKBgFfo
lmhavcdYcElReQz3AUmHlnRIyDov/lppA9mfkrWwhSf3wu8OZrVctjxXumG2xmWQ
3XfIvNPi8dSppN0eSBAz5qKyxkKs4EQukvb7o8DFFGnrskzcuOzijIMwGF1XlbEH
/Pm1GoZALUs3k6XWuhOMu7kZVg/b5OPXLDIHulTdAoGBAIhFZhcl1/W7ANlFvYy/
6OuxjHYCqFgOa4qYz9ia2X9UnK+SOqTLplZtbbYag4OIxvGZAQ3+Ys6Tm0Y4IySk
qB8d1aSzJelu8feqJtWf9QZFbHvdN+orRQkhPwydC0m/ujefy/+v/edCXv9kWCdj
mw7DaZnzhqap9CnBXnYXFP+5
-----END PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,54 @@
let gulp = require('gulp');
let path = require('path');
let fse = require('fs-extra');
let fs = require('fs');
let shell = require('gulp-shell');
gulp.task("packageCrx", function () {
let pem = path.join(__dirname, "bin/dist.pem");
if (!fs.existsSync(pem)) {
console.log("签名文件不存在:" + pem);
return;
}
let dist = path.join(__dirname, "dist");
if (!fs.existsSync(dist)) {
console.log("打包目录不存在: " + dist);
console.log("发布失败!");
return;
}
let exec = require('child_process').exec;
let packageCmd = "chrome.exe --pack-extension=" + dist + " --pack-extension-key=" + pem;
console.log("------------------------------------------------");
console.log("执行打包命令:\n " + packageCmd);
console.log("------------------------------------------------");
let ret = exec(packageCmd);
ret.stdout.on('data', function () {
console.log("data");
});
ret.stdout.on('close', function (err, a, b, c) {
let file = path.join(__dirname, "dist.crx");
if (fs.existsSync(file)) {
let desFile = path.join(__dirname, "bin/cc-inspector.crx");
if (fs.existsSync(desFile)) {
fse.removeSync(desFile);
}
fse.move(file, desFile, function (err) {
if (!err) {
console.log("发布插件安装包文件成功!");
console.log("存放路径: " + desFile);
} else {
console.log(err);
}
})
} else {
console.log("文件不存在: " + file);
console.log("发布失败!");
}
});
});
gulp.task("default", function () {
console.log("hello gulp!");
});

10133
CocosCreatorInspector/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
{
"name": "cocos-inspector",
"description": "Cocos Creator Inspector",
"version": "1.0.0",
"author": "xu_yanfeng",
"license": "MIT",
"private": true,
"scripts": {
"dev-server": "webpack-dev-server --inline --progress --open --hot --port 8888",
"dev-index": "cross-env NODE_ENV=development webpack-dev-server --open http://localhost:8082/index.html --inline --progress --hot --port 8082",
"dev-popup": "cross-env NODE_ENV=development webpack-dev-server --open http://localhost:8083/popup.html --inline --progress --hot --port 8083",
"dev-inspector": "cross-env NODE_ENV=development webpack-dev-server --open http://localhost:8084/devInspector.html --inline --progress --hot --port 8084",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
"dependencies": {
"fs": "0.0.1-security",
"fs-extra": "^5.0.0",
"gulp": "^3.9.1",
"gulp-shell": "^0.6.5",
"node-sass": "^4.7.2",
"path": "^0.12.7",
"sass-loader": "^6.0.6",
"url-loader": "^0.6.2",
"vue": "^2.4.4",
"vue-awesome": "^2.3.4"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"clean-webpack-plugin": "^0.1.17",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"element-ui": "^2.0.11",
"file-loader": "^1.1.4",
"html-webpack-plugin": "^2.30.1",
"style-loader": "^0.19.0",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,29 @@
chrome.extension.onConnect.addListener(function (port) {
console.log("backgroundScripts connect!");
let extensionListener = function (message, sender, sendResponse) {
if (message.tabId && message.content) {
if (message.action === 'code') {
console.log("执行code");
chrome.tabs.executeScript(message.tabId, {code: message.content});
} else if (message.action === 'script') {
console.log("执行script");
chrome.tabs.executeScript(message.tabId, {file: message.content});
} else {
console.log("执行other");
chrome.tabs.sendMessage(message.tabId, message, sendResponse);
}
} else {
port.postMessage(message);
}
sendResponse(message);
};
chrome.extension.onMessage.addListener(extensionListener);
port.onDisconnect.addListener(function (port) {
chrome.extension.onMessage.removeListener(extensionListener);
});
});
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
return true;
});

View File

@ -0,0 +1,21 @@
window.addEventListener('message', function (event) {
let data = event.data;
// console.log("[contentScripts] " + JSON.stringify(data));
chrome.extension.sendMessage(data);
}, false);
let gameCanvas = document.querySelector("#GameCanvas");
if (gameCanvas) {
// console.log('find GameCanvas element');
// gameCanvas.addEventListener('click', function () {
// console.log("click canvas");
// });
// gameCanvas.style.display = 'none';
} else {
// console.log("can't find GameCanvas element");
chrome.extension.sendMessage({type: 0, msg: "no creator game!"});
}

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Dev</title>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,52 @@
// 检查游戏是否为cocos游戏
// var cc={};
// if (typeof cc === "undefined") {
// console.log("该html不是cocos游戏,无法调试!");
// chrome.devtools.panels.elements.createSidebarPane("Creator Properties", function (sidebar) {
// // console.log("[Cocos Creator Inspector] CreateSidebarPane");
// // sidebar.setObject({ some_data: "Some data to show" });
// sidebar.setPage("devNoGame.html");
// });
// chrome.devtools.panels.create(
// "Cocos",
// "static/images/icon48.png",
// "devNoGame.html", function (panel) {
// // console.log("[Cocos Creator Inspector] Dev Panel Created!");
// });
//
// } else {
//
// }
chrome.devtools.panels.elements.createSidebarPane('My SliderBar', function (sidebar) {
sidebar.setObject({some_data: "some data to show!"});
});
chrome.devtools.panels.create(
"Cocos",
"static/images/icon48.png",
"devInspector.html",
function (panel) {
console.log("[Cocos Creator Inspector] Dev Panel Created!");
panel.onShown.addListener(function (window) {
console.log("panel show");
});
panel.onHidden.addListener(function (window) {
console.log("panel hide");
});
panel.onSearch.addListener(function (action, query) {
console.log("panel search!");
return false;
});
}
);
// (function () {
// var t = window.setInterval(function () {
// egret && egret.devtool &&
// egret.devtool.start &&
// (window.clearInterval(t) || egret.devtool.start());
// console.log("waiting")
// }, 100);
// egret && egret.devtool && egret.devtool.start && (window.clearInterval(t) || egret.devtool.start());
// })();

View File

@ -0,0 +1,219 @@
<template>
<div id="app">
<el-button type="success" class="el-icon-refresh" size="mini" @click="onBtnClickUpdatePage">刷新</el-button>
<!--<el-button type="success" size="mini" @click="onTestData">测试</el-button>-->
<!--<el-button type="success" size="mini" @click="onBtnClickTest">test</el-button>-->
<div v-show="isShowDebug">
<el-row>
<el-col :span="8">
<div class="grid-content treeList">
<el-tree :data="treeData"
:props="defaultProps"
:expand-on-click-node="false"
@node-click="handleNodeClick"></el-tree>
</div>
</el-col>
<el-col :span="16">
<div class="grid-content bg-purple-light treeInfo">
<NodeBaseProperty v-bind:itemData="treeItemData"></NodeBaseProperty>
<SceneProperty v-show=" treeItemData.type === 'cc_Scene'"></SceneProperty>
<ComponentsProperty v-bind:components="treeItemData.components"></ComponentsProperty>
</div>
</el-col>
</el-row>
</div>
<div v-show="!isShowDebug">
未发现cocos creator的游戏!
</div>
</div>
</template>
<script>
import injectScript from '../injectScript.js'
export default {
name: "app",
data() {
return {
isShowDebug: false,
treeItemData: {},
treeData: [],
treeDataMap: {},
}
},
created() {
if (chrome && chrome.extension) {
} else {
this.isShowDebug = true;
this.onTestData();
return;
}
let backgroundPageConnection = chrome.extension.connect({
name: btoa("for" + String(chrome.devtools.inspectedWindow.tabId))
});
backgroundPageConnection.onMessage.addListener(function (message) {
if (message !== null) {
let msgType = {
nodeInfo: 2,//
nodeListInfo: 1,//
notSupport: 0,//
};
if (message.type === msgType.nodeListInfo) {//
this.isShowDebug = true;
// let str = JSON.stringify(message.msg);
// console.log("onMessage: " + str);
this._updateView(message.msg);
} else if (message.type === msgType.notSupport) {//
this.isShowDebug = false;
} else if (message.type === msgType.nodeInfo) {
this.isShowDebug = true;
this.treeItemData = message.msg;
}
}
}.bind(this));
window.addEventListener('message', function (event) {
console.log("on vue:" + JSON.stringify(event.data));
console.log("on vue:" + JSON.stringify(event));
}, false);
},
methods: {
onTestData() {
let testData = {
"type": "cc_Node",
"uuid": "5cUWX4Yh1MipGk+ssnZ/fL",
"name": "Canvas",
"x": 960,
"y": 540.4931506849315,
"zIndex": 0,
"childrenCount": 6,
"children": [],
"width": 1920,
"height": 1080.986301369863,
"color": "#fff85f",
"opacity": 255,
"rotation": 0,
"rotationX": 0,
"rotationY": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"scaleX": 1,
"scaleY": 1,
"skewX": 0,
"skewY": 0,
"components": [
{
"uuid": "Comp.931",
"type": "cc_Canvas",
"name": "Canvas<Canvas>"
},
{
"uuid": "Comp.932",
"type": "HotUpdateScene",
"name": "Canvas<HotUpdateScene>"
}],
"active": true
};
this.treeItemData = testData;
},
handleNodeClick(data) {
// todo
// console.log(data);
let uuid = data.uuid;
if (uuid !== undefined) {
let code = "window.getNodeInfo('" + uuid + "')";
chrome.devtools.inspectedWindow.eval(code);
}
},
_updateView(data) {
//
this.treeData = [];
let sceneData = data.scene;
if (sceneData) {
// scene info
let dataRoot = {
type: sceneData.type, uuid: sceneData.uuid,
label: sceneData.name, children: []
};
this.treeData.push(dataRoot);
this.handleNodeClick(dataRoot);
// scene children info
for (let k in sceneData.children) {
let itemSceneData = sceneData.children[k];
// let sceneItem = {uuid: itemSceneData.uuid, label: itemSceneData.name, children: []};
let sceneItem = {};
dealChildrenNode(itemSceneData, sceneItem);
this.treeData[0].children.push(sceneItem);
}
}
// TODO
if (JSON.stringify(this.treeData) === "[]") {//
} else {//
}
function dealChildrenNode(rootData, obj) {
obj['data'] = rootData;
obj['uuid'] = rootData.uuid;
obj['label'] = rootData.name;
obj['type'] = rootData.type;
obj['children'] = [];
let rootChildren = rootData.children;
for (let k in rootChildren) {
let itemData = rootChildren[k];
let item = {};
dealChildrenNode(itemData, item);
obj.children.push(item);
}
}
},
_getInjectScriptString() {
let code = injectScript.toString();
let array = code.split('\n');
array.splice(0, 1);//
array.splice(-1, 1);//
let evalCode = "";
for (let i = 0; i < array.length; i++) {
evalCode += array[i] + '\n';
}
// console.log(evalCode);
return evalCode;
},
onBtnClickUpdatePage() {
let code = this._getInjectScriptString();
chrome.devtools.inspectedWindow.eval(code, function () {
console.log("刷新成功!");
});
},
}
}
</script>
<style scoped>
.treeList {
height: 100%
}
.treeInfo {
height: 100%
}
.bg-purple {
background: #d3dce6;
}
.grid-content {
border-radius: 4px;
min-height: 20px;
}
.bg-purple-light {
background: #e5e9f2;
}
body span h1 h2 h3 {
font-family: BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, 'SourceHanSansCN-Normal', Arial, sans-serif
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<div id="app">
<div>
<div>
<h4 @click="onClickComp" style="margin-top: 5px;margin-bottom: 1px;font-weight: bold;cursor: pointer">挂载组件:</h4>
<hr style="margin-bottom: 2px;margin-top: 2px;"/>
</div>
<div v-show="isShowComp">
<ui-prop :name="index" track-by="$index" v-for="(comp,index) in components" :key="index">
<span>{{comp.type}}</span>
</ui-prop>
</div>
</div>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
isShowComp: true,
}
},
methods: {
onClickComp() {
this.isShowComp = !this.isShowComp;
}
},
props: [
'components'
]
}
</script>
<style scoped>
span {
color: #fd942b;
}
</style>

View File

@ -0,0 +1,282 @@
<template>
<div id="app">
<div>
<ui-prop name="uuid">
<span> {{itemData.uuid}}</span>
</ui-prop>
<ui-prop name="name">
<span> {{itemData.name}}</span>
</ui-prop>
<!--坐标-->
<ui-prop name="Position">
<div style="float: left;width: 100%;">
<ui-prop name="X" style="width: 50%;float: left; cursor: ew-resize;"
@movestep="changePositionActionX"
step="10">
<!--<span>{{itemData.x}}</span>-->
<input class="myInput"
@change="changePosition"
placeholder="itemData.x"
v-model="itemData.x">
</ui-prop>
<ui-prop name="Y" style="width: 50%;float:left;cursor: ew-resize;"
@movestep="changePositionActionY"
step="10">
<!--<span>{{itemData.y}}</span>-->
<input class="myInput"
@change="changePosition"
placeholder="itemData.y"
v-model="itemData.y">
</ui-prop>
</div>
</ui-prop>
<!--旋转-->
<!--rotationX, rotationY暂时舍弃显示-->
<ui-prop name="Rotation">
<span> {{itemData.rotation}}</span>
<!--<input class="myInput"-->
<!--@change="changeRotation"-->
<!--placeholder="itemData.rotation"-->
<!--v-model="itemData.rotation"-->
<!--style="width: 98%">-->
</ui-prop>
<!--缩放-->
<ui-prop name="Scale">
<div style="float: left;width: 100%;">
<ui-prop name="X" style="width: 50%;float: left;">
<span>{{itemData.scaleX}}</span>
</ui-prop>
<ui-prop name="Y" style="width: 50%;float:left;">
<span>{{itemData.scaleY}}</span>
</ui-prop>
</div>
</ui-prop>
<!--锚点-->
<ui-prop name="Anchor">
<div style="float: left;width: 100%;">
<ui-prop name="X" style="width: 50%;float: left;">
<span>{{itemData.anchorX}}</span>
</ui-prop>
<ui-prop name="Y" style="width: 50%;float:left;">
<span>{{itemData.anchorY}}</span>
</ui-prop>
</div>
</ui-prop>
<!--尺寸-->
<ui-prop name="Size">
<div style="float: left;width: 100%;">
<ui-prop name="W" style="width: 50%;float: left;cursor: ew-resize;"
@movestep="changeSizeActionWidth"
step="10">
<!--<span>{{itemData.width}}</span>-->
<input class="myInput"
@change="changeSize"
placeholder="itemData.width"
v-model="itemData.width">
</ui-prop>
<ui-prop name="H" style="width: 50%;float:left;cursor: ew-resize;"
@movestep="changeSizeActionHeight"
step="10">
<!--<span>{{itemData.height}}</span>-->
<input class="myInput"
@change="changeSize"
placeholder="itemData.height"
v-model="itemData.height">
</ui-prop>
</div>
</ui-prop>
</ui-prop>
<!--透明度-->
<ui-prop name="Opacity">
<span>{{itemData.opacity}}</span>
</ui-prop>
<!--斜切-->
<ui-prop name="Skew">
<div style="float: left;width: 100%;">
<ui-prop name="X" style="width: 50%;float: left;">
<span>{{itemData.skewX}}</span>
</ui-prop>
<ui-prop name="Y" style="width: 50%;float:left;">
<span>{{itemData.skewY}}</span>
</ui-prop>
</div>
</ui-prop>
</div>
<ui-prop name="zIndex">
<span>{{itemData.zIndex}}</span>
</ui-prop>
<ui-prop name="childrenCount">
<span>{{itemData.childrenCount}}</span>
</ui-prop>
<!--节点状态-->
<ui-prop name="active">
<p v-if="itemData.active" style="margin: 0;display: flex;align-items: center;flex-wrap: wrap;">
<input type="checkbox"
style="width: 20px;height: 20px;"
:checked="itemData.active"
@click="onBtnClickNodeHide">
隐藏节点
</p>
<p v-if="!itemData.active" style="margin: 0;display: flex;align-items: center;flex-wrap: wrap;">
<input type="checkbox"
style="width: 20px;height: 20px;"
:checked="itemData.active"
@click="onBtnClickNodeShow"
>
显示节点
</p>
</ui-prop>
<!--颜色-->
<ui-prop name="color">
<div style="float: left;width: 100%;height: 100%;">
<div style="float: left;width: 50%; height: 100%;">
<el-color-picker v-model="itemData.color" size="mini"
style="margin: 0;display: flex;align-items: center;flex-wrap: wrap;"
@change="changeColor"></el-color-picker>
</div>
<div style="float: left;width: 50%;">
<span>{{itemData.color}}</span>
</div>
</div>
</ui-prop>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {}
},
methods: {
changeSizeActionWidth(step) {
let w = parseFloat(this.itemData.width);
this.itemData.width = w + step;
this.changeSize();
},
changeSizeActionHeight(step) {
let h = parseFloat(this.itemData.height);
this.itemData.height = h + step;
this.changeSize();
},
changePositionActionX(step) {
let x = parseFloat(this.itemData.x);
this.itemData.x = x + step;
this.changePosition();
},
changePositionActionY(step) {
let y = parseFloat(this.itemData.y);
this.itemData.y = y + step;
this.changePosition();
},
changePosition() {
// console.log("change changePositionX:" + this.itemData.x);
// console.log("change changePositionY:" + this.itemData.y);
this._evalCode(
"window.pluginSetNodePosition(" +
"'" + this.itemData.uuid + "'," +
"'" + this.itemData.x + "'," +
"'" + this.itemData.y + "'" +
")");
this._freshNode();
},
changeSize() {
// console.log("change width:" + this.itemData.width);
// console.log("change height:" + this.itemData.height);
this._evalCode(
"window.pluginSetNodeSize(" +
"'" + this.itemData.uuid + "'," +
"'" + this.itemData.width + "'," +
"'" + this.itemData.height + "'" +
")");
this._freshNode();
},
changeRotation() {
console.log("change rotation:" + this.itemData.rotation);
this._evalCode(
"window.pluginSetNodeRotation('" +
this.itemData.uuid + "','" +
this.itemData.rotation + "')");
this._freshNode();
},
changeColor() {
let color = this.itemData.color;
console.log("color:" + color);
this._evalCode(
"window.pluginSetNodeColor('" +
this.itemData.uuid + "','" +
color + "');");
this._freshNode();
},
onBtnClickNodeHide() {
let uuid = this.itemData.uuid;
if (uuid !== undefined) {
let code = "window.pluginSetNodeActive('" + uuid + "', 0);";
this._evalCode(code);
this._freshNode();
}
},
onBtnClickNodeShow() {
let uuid = this.itemData.uuid;
if (uuid !== undefined) {
let code = "window.pluginSetNodeActive('" + uuid + "', 1);";
this._evalCode(code);
this._freshNode();
}
},
_freshNode() {
let uuid = this.itemData.uuid;
let code2 = "window.getNodeInfo('" + uuid + "')";
this._evalCode(code2);
},
_evalCode(code) {
if (chrome && chrome.devtools) {
chrome.devtools.inspectedWindow.eval(code);
} else {
console.log(code);
}
},
},
props: [
'itemData'
]
}
</script>
<style scoped>
span {
color: #fd942b;
}
.btnSize {
padding: 5px 10px;
}
.comp {
border: 2px solid #a1a1a1;
padding: 5px 5px;
background: #dddddd;
width: 100%;
border-radius: 5px;
-moz-border-radius: 5px; /* 老的 Firefox */
}
.float-left {
float: left;
}
.compBorder {
border: 1px solid #b3b3b3;
background: #ffffff
}
.myInput {
width: 90%;
border-radius: 5px;
color: #fd942b;
}
</style>

View File

@ -0,0 +1,18 @@
<template>
<div id="app">
<!--<h1> cc_Scene</h1>-->
</div>
</template>
<script>
export default {
name: "app",
data() {
return {}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,23 @@
import Vue from 'vue';
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue';
import ui_prop from './ui/ui-prop.vue'
import NodeBaseProperty from './ccType/NodeBaseProperty.vue'
import SceneProperty from './ccType/SceneProperty.vue'
import ComponentsProperty from './ccType/ComponentsProperty'
import ColorPicker from './ui/colorPicker'
Vue.component('ui-prop', ui_prop);
Vue.component('NodeBaseProperty', NodeBaseProperty);
Vue.component('SceneProperty', SceneProperty);
Vue.component('ComponentsProperty', ComponentsProperty);
Vue.component('ColorPicker', ColorPicker);
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});

View File

@ -0,0 +1,229 @@
<template lang="html">
<div class="m-colorPicker" ref="colorPicker" v-on:click="event => { event.stopPropagation() }">
<!-- 颜色显示小方块 -->
<div class="colorBtn"
v-bind:style="`background-color: ${showColor}`"
v-on:click="openStatus = !disabled"
v-bind:class="{ disabled: disabled }"
></div>
<!-- 用以激活HTML5颜色面板 -->
<input type="color"
ref="html5Color"
v-model="html5Color"
v-on:change="updataValue(html5Color)">
<!-- 颜色色盘 -->
<div class="box" v-bind:class="{ open: openStatus }">
<div class="hd">
<div class="colorView" v-bind:style="`background-color: ${showPanelColor}`"></div>
<div class="defaultColor"
v-on:click="handleDefaultColor"
v-on:mouseover="hoveColor = defaultColor"
v-on:mouseout="hoveColor = null"
>默认颜色</div>
</div>
<div class="bd">
<h3>主题颜色</h3>
<ul class="tColor">
<li
v-for="color of tColor"
v-bind:style="{ backgroundColor: color }"
v-on:mouseover="hoveColor = color"
v-on:mouseout="hoveColor = null"
v-on:click="updataValue(color)"
></li>
</ul>
<ul class="bColor">
<li v-for="item of colorPanel">
<ul>
<li
v-for="color of item"
v-bind:style="{ backgroundColor: color }"
v-on:mouseover="hoveColor = color"
v-on:mouseout="hoveColor = null"
v-on:click="updataValue(color)"
></li>
</ul>
</li>
</ul>
<h3>标准颜色</h3>
<ul class="tColor">
<li
v-for="color of bColor"
v-bind:style="{ backgroundColor: color }"
v-on:mouseover="hoveColor = color"
v-on:mouseout="hoveColor = null"
v-on:click="updataValue(color)"
></li>
</ul>
<h3 v-on:click="triggerHtml5Color">更多颜色...</h3>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'colorPicker',
props: {
//
value: {
type: String,
required: true
},
//
defaultColor: {
type: String,
default: '#000'
},
//
disabled: {
type: Boolean,
default: false
}
},
data () {
return {
//
openStatus: false,
//
hoveColor: null,
//
tColor: ['#000', '#fff', '#eeece1', '#1e497b', '#4e81bb', '#e2534d', '#9aba60', '#8165a0', '#47acc5', '#f9974c'],
//
colorConfig: [
['#7f7f7f', '#f2f2f2'],
['#0d0d0d', '#808080'],
['#1c1a10', '#ddd8c3'],
['#0e243d', '#c6d9f0'],
['#233f5e', '#dae5f0'],
['#632623', '#f2dbdb'],
['#4d602c', '#eaf1de'],
['#3f3150', '#e6e0ec'],
['#1e5867', '#d9eef3'],
['#99490f', '#fee9da']
],
//
bColor: ['#c21401', '#ff1e02', '#ffc12a', '#ffff3a', '#90cf5b', '#00af57', '#00afee', '#0071be', '#00215f', '#72349d'],
html5Color: this.value
}
},
computed: {
//
showPanelColor () {
if (this.hoveColor) {
return this.hoveColor
} else {
return this.showColor
}
},
//
showColor () {
if (this.value) {
return this.value
} else {
return this.defaultColor
}
},
//
colorPanel () {
let colorArr = []
for (let color of this.colorConfig) {
colorArr.push(this.gradient(color[1], color[0], 5))
}
return colorArr
}
},
methods: {
triggerHtml5Color () {
this.$refs.html5Color.click()
},
// value
updataValue (value) {
this.$emit('input', value)
this.$emit('change', value)
this.openStatus = false
},
//
handleDefaultColor () {
this.updataValue(this.defaultColor)
},
// hex
parseColor (hexStr) {
if (hexStr.length === 4) {
hexStr = '#' + hexStr[1] + hexStr[1] + hexStr[2] + hexStr[2] + hexStr[3] + hexStr[3]
} else {
return hexStr
}
},
// RGB HEX
rgbToHex (r, g, b) {
let hex = ((r << 16) | (g << 8) | b).toString(16)
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex
},
// HEX RGB
hexToRgb (hex) {
hex = this.parseColor(hex)
let rgb = []
for (let i = 1; i < 7; i += 2) {
rgb.push(parseInt('0x' + hex.slice(i, i + 2)))
}
return rgb
},
//
gradient (startColor, endColor, step) {
// hex rgb
let sColor = this.hexToRgb(startColor)
let eColor = this.hexToRgb(endColor)
// R\G\B
let rStep = (eColor[0] - sColor[0]) / step
let gStep = (eColor[1] - sColor[1]) / step
let bStep = (eColor[2] - sColor[2]) / step
let gradientColorArr = []
// hex
for (let i = 0; i < step; i++) {
gradientColorArr.push(this.rgbToHex(parseInt(rStep * i + sColor[0]), parseInt(gStep * i + sColor[1]), parseInt(bStep * i + sColor[2])))
}
return gradientColorArr
}
},
mounted () {
//
document.onclick = (e) => {
this.openStatus = false
}
}
}
</script>
<style lang="scss" scoped>
.m-colorPicker{
position: relative; text-align: left; font-size: 14px; display: inline-block;
ul,li,ol{ list-style: none; margin: 0; padding: 0; }
input{ display: none; }
.colorBtn{ width: 15px; height: 15px; }
.colorBtn.disabled{ cursor: no-drop; }
.box{
position: absolute; width: 190px; background: #fff; border: 1px solid #ddd; visibility: hidden; border-radius: 2px; margin-top: 2px; padding: 10px; padding-bottom: 5px; box-shadow: 0 0 5px rgba(0,0,0,.15); opacity: 0; transition: all .3s ease;
h3{ margin: 0; font-size: 14px; font-weight: normal; margin-top: 10px; margin-bottom: 5px; line-height: 1; }
}
.box.open{ visibility: visible; opacity: 1; }
.hd{
overflow: hidden; line-height: 29px;
.colorView{ width: 100px; height: 30px; float: left; transition: background-color .3s ease; }
.defaultColor{ width: 80px; float: right; text-align: center; border: 1px solid #ddd; cursor: pointer; }
}
.tColor{
li{ width: 15px; height: 15px; display: inline-block; margin: 0 2px; transition: all .3s ease; }
li:hover{ box-shadow: 0 0 5px rgba(0,0,0,.4); transform: scale(1.3); }
}
.bColor{
li{
width: 15px; display: inline-block; margin: 0 2px;
li{ display: block; width: 15px; height: 15px; transition: all .3s ease; margin: 0; }
li:hover{ box-shadow: 0 0 5px rgba(0,0,0,.4); transform: scale(1.3); }
}
}
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<div id="app" style="height: 30px;overflow: hidden;width: 100%;">
<div style="width: 20%;float: left;background-color: #4a4a4a;text-align: left;"
@mousedown="changePositionMouseAction"
onselectstart="return false;"
class="noselect">
<span onselectstart="return false;" class="noselect font"
style="line-height: 30px;color: #bdbdbd;font-size: 12px;margin: 3px;">
{{name}}
</span>
</div>
<div style=" float:left;background-color: #4a4a4a;width: 80%;height:100%;text-align: left;">
<div style="line-height: 30px;height: 100%;">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {
clientX: 0,
};
},
methods: {
changePositionMouseAction(event) {
document.addEventListener("mousemove", this._onMouseMove);
document.addEventListener("mouseup", this._onMouseUp);
document.addEventListener("onselectstart", this._onSelect);
},
_onSelect() {
return false;
},
_onMouseMove(event) {
let x = event.clientX;
let calcStep = parseFloat(this.step) || 1;// 1
// console.log("curentX: " + x);
// console.log("clientX: " + this.clientX);
if (x > this.clientX) {
calcStep = Math.abs(calcStep);
} else {
calcStep = -Math.abs(calcStep);
}
// console.log(calcStep);
this.$emit("movestep", calcStep);
this.clientX = x;
},
_onMouseUp(event) {
document.removeEventListener('mousemove', this._onMouseMove);
document.removeEventListener("mouseup", this._onMouseUp);
document.removeEventListener("onselectstart", this._onSelect);
},
},
props: [
'name',
'step',
]
}
</script>
<style scoped>
.font {
font-family: BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, 'SourceHanSansCN-Normal', Arial, sans-serif
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently
not supported by any browser */
}
</style>

View File

@ -0,0 +1,166 @@
// eval 注入脚本的代码,变量尽量使用var,后来发现在import之后,let会自动变为var
export default function () {
let msgType = {
nodeInfo: 2,//节点信息
nodeListInfo: 1,// 节点列表信息
notSupport: 0,// 不支持的游戏
};
let postData = {
scene: {
name: "",
children: []
},
};
window.inspectorGameMemoryStorage = window.inspectorGameMemoryStorage || {};
// 收集组件信息
function getNodeComponentsInfo(node) {
let ret = [];
let nodeComp = node._components;
for (let i = 0; i < nodeComp.length; i++) {
let itemComp = nodeComp[i];
window.inspectorGameMemoryStorage[itemComp.uuid] = itemComp;
ret.push({
uuid: itemComp.uuid,
type: itemComp.constructor.name,
name: itemComp.name,
});
}
return ret;
}
window.pluginSetNodeColor = function (uuid, colorHex) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
node.color = cc.hexToColor(colorHex);
}
};
window.pluginSetNodeRotation = function (uuid, rotation) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
node.rotation = rotation;
}
};
window.pluginSetNodePosition = function (uuid, x, y) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
node.x = x;
node.y = y;
}
};
window.pluginSetNodeSize = function (uuid, width, height) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
node.width = width;
node.height = height;
}
};
// 设置节点是否可视
window.pluginSetNodeActive = function (uuid, isActive) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
if (isActive === 1) {
node.active = true;
} else if (isActive === 0) {
node.active = false;
}
}
};
// 获取节点信息
window.getNodeInfo = function (uuid) {
let node = window.inspectorGameMemoryStorage[uuid];
if (node) {
let nodeComp = getNodeComponentsInfo(node);
let nodeData = {
type: node.constructor.name,
uuid: node.uuid,
name: node.name,
x: node.x,
y: node.y,
zIndex: node.zIndex,
childrenCount: node.childrenCount,
children: [],
width: node.width,
height: node.height,
color: node.color.toCSS(),
opacity: node.opacity,
rotation: node.rotation,
rotationX: node.rotationX,
rotationY: node.rotationY,
anchorX: node.anchorX,
anchorY: node.anchorY,
scaleX: node.scaleX,
scaleY: node.scaleY,
skewX: node.skewX,
skewY: node.skewY,
components: nodeComp
};
let nodeType = node.constructor.name;
if (nodeType === 'cc_Scene') {
} else {
nodeData.active = node.active;
}
window.sendMsgToDevTools(msgType.nodeInfo, nodeData);
} else {
// 未获取到节点数据
console.log("未获取到节点数据");
}
};
// 收集节点信息
function getNodeChildren(node, data) {
// console.log("nodeName: " + node.name);
let nodeData = {
uuid: node.uuid,
name: node.name,
children: [],
};
window.inspectorGameMemoryStorage[node.uuid] = node;
let nodeChildren = node.getChildren();
for (let i = 0; i < nodeChildren.length; i++) {
let childItem = nodeChildren[i];
// console.log("childName: " + childItem.name);
getNodeChildren(childItem, nodeData.children);
}
data.push(nodeData);
}
window.sendMsgToDevTools = function (type, msg) {
window.postMessage({type: type, msg: msg}, "*");
};
// 检测是否包含cc变量
let isCocosCreatorGame = true;
try {
let cocosInspectorTestVar = cc;
} catch (e) {
isCocosCreatorGame = false;
window.sendMsgToDevTools(msgType.notSupport, "不支持调试游戏!");
}
if (isCocosCreatorGame) {
let scene = cc.director.getScene();
if (scene) {
postData.scene = {
type: 1,// 标识类型
uuid: scene.uuid,
name: scene.name,
children: [],
};
window.inspectorGameMemoryStorage[scene.uuid] = scene;
let sceneChildren = scene.getChildren();
for (let i = 0; i < sceneChildren.length; i++) {
let node = sceneChildren[i];
getNodeChildren(node, postData.scene.children);
}
// console.log(postData);
window.sendMsgToDevTools(msgType.nodeListInfo, postData);
} else {
postData.scene = null;
window.sendMsgToDevTools(msgType.notSupport, "不支持调试游戏!");
}
} else {
console.log("未发现cocos creator game");
}
}

View File

@ -0,0 +1,12 @@
let index = 0;
setInterval(function () {
let msg = "util: " + index++;
// chrome.extension.sendMessage(msg;
if (typeof aa !== undefined) {
msg = aa;
}
window.postMessage({type: 1, msg: msg}, '*');
}.bind(this), 2000);

View File

@ -0,0 +1,21 @@
<template>
<div id="app">
<h1>{{label}}</h1>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {
label: "indexPage",
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue</title>
</head>
<body>
<div id="app">
</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
import Vue from 'vue';
import App from './App.vue';
new Vue({
el: '#app',
render: h => h(App)
});

View File

@ -0,0 +1,48 @@
{
"name": "Cocos Creator Inspector",
"version": "1.0.1",
"description": "Cocos Creator Inspector",
"browser_action": {
"default_title": "Cocos Creator Inspector",
"default_icon": "static/images/icon48.png",
"default_popup": "popup.html"
},
"icons": {
"48": "static/images/icon48.png"
},
"devtools_page": "dev.html",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"contentScripts.main.js"
],
"run_at": "document_end"
}
],
"background": {
"scripts": [
"backgroundScripts.main.js"
]
},
"options_page": "index.html",
"manifest_version": 2,
"permissions": [
"tabs",
"http://*/*",
"https://*/*",
"*://*/*",
"system.cpu",
"tabs",
"storage",
"nativeMessaging"
],
"web_accessible_resources": [
"*/*",
"*"
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

View File

@ -0,0 +1,62 @@
<template>
<div id="app" style="width: auto;">
<h3>{{title}}</h3>
<div style="text-align: center;width: 100%; color: #6d6d6d;">
<span>支持作者</span>
</div>
<br/>
<div style="margin:0 auto;width:100%;">
<div style="width: 200px; margin: 0 auto;" v-show="isShowMoneyPng">
<img style="width: 100%;height: auto;" src="static/images/money.jpg">
</div>
</div>
<br/>
<div id="foot" style="height: 30px;">
<span style="font-size: 14px;float: left;text-align: center;line-height: 30px;color: #6d6d6d;">联系方式:</span>
<div style="height: 100%;float: right;margin-right: 10px;">
<a href="https://github.com/tidys/CocosCreatorPlugins/tree/master/CocosCreatorInspector" target="_blank">
<img src="static/images/github.png" style="height: 100%;">
</a>
</div>
<div style="height: 100%;float: right;margin-right: 10px;">
<a href="https://jq.qq.com/?_wv=1027&k=5SdPdy2" target="_blank">
<img src="static/images/qq.png" style="height: 100%;">
</a>
</div>
<div style="height: 100%;float: right;margin-right: 10px;">
<a href="http://forum.cocos.com/t/chrome-creator/55669" target="_blank">
<img src="static/images/tiezi.png" style="height: 100%;">
</a>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import 'vue-awesome/icons/flag'
import 'vue-awesome/icons'
import Icon from 'vue-awesome/components/Icon'
Vue.component('icon', Icon);
export default {
name: "app",
data() {
return {
title: "cc-inspector",
isShowMoneyPng: true,
}
},
methods: {
onBtnClickGitHub() {
console.log("onBtnClickGitHub");
}
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,10 @@
import Vue from 'vue';
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue</title>
</head>
<body>
<div id="app">
</div>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,147 @@
let path = require('path');
let webpack = require('webpack');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let CleanWebpackPlugin = require('clean-webpack-plugin');
let CopyWebpackPlugin = require('copy-webpack-plugin');
if (process.env.NODE_ENV === 'production') {
}
module.exports = {
entry: {
popup: path.resolve(__dirname, "./src/popup/main.js"),
devInspector: path.resolve(__dirname, './src/dev/devInspector/main.js'),
dev: path.resolve(__dirname, './src/dev/dev.js'),
index: path.resolve(__dirname, './src/index/main.js'),
backgroundScripts: path.resolve(__dirname, './src/dev/backgroundScripts.js'),
contentScripts: path.resolve(__dirname, './src/dev/contentScripts.js'),
util: path.resolve(__dirname, './src/dev/util.js'),
injectScript: path.resolve(__dirname, './src/dev/injectScript.js'),
},
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/',
filename: '[name].main.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// webpack 执行之前删除dist下的文件
new CleanWebpackPlugin(
['dist/*'],
{
root: __dirname,//根目录
verbose: true,//开启在控制台输出信息
dry: false,//启用删除文件
}),
//index.html
new HtmlWebpackPlugin({
template: __dirname + "/src/index/index.html",
filename: 'index.html',
inject: 'body',
chunks: ['index']
}),
//popup.html
new HtmlWebpackPlugin({
template: __dirname + "/src/popup/popup.html",
filename: 'popup.html',
inject: 'body',
chunks: ['popup']
}),
//dev.html
new HtmlWebpackPlugin({
template: __dirname + "/src/dev/dev.html",
filename: 'dev.html',
inject: 'body',
chunks: ['dev']
}),
//devInspector.html
new HtmlWebpackPlugin({
template: __dirname + "/src/dev/devInspector/devInspector.html",
filename: 'devInspector.html',
inject: 'body',
chunks: ['devInspector']
}),
// 拷贝静态资源(manifest.json)
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, 'src/assets/'),
to: 'static',
force: true,
// ignore: ['.*']
},
{
from: path.resolve(__dirname, 'src/manifest.json'),
to: path.resolve(__dirname, 'dist/')
}]),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
// new webpack.optimize.UglifyJsPlugin({
// sourceMap: true,
// compress: {
// warnings: false
// }
// }),
new webpack.LoaderOptionsPlugin({
minimize: true
})
],
module: {
rules: [
{
test: /\.(less|css)$/,
use: [
'vue-style-loader',
'css-loader'
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'style-loader!css-loader!sass-loader',
sass: 'style-loader!css-loader!sass-loader?indentedSyntax',
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg|ttf|woff|woff2|eot)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
contentBase: "./dist",//本地服务器所加载的页面所在的目录
historyApiFallback: true,//不跳转
noInfo: true,
inline: true,//实时刷新
overlay: true
},
performance: {
hints: false
},
devtool: '#source-map'
};

View File

@ -0,0 +1,40 @@
# 如何运行项目
## 使用前
在使用之前,需要在项目目录CocosCreatorInspector下执行命令
```
npm install
```
初始化项目所需的依赖包
# 编译
在项目目录运行编译命令
```
npm run build
```
会生成dist目录,目录下即打包所需要的所有文件
# 如何打包插件
## 命令行方式
- 为了能够在计算机上让gulp直行任务所以我们需要全局安装gulp。在终端执行
```$xslt
cnpm install gulp -g
```
- 安装完成后,我们可以同样通过命令查看是否安装成功:
```$xslt
gulp -v
```
- 运行打包任务
```$xslt
gulp packageCrx
```
## 在webstorm中运行gulp任务
- 在gulpfile.js文件上右击选择**Show Gulp Tasks**
![](../doc/CreatorInspector/package/1.png)
- 如果webstorm没有检测到任务列表,需要设置下安装包,点击**设置**,
打开**Gulp Settings...**
![](../doc/CreatorInspector/package/2.png)
- 设置gulp模块的物理地址,注意图中红框设置的地址
![](../doc/CreatorInspector/package/3.png)
- 在webstorm中的gulp视图刷新任务列表
- 双击**packageCrx**,执行打包插件任务

View File

@ -0,0 +1,53 @@
## 注入脚本收集的数据结构
节点树数据结构
```json
{
"scene": {
"type":"1",// 类型
"uuid": "scene-uuid",
"name": "scene-name",
"children": [
{
"uuid": "node-uuid",
"name": "node-name",
"type": "cc_Node",
"x": 960.48,
"y": 540,
"zIndex": 0,
"width": 1920.96,
"height": 1080,
"active": true,
"color": "#ffffff",
"opacity": 255,
"rotation": 0,
"rotationX": 0,
"rotationY": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"scaleX": 1,
"scaleY": 1,
"skewX": 0,
"skewY": 0,
"childrenCount": 5,
"children": []
},
{
"uuid":"..."
}
]
}
}
```
缓存游戏真实的内存结构,window.inspectorGameMemoryStorage
```json
{
"node-uuid":"node-memory"
}
```
在遍历节点树的同时,会存储游戏实际的内存数据到inspectorGameMemoryStorage
## 获取某个节点信息
```
window.getNodeInfo
```

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Zaporozhets Yura
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

27
README.md Normal file
View File

@ -0,0 +1,27 @@
# Vue.js Chrome Extension Template ([wcer](https://github.com/YuraDev/wcer))
> Template for quick creation of Chrome extension on Vuejs c hot reloading when developing.
![Vue.js Chrome Extension Template images](/docs/images/mini.jpg)
## Installation:
This boilerplate was built as a template for [vue-cli](https://github.com/vuejs/vue-cli) and includes options to customize your final scaffolded app.
``` bash
# install vue-cli
$ npm install -g vue-cli
# create a new project using the template
$ vue init YuraDev/vue-chrome-extension-template my-project
# install dependencies and go!
$ cd my-project
$ npm install # or yarn
$ npm run dev # or yarn dev
```
## Structure
* [backend](https://developer.chrome.com/extensions/background_pages): Background work of your scripts
* [content](https://developer.chrome.com/extensions/content_scripts) Run in the context of web pages
* [devtools](https://developer.chrome.com/extensions/devtools) - It can add new UI panels and sidebars, interact with the inspected page, get information about network requests, and more.
* [options](https://developer.chrome.com/extensions/options) - To allow users to customize the behavior of your extension, you may wish to provide an options page.
* popup - The page (window) that will be displayed when the icon is clicked
* tab - Your application will work in a separate tab
* ext - Shared scripts
* [manifest.js](https://developer.chrome.com/extensions/manifest) - Descriptions of the application, its rights and possibilities

BIN
docs/images/mini.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

20
meta.json Normal file
View File

@ -0,0 +1,20 @@
{
"prompts": {
"name": {
"type": "string",
"required": true,
"label": "Project name"
},
"description": {
"type": "string",
"required": true,
"label": "Project description",
"default": "A Vue.js project"
},
"author": {
"type": "string",
"label": "Author"
}
},
"completeMessage": "To get started:\n\n cd {{destDirName}}\n npm install # or yarn\n npm run dev # or yarn dev\n\n"
}

18
template/.babelrc Normal file
View File

@ -0,0 +1,18 @@
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["istanbul"]
}
}
}

3
template/.eslintignore Normal file
View File

@ -0,0 +1,3 @@
core/*.js
core/*/*.js
build/*.js

31
template/.eslintrc.js Normal file
View File

@ -0,0 +1,31 @@
// https://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
globals: {
"chrome": true
// chrome: true
},
env: {
browser: true,
},
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}

12
template/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# IDE
.vscode
# dependencies
node_modules
# logs
npm-debug.log
yarn.lock
# Backpack build
build

8
template/.postcssrc.js Normal file
View File

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}

11
template/core/page.ejs Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet" type="text/css">
</head>
<body>
<div id="root"></div>
</body>
</html>

60
template/core/tools.js Normal file
View File

@ -0,0 +1,60 @@
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
exports.htmlPage = (title, filename, chunks, template) => new HtmlWebpackPlugin({
title,
hash: true,
cache: true,
inject: 'body',
filename: './pages/' + filename + '.html',
template: template || path.resolve(__dirname, './page.ejs'),
appMountId: 'app',
chunks
})
exports.cssLoaders = (options = {}) => {
let loaders = {}
let prePprocessors = {
css: {},
postcss: {},
less: { loader: 'less'},
sass: { loader:'sass', options: { indentedSyntax: true } },
scss: { loader:'sass' },
stylus: { loader: 'stylus' },
styl: { loader: 'stylus' }
}
for(let key in prePprocessors) {
let loader = [{
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production'
}
}]
if (prePprocessors[key].loader) {
loader.push({
loader: prePprocessors[key].loader + '-loader',
options: Object.assign({}, prePprocessors[key].options, { sourceMap: options.sourceMap })
})
}
if (options.extract) {
loaders[key] = ExtractTextPlugin.extract({ use: loader, fallback: 'vue-style-loader' })
} else {
loaders[key] = ['vue-style-loader'].concat(loader)
}
}
return loaders;
}
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}

View File

@ -0,0 +1,106 @@
const path = require('path')
const webpack = require('webpack')
const ChromeReloadPlugin = require('wcer')
const {cssLoaders, htmlPage} = require('./tools')
const CopyWebpackPlugin = require('copy-webpack-plugin')
let resolve = dir => path.join(__dirname, '..', 'src', dir)
module.exports = {
entry: {
tab: resolve('./tab'),
popup: resolve('./popup'),
options: resolve('./options'),
content: resolve('./content'),
devtools: resolve('./devtools'),
background: resolve('./backend'),
panel: resolve('./devtools/panel'),
inject: resolve('./content/inject'),
},
output: {
path: path.join(__dirname, '..', 'build'),
publicPath: '/',
filename: 'js/[name].js',
chunkFilename: 'js/[id].[name].js?[hash]',
library: '[name]'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [path.join(__dirname, '..', 'src'), path.join(__dirname, '..', 'test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
extractCSS: true,
loaders: {
...cssLoaders(),
js: { loader: 'babel-loader' }
},
transformToRequire: {
video: 'src',
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [path.join(__dirname, '..', 'src'), path.join(__dirname, '..', 'test')],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'img/[name].[hash:7].[ext]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name].[hash:7].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]'
}
}
]
},
plugins: [
htmlPage('home', 'app', ['tab']),
htmlPage('popup', 'popup', ['popup']),
htmlPage('panel', 'panel', ['panel']),
htmlPage('devtools', 'devtools', ['devtools']),
htmlPage('options', 'options', ['options']),
htmlPage('background', 'background', ['background']),
new CopyWebpackPlugin([{ from: path.join(__dirname, '..', 'static') }]),
new ChromeReloadPlugin({
port: 9090,
manifest: path.join(__dirname, '..', 'src', 'manifest.js')
}),
],
performance: { hints: false },
}

View File

@ -0,0 +1,21 @@
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseWebpack = require('./webpack.base')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const {styleLoaders} = require('./tools')
module.exports = merge(baseWebpack, {
// cheap-module-eval-source-map быстрее для разработки
watch: true,
module: {
rules: styleLoaders({ sourceMap: false })
},
devtool: '#cheap-module-eval-source-map',
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"development"'
}),
new FriendlyErrorsPlugin()
]
})

View File

@ -0,0 +1,47 @@
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseWebpack = require('./webpack.base')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const {styleLoaders} = require('./tools')
module.exports = merge(baseWebpack, {
devtool: '#cheap-module-eval-source-map',
module: {
rules: styleLoaders({ extract: true, sourceMap: true })
},
plugins: [
new CleanWebpackPlugin(['build/*.*']),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
new ExtractTextPlugin({
filename: 'css/[name].[contenthash].css'
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
})
]
})

13295
template/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

69
template/package.json Normal file
View File

@ -0,0 +1,69 @@
{
"name": "vue-chrome-extension-template",
"version": "0.0.1",
"description": "vue.js chrome extension template (wcer)",
"author": "works.yura@gmail.com",
"license": "MIT",
"private": false,
"dependencies": {
"axios": "^0.17.0",
"element-ui": "^2.0.1",
"lodash": "^4.17.4",
"vue": "^2.5.2",
"vue-meta": "^1.2.0",
"vue-pouch": "^0.0.22",
"vue-router": "^3.0.1",
"vuex": "^3.0.0"
},
"scripts": {
"lint": "eslint --ext .js,.vue src",
"dev": "webpack --config ./core/webpack.dev.js --hide-modules",
"build": "webpack --config ./core/webpack.prod.js -p --progress --hide-modules --colors"
},
"devDependencies": {
"archiver": "^2.1.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.1",
"babel-loader": "^7.1.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-2": "^6.24.1",
"babel-register": "^6.26.0",
"buble": "^0.16.0",
"buble-loader": "^0.4.1",
"clean-webpack-plugin": "^0.1.17",
"copy-webpack-plugin": "^4.2.0",
"cross-env": "^5.1.0",
"css-loader": "^0.28.7",
"enhanced-resolve": "^3.4.1",
"eslint": "^4.9.0",
"eslint-config-standard": "^10.2.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-html": "^3.2.2",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"eslint-plugin-vue-libs": "^1.2.1",
"extract-text-webpack-plugin": "^3.0.1",
"file-loader": "^1.1.5",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"node-sass": "^4.5.3",
"nodemon": "^1.12.1",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"pug": "^2.0.0-rc.4",
"pug-loader": "^2.3.0",
"sass-loader": "^6.0.6",
"url-loader": "^0.6.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.3",
"vue-template-compiler": "^2.5.2",
"wcer": "^1.0.2",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.3",
"webpack-merge": "^4.1.0",
"ws": "^3.2.0"
}
}

View File

@ -0,0 +1 @@
console.log('background !')

View File

@ -0,0 +1 @@
console.log('content-script!')

View File

@ -0,0 +1,5 @@
var content = chrome.extension.getURL('js/content.js')
var script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.setAttribute('src', content)
document.body.appendChild(script)

View File

@ -0,0 +1,3 @@
chrome.devtools.panels.create('panel', 'img/logo.png', 'pages/panel.html', function (panel) {
console.log('hello from callback')
})

View File

@ -0,0 +1,8 @@
import Vue from 'vue'
import root from './root.vue'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#root',
render: h => h(root)
})

View File

@ -0,0 +1,18 @@
<template lang="pug">
div devtools
</template>
<script>
export default {
data: () => ({
}),
computed: { },
created () { },
mounted () { },
methods: { }
}
</script>
<style lang="scss">
div {
color: blue
}
</style>

View File

@ -0,0 +1,22 @@
export default {
get (key) {
try {
return JSON.parse(localStorage.getItem(key))
} catch (e) {}
},
set (key, val) {
try {
localStorage.setItem(key, JSON.stringify(val))
} catch (e) {}
},
remove (key) {
try {
localStorage.removeItem(key)
} catch (e) {}
},
clear () {
try {
localStorage.clear()
} catch (e) {}
}
}

41
template/src/manifest.js Normal file
View File

@ -0,0 +1,41 @@
module.exports = {
name: 'Vue Extension',
version: '1.0.0',
description: 'Vue.js Chrome Extension Template (wcer)',
author: 'yura',
manifest_version: 2,
icons: { '16': 'icons/16.png', '128': 'icons/128.png' },
permissions: [
'<all_urls>',
'*://*/*',
'activeTab',
'tabs',
'cookies',
'background',
'contextMenus',
'unlimitedStorage',
'storage',
'notifications',
'identity',
'identity.email'
],
browser_action: {
default_title: 'title',
default_popup: 'pages/popup.html'
},
background: {
persistent: false,
page: 'pages/background.html'
},
devtools_page: 'pages/devtools.html',
options_page: 'pages/options.html',
content_scripts: [{
js: [ 'js/inject.js' ],
run_at: 'document_end',
matches: ['<all_urls>'],
all_frames: true
}],
content_security_policy: "script-src 'self' 'unsafe-eval'; object-src 'self'",
web_accessible_resources: [ 'panel.html', 'js/content.js' ]
}

View File

@ -0,0 +1,8 @@
import Vue from 'vue'
import root from './root.vue'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#root',
render: h => h(root)
})

View File

@ -0,0 +1,18 @@
<template lang="pug">
div options
</template>
<script>
export default {
data: () => ({
}),
computed: { },
created () { },
mounted () { },
methods: { }
}
</script>
<style>
div {
color: blue
}
</style>

View File

@ -0,0 +1,12 @@
import Vue from 'vue'
import root from './root.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
el: '#root',
render: h => h(root)
})

View File

@ -0,0 +1,23 @@
<template lang="pug">
div
el-button(type="primary" @click="tab") New tab
</template>
<script>
export default {
data: () => ({
}),
computed: { },
created () { },
mounted () { },
methods: {
tab () {
chrome.tabs.create({ url: 'pages/app.html' })
}
}
}
</script>
<style lang="scss">
div {
color: blue
}
</style>

View File

@ -0,0 +1,8 @@
import Vue from 'vue'
import root from './root.vue'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#root',
render: h => h(root)
})

18
template/src/tab/root.vue Normal file
View File

@ -0,0 +1,18 @@
<template lang="pug">
div tab
</template>
<script>
export default {
data: () => ({
}),
computed: { },
created () { },
mounted () { },
methods: { }
}
</script>
<style lang="scss">
div {
color: blue
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB