支持中文

This commit is contained in:
naibo
2023-03-17 23:00:21 +08:00
parent a57abc51bc
commit 3f21271025
114 changed files with 47070 additions and 481 deletions
Binary file not shown.
+6 -1
View File
@@ -9,11 +9,16 @@ npm install
npm install @electron-forge/cli
npm start
```
## Package Instruction
```
npx electron-forge import
npm run package
```
optional:
```
npm run make
```
-30
View File
@@ -1,30 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src="jquery-3.4.1.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="vue.js"></script>
<link rel="stylesheet" href="bootstrap/css/bootstrap.css">
</link>
<title>EasySpider: NoCode Visual Web Crawler</title>
</head>
<body>
<div style="padding: 10px; text-align: center;vertical-align: middle;">
<p>Status: Click Button below to start.</p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;" href="javascript:void(0)" id="btnDesign"
class="btn btn-primary btn-lg">Design Task</a></p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;" href="javascript:void(0)" id="btnInvoke"
class="btn btn-primary btn-lg">View/Manage/Invoke Tasks</a></p>
</div>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
+72 -15
View File
@@ -1,5 +1,6 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow, dialog, ipcMain } = require('electron');
const { app, BrowserWindow, dialog, ipcMain, screen } = require('electron');
app.commandLine.appendSwitch("--disable-http-cache");
const path = require('path');
const {exec} = require('child_process');
const iconPath = path.join(__dirname, 'favicon.ico');
@@ -19,12 +20,26 @@ if (process.platform === 'win32' || process.platform === 'win64') {
chromeBinaryPath = path.join(__dirname, "chrome_linux64/chrome");
execute_path = path.join(__dirname, "chrome_linux64/easyspider_executestage");
}
let language = "en";
let server_address = "https://servicewrapper.systems";
let driver = null;
let mainWindow = null;
let flowchart_window = null;
// var ffi = require('ffi-napi');
// var libm = ffi.Library('libm', {
// 'ceil': [ 'double', [ 'double' ] ]
// });
// libm.ceil(1.5); // 2
// const {user32FindWindowEx,
// winspoolGetDefaultPrinter,} = require('win32-api/fun');
// async function testt(){
// // 获取当前电脑当前用户默认打印机名
// const printerName = await winspoolGetDefaultPrinter()
// console.log(printerName);
// }
// testt();
function createWindow() {
// Create the browser window.
@@ -35,14 +50,17 @@ function createWindow() {
preload: path.join(__dirname, 'preload.js')
},
icon: iconPath,
// frame: false, //取消window自带的关闭最小化等
resizable: false //禁止改变主窗口尺寸
})
// and load the index.html of the app.
mainWindow.loadFile('index.html');
mainWindow.loadFile('src/index.html');
// 隐藏菜单栏
const { Menu } = require('electron');
Menu.setApplicationMenu(null);
// mainWindow.webContents.openDevTools();
// Open the DevTools.
// mainWindow.webContents.openDevTools()
@@ -52,12 +70,30 @@ function createWindow() {
function beginInvoke(msg) {
if (msg.type == 1) {
if (msg.message.id != -1) {
let url = server_address + `/FlowChart.html?id=${msg.message.id}&backEndAddressServiceWrapper=` + server_address;
let url = "";
if (language == "zh"){
url = server_address + `/FlowChart_CN.html?id=${msg.message.id}&backEndAddressServiceWrapper=` + server_address;
} else if(language == "en"){
url = server_address + `/FlowChart.html?id=${msg.message.id}&backEndAddressServiceWrapper=` + server_address;
}
console.log(url);
flowchart_window.loadURL(url);
}
mainWindow.hide();
flowchart_window.show();
const { windowManager } = require("node-window-manager");
const window = windowManager.getActiveWindow();
// Prints the currently focused window bounds.
console.log(window.getBounds());
// This method has to be called on macOS before changing the window's bounds, otherwise it will throw an error.
// It will prompt an accessibility permission request dialog, if needed.
windowManager.requestAccessibility();
// Sets the active window's bounds.
let size = screen.getPrimaryDisplay().workAreaSize
let width = parseInt(size.width)
let height = parseInt(size.height * 0.6)
window.setBounds({ x: 0, y: size.height * 0.4, height:height, width:width });
} else if (msg.type == 2) {
//keyboard
const robot = require("@jitsi/robotjs");
@@ -127,13 +163,19 @@ const chrome = require('selenium-webdriver/chrome');
const { ServiceBuilder } = require('selenium-webdriver/chrome');
const { rootCertificates } = require('tls');
const { exit } = require('process');
const {windowManager} = require("node-window-manager");
console.log(process.platform);
async function runBrowser() {
async function runBrowser(lang="en") {
const serviceBuilder = new ServiceBuilder(driverPath);
let options = new chrome.Options();
options.addExtensions(path.join(__dirname, "EasySpider.crx"));
language = lang;
if(lang=="en") {
options.addExtensions(path.join(__dirname, "EasySpider_en.crx"));
} else if(lang=="zh") {
options.addExtensions(path.join(__dirname, "EasySpider_zh.crx"));
}
options.setChromeBinaryPath(chromeBinaryPath);
driver = new Builder()
.forBrowser('chrome')
@@ -141,24 +183,33 @@ async function runBrowser() {
.setChromeService(serviceBuilder)
.build();
try {
await driver.get(server_address + "/serviceList.html?backEndAddressServiceWrapper=" + server_address);
await driver.get(server_address + "/taskList.html?backEndAddressServiceWrapper=" + server_address + "&lang=" + lang);
} finally {
// await driver.quit(); // 退出浏览器
}
}
function handleOpenBrowser(event) {
function handleOpenBrowser(event, lang="en") {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
runBrowser();
runBrowser(lang);
let size = screen.getPrimaryDisplay().workAreaSize;
let width = parseInt(size.width);
let height = parseInt(size.height * 0.6);
flowchart_window = new BrowserWindow({
width: 1600,
height: 900,
x:0,
y:0,
width: width,
height: height,
icon: iconPath,
});
let url = "";
let id = -1;
let url = server_address + `/FlowChart.html?id=${id}&backEndAddressServiceWrapper=` + server_address;
if (lang == "en") {
url = server_address + `/FlowChart.html?id=${id}&backEndAddressServiceWrapper=` + server_address;
}else if(lang == "zh") {
url = server_address + `/FlowChart_CN.html?id=${id}&backEndAddressServiceWrapper=` + server_address;
}
// and load the index.html of the app.
flowchart_window.loadURL(url);
flowchart_window.hide();
@@ -167,9 +218,15 @@ function handleOpenBrowser(event) {
});
}
function handleOpenInvoke(event){
function handleOpenInvoke(event, lang="en"){
const window = new BrowserWindow({icon: iconPath});
let url = server_address + `/serviceList.html?type=1&backEndAddressServiceWrapper=` + server_address;
let url = "";
language = lang;
if (lang == "en") {
url = server_address + `/taskList.html?type=1&backEndAddressServiceWrapper=` + server_address;
}else if(lang == "zh") {
url = server_address + `/taskList.html?type=1&backEndAddressServiceWrapper=` + server_address + "&lang=zh";
}
// and load the index.html of the app.
window.loadURL(url);
window.maximize();
+5863
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
rmdir /s C:\Users\q9823\AppData\Local\Temp\electron-packager
npm run package
+21 -3
View File
@@ -6,6 +6,7 @@
"description": "NoCode Visual Web Crawler",
"main": "main.js",
"scripts": {
"start_direct": "electron .",
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
@@ -20,20 +21,37 @@
"author": "Naibo Wang",
"license": "CC0-1.0",
"devDependencies": {
"electron": "^22.2.0"
"@electron-forge/cli": "^6.0.5",
"@electron-forge/maker-deb": "^6.0.5",
"@electron-forge/maker-rpm": "^6.0.5",
"@electron-forge/maker-squirrel": "^6.0.5",
"@electron-forge/maker-zip": "^6.0.5",
"electron": "^20.0.0"
},
"repository": "https://github.com/electron/electron-quick-start",
"dependencies": {
"@electron-forge/cli": "^6.0.5",
"@jitsi/robotjs": "^0.6.11",
"electron-squirrel-startup": "^1.0.0",
"ffi-napi": "^4.0.3",
"node-window-manager": "^2.2.4",
"ref-napi": "^3.0.3",
"selenium-webdriver": "^4.8.0",
"win32-api": "^20.4.1",
"ws": "^8.12.0"
},
"config": {
"forge": {
"makers": [],
"packagerConfig": {
"icon": "favicon.ico"
"icon": "favicon.ico",
"appVersion": "0.1.0",
"name": "EasySpider",
"appCopyright": "Naibo Wang(naibowang@foxmail.com)",
"win32metadata": {
"ProductName": "EasySpider",
"CompanyName": "浙江大学",
"FileDescription": "EasySpider"
}
},
"publishers": []
}
+2 -2
View File
@@ -8,6 +8,6 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
startDesign: () => ipcRenderer.send('start-design', ""),
startInvoke: () => ipcRenderer.send('start-invoke', ""),
startDesign: (lang="en") => ipcRenderer.send('start-design', lang),
startInvoke: (lang="en") => ipcRenderer.send('start-invoke', lang),
})
@@ -1,7 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<script src="jquery-3.4.1.min.js"></script>
<script src="../js/jquery-3.4.1.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
@@ -1,7 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<script src="jquery-3.4.1.min.js"></script>
<script src="../js/jquery-3.4.1.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<script src="jquery-3.4.1.min.js"></script>
<script src="../js/jquery-3.4.1.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="jquery-3.4.1.min.js"></script>
<script src="../js/jquery-3.4.1.min.js"></script>
<meta charset="utf-8" />
</head>
<html>

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

+78
View File
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<script src="js/jquery-3.4.1.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="js/vue.global.js"></script>
<link rel="stylesheet" href="bootstrap/css/bootstrap.css">
</link>
<title>EasySpider: NoCode Visual Web Crawler</title>
</head>
<body>
<div id="app">
<div v-if="init" style="padding: 10px; text-align: center;vertical-align: middle;">
<p style="margin-top: 20px">选择语言/Select Language</p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;" @click="changeLang('zh')" class="btn btn-outline-primary btn-lg">中文版</a></p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;" @click="changeLang('en')" class="btn btn-outline-primary btn-lg">English</a></p>
</div>
<div v-else style="padding: 10px; text-align: center;vertical-align: middle;">
<div v-if="lang=='en'">
<p style="margin-top: 20px">Hint: Click Button below to start.</p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;color:white" @click="startDesign('en')"
class="btn btn-primary btn-lg">Design Task</a></p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;color:white" @click="startInvoke('en')" @click
class="btn btn-primary btn-lg">View/Manage/Invoke Tasks</a></p>
</div>
<div v-else-if="lang=='zh'">
<p style="margin-top: 20px">提示:点击下方按钮开始使用。</p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;color:white" @click="startDesign('zh')"
class="btn btn-primary btn-lg">设计任务</a></p>
<p><a style="margin-top: 15px; width: 300px;height:60px;padding-top:12px;color:white" @click="startInvoke('zh')" @click
class="btn btn-primary btn-lg">查看/管理/执行任务</a></p>
</div>
</div>
</div>
<!-- You can also require other files to run in this process -->
<script src="js/renderer.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
init: true,
lang: 'zh',
}
},
methods: {
changeLang(lang='zh') {
this.init = false;
this.lang = lang;
},
startDesign(lang){
window.electronAPI.startDesign(lang);
},
startInvoke(lang){
window.electronAPI.startInvoke(lang);
}
}
}).mount('#app');
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

@@ -1,8 +1,8 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appShortName__",
"description": "__MSG_appDescription__",
"version": "0.0.0",
"name": "EasySpider",
"short_name": "EasySpider",
"description": "EasySpider",
"version": "0.1.0",
"manifest_version": 2,
"default_locale": "en",
"icons": {
-28
View File
@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXazUrRLF9mN3X
L3xbQi6khT53dE4oQjv7uXhIvsuYIx95hqj7cM7GTGsLsmmWKoErPOSE9QoqbCBA
f10YFIrDmm6qYd3KYSlpZWJ9gguTGLtbCV8c8ksPAwwM2jQ99B+tOSq7Ue0r/f6B
BBd3ywr1mix+1TX6MS+vJrkNwhPbgSsP4BqOEMPZUvI56g50xK6BX3kyd3gCWX+d
YyAaJwByz1/npoIwGo/mUD8YgtS/GToZjDPkoYgaD0ATnfrlWNEwQwx30oFK5vqC
GUFzaKpX6siqK4cX7KhRKK9UknCHhqu4jMbb+fD35ztr3cpdAd1Cw2rUYi04K6l3
irsVIMhzAgMBAAECggEABA3kplBSSnImDAjWhfUJNxfLSjWnIKZgVxiG0Psk9MsF
xCAxC+onGqQeJiwbmms2LCMNSIKmpgdHqqV9IzbZoEMkpB8Czwf51lEBMtTHLEGW
Iz6nAhygFK5qKpxslZ3H5V+tftddQVHev8nc01dzGvyyeI2OQFh/xZ1bhch3IpwO
7X/taYUaU/wiTlUEQgfuJBy7bHMS7JxrQQ2gaoh1iwMJruiUZWt41mr5hUxXwVTn
BcT+yMMuy36K1B+M6ia983SYUVVBO7iqcY4/nNIUIxQ2MB2v1Bc5E5ZKvO2GA0HR
TAqBRApEjMURLvwz83EZ0DzABknr70IfixNgXdeNXQKBgQDvhLhDk5sMrVNN1iV3
2Q2P8eUgmHHfzmDihpChD5DP8tNxi4J506DMkaBP4OnmcN5chpZW2oLO8SS6aqCS
XZUiTaypWhUu0ukHDlv4nsqJHRccIWDlSqUtLbUN+6JudtLxMrwqylsZjLA6G3Du
d4GJnIs+/BaB1c2zAj2fXcyplwKBgQDmPfTAi8+4ZiJvu/VdY/Z0sS7MDxvQmQE6
MKjOQEc8Njl8F/fRA7Sz0ms/dkAtkoXeunQgS3T4LxRd0w7OmnlE0Dk3X1vkF10N
FIYP1GXrhkLtkzO0rELU7gVVJP7eAP25GWWaG8bN0nmI6r30lC3Xb6QiHBCtv2EY
rv1C+xxbhQKBgQDk3020RTfDxVv05Myo2R+8jMkFfKZT1kF+NFe/j8Aw9ThXJ5hm
EXN2BzHJIoJfUTsp7vF5zRNx67vM5lbJheMcBF0Y9puHQsKpm28HA7VFkCalGsAc
Wle79BEua2WraJ/pGzHzMaobn/RFkjM3q7p8ZLoqVXisWEFW7K01u8v1wQKBgQDY
koK880ZKv9e4nmaomDTlgxzv2W5igunCoK7Ig3H+U0szTSBQPVomo9E5+rNXqrG9
1kkRb6jxIufXcYZGFMvpTKvlSA+Zt9hRS3LnRPUx3DLsYkCKvFaJD/N4KbqLfQcs
q5UEpwgT5t1nStevTgro0Rzk8N1HcfOVUlTsQmRkOQKBgHsFyWCSYYixyWBX+aaq
jxtIxfVIHo68z6sV6ERG5KtfXipKpem8ju0sNRzFi1/HwoEX9W6A0S1caeLTqWGt
o8kEHyGOOqmJYJaTK20EckDEUUGGpjZ/Wa2MCGNGvTJxQIv4i/g4fNIpWTTy1vRD
TQlffAYcH4lGhmlIWFKo+SvY
-----END PRIVATE KEY-----
+4 -4
View File
@@ -1,8 +1,8 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appShortName__",
"description": "__MSG_appDescription__",
"version": "0.0.0",
"name": "EasySpider",
"short_name": "EasySpider",
"description": "EasySpider",
"version": "0.1.0",
"manifest_version": 2,
"default_locale": "en",
"icons": {
Binary file not shown.
+28
View File
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7wvsAD5sZBMt8
+zza55fI0XeuIJ21IzAMfrCEY+uRbxoat1Vr6iTIWxvvJLs6jrZFj0eU09FFjRqk
ajExVaM3wTf0GEzzM0NQsiL3rlsjxzI1A04gjHtc3Rtk9hoGdIN9InZXR7AIIHRW
9JSv3VaJKHM5ifDc3VTS5xv155ajJUV+leV0HvHGkJ8j6wIqAmJ9FO3nldxx2PgB
9CfsSe0poBJm5bzL8sz0HkcLwTb6us2VKR7SnmiCQj7bXecwLRrWcpxt/g4ssat1
l95rVfgAdL3ASYcEwV584qMpoxDcvRW2O+f1XSQTk16OwMSjjNF+ZxKZrL3Gsa6i
ZDkAHjrNAgMBAAECggEACpRx30QshEw3CSEBAgFjFfTo+P4BKkfuzlgZ1dk+2LA5
eNWUHHi86jCUEjVwJVxi8eghFkZEjauQm5YY6oOS/F0eAYTtr8CCOQWonxXghdNq
GqmdLowBQYTQpS+Rh4PritK1Igrkj44AmuESOxdOPSad2NlTIfwzajo34vMnPk8O
Rj9GAhOyg6T58vZi4pILOwmTlwEcaSfyoE5nyHl1HRsncoe8evN5qpnZbGLPmoGh
blL6jTjqIVF67/kqLu36INMIgKM+nahCWy3JjRD3JEuxzk2YVQU+9VspDWNQdFdL
T9CAW+CQ/QVVqPhJ2em7N0CcTTCHKGSvkWEbz5J6gwKBgQD4A2G5nNDjzyapfpOy
qszbtUUIlA1LndLVptD1qDDqU0/LOcmxnfZhvjnsb7JHdxsPkra0c9bYia5GXN5H
JcFuE24UjjWcQ740wWIWS/NDgf6+sNzf79TaAvZK0SmS9WXKCzCqEbVgQeHke1Oi
kYKqFulipluLGR+t9cVdIB80xwKBgQDBzuKs5aP/blm7O8jNufQ/xq5/BbogWAx7
GHUqR26BAF/WYr3a/5atr7oWim8WhXHgprz+OSaagOsF8jQwvD9Nx4BAH8NSEAj2
7vyHGIV6vbH9Ho4sOJLoJRAlPUNHvV8bY2wwrhXEeL2MudRMfnenKDAEp4wBoxoN
eLVIjNKXywKBgQC8sp39AiIw4eBxnzuy+Z8KHx4aC8Md4EOUiOp9re0hrCeO4TXj
LONTtM8PZGCJXUa6j47xNx2k/QQaxvfbvA8yuBfODfEeJrCmJOiDPGAm4dY3sgsr
WqdhBFXt0LxH8uvyUJdDHlwYk6fSFj8o9nsq/GmvxBDsgT4INnFmjFUR6wKBgQCH
t12Kn6DxLRBPCfV7Av3kbzggoR0OqznKNX1Opwjd8yopkanLovGcHRNd14ElLzto
irqL9+9tgFuUJWCgxCI8UDkiLlvzqmDssrxJykUmh5INY4lBtDhDsjiVK0pjAVyJ
bF0F1dJObBKoajUdf+5AMuc1SzLCrrl+t4mTDXIncwKBgAdPc/gj0RR74rQaozkn
1htPey1FQqkIbLtOn1/GYrG1vQ9i8o7J+jn3xTIymD5kG/3aLgOjj6WQC6joMM4K
nUFRmol9Vu3NhiAv9wsFswMYKMwQbw6Auh1fU3B/N3mGkv9E9fG0UKEpJvfvq592
SlSnqy4jU1fq4L7rc1tonOzF
-----END PRIVATE KEY-----
@@ -0,0 +1,18 @@
{
"appName": {
"message": "servicewrapper",
"description": "The name of the application"
},
"appShortName": {
"message": "fwbz",
"description": "The short_name (maximum of 12 characters recommended) is a short version of the app's name."
},
"appDescription": {
"message": "service wrapper",
"description": "The description of the application"
},
"browserActionTitle": {
"message": "servicewrapper",
"description": "The title of the browser action button"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

+78
View File
@@ -0,0 +1,78 @@
{
"name": "EasySpider",
"short_name": "EasySpider",
"description": "EasySpider",
"version": "0.1.0",
"manifest_version": 2,
"default_locale": "en",
"icons": {
"16": "images/icon-16.png",
"128": "images/icon-128.png"
},
"background": {
"scripts": [
"scripts/background.js"
]
},
"page_action": {
"default_icon": {
"19": "images/icon-19.png",
"38": "images/icon-38.png"
},
"default_title": "__MSG_browserActionTitle__",
"default_popup": "pages/popup.html"
},
"options_page": "pages/options.html",
"options_ui": {
"page": "pages/options.html",
"chrome_style": true
},
"minimum_chrome_version": "10.0",
"devtools_page": "pages/devtools.html",
"omnibox": {
"keyword": "fwbz"
},
"content_scripts": [{
"matches": [
"http://*/*",
"https://*/*"
],
"css": [
"styles/contentscript.css"
],
"js": [
"scripts/jquery-3.4.1.min.js", "scripts/vue.js", "scripts/baozhuangscript.js", "scripts/contentscript.js", "scripts/messageInteraction.js"
],
"run_at": "document_end",
"all_frames": false
}],
"web_accessible_resources": ["js/inject.js"],
"permissions": [
"activeTab",
"alarms",
"bookmarks",
"browsingData",
"contextMenus",
"cookies",
"downloads",
"downloads.open",
"geolocation",
"history",
"identity",
"idle",
"management",
"nativeMessaging",
"notifications",
"privacy",
"proxy",
"sessions",
"storage",
"tabs",
"topSites",
"webNavigation",
"webRequest",
"webRequestBlocking",
"unlimitedStorage",
"<all_urls>"
]
}
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Devtools</title>
<link rel="stylesheet" type="text/css" href="../styles/devtools.css">
</head>
<body>
<h1>Devtools</h1>
<script src="../scripts/popup.js"></script>
</body>
</html>
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Options</title>
<link rel="stylesheet" type="text/css" href="../styles/options.css">
</head>
<body>
<label>
<input type="checkbox" name="examplOption" checked>
Example Option
</label>
<script src="../scripts/options.js"></script>
</body>
</html>
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Popup</title>
<link rel="stylesheet" type="text/css" href="../styles/popup.css">
</head>
<body>
<h1>服务包装手动版工具</h1>
<script src="../scripts/popup.js"></script>
<script src="../scripts/baozhuangscript.js"></script>
</body>
</html>
@@ -0,0 +1,66 @@
//此变量用于监听是否加载了新的页面(包括新窗口打开),如果是,增加变量值,用于传回后台。
var tabList = []; //用来记录打开的新的tab的id
var nowTabId = null;
var nowTabIndex = 0; //重要变量!!
chrome.storage.local.set({ "parameterNum": 1 }); //修改默认的参数索引值
// chrome.tabs.update(6,{"active":true}) //一行就可以切换标签页
chrome.tabs.onActivated.addListener(function(activeInfo) {
nowTabId = activeInfo.tabId; //记录现在活动的tabid
if (tabList.indexOf(nowTabId) != -1) {
nowTabIndex = tabList.indexOf(nowTabId);
}
});
// 监听来自content-script的消息
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.type == 0) {
if (tabList.indexOf(sender["tab"]["id"]) < 0) { //元素不存在加入数组
tabList.push(sender["tab"]["id"]);
}
nowTabIndex = tabList.indexOf(nowTabId);
sendResponse({ type: 0, "msg": "Get!" }); //回传一个消息
} else if (request.type == 1) { //前台询问参数索引值
sendResponse({ type: 1, "value": parameterNum }); //回传一个消息
} else if (request.type == 2) {
let message = {
type: 2, //消息类型,2代表键盘输入
message: { "keyboardStr": "{}{BS}" + request.msg } // {}全选{BS}退格
};
window.ws.send(JSON.stringify(message));
} else if (request.type == 3) {
let tmsg = request.msg;
tmsg.tabIndex = nowTabIndex; //赋值当前tab的id
let message = {
type: 3, //消息类型,3代表元素增加事件
from: 0, //0代表从浏览器到流程图,1代表从流程图到浏览器
message: { "pipe": JSON.stringify(request.msg) } // {}全选{BS}退格
};
console.log(message);
window.ws.send(JSON.stringify(message));
}
});
// 打开一个 web socket
window.ws = new WebSocket("ws://localhost:8084");
window.ws.onopen = function() {
// Web Socket 已连接上,使用 send() 方法发送数据
console.log("已连接");
message = {
type: 0, //消息类型,0代表链接操作
message: {
id: 0, //socket id
}
};
this.send(JSON.stringify(message));
};
window.ws.onmessage = function(evt) {
evt = JSON.parse(evt.data);
if (evt["type"] == "0") { //0代表更新参数添加索引值
chrome.storage.local.set({ "parameterNum": parseInt(evt["value"]) }); //修改值
}
};
window.ws.onclose = function() {
// 关闭 websocket
console.log("连接已关闭...");
};
@@ -0,0 +1,261 @@
//表现层的处理
if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
}
//返回element相对node节点的xpath,默认的node节点是: /
function readXPath(element, type = 1, node = document.body) {
try {
if (type == 0) //type=0代表默认可通过id生成xpath type=1代表只能从根节点生成xpath
{
if (element.id !== "") { //判断id属性,如果这个元素有id,则显示//*[@id="xPath"] 形式内容
return '//*[@id=\"' + element.id + '\"]';
}
}
//这里需要需要主要字符串转译问题,可参考js 动态生成html时字符串和变量转译(注意引号的作用)
if (element == node) { //递归到body处,结束递归
if (node == document.body) {
return '/html/' + element.tagName.toLowerCase();
} else {
return "";
}
}
var ix = 1, //在nodelist中的位置,且每次点击初始化
siblings = element.parentNode.childNodes; //同级的子元素
for (var i = 0, l = siblings.length; i < l; i++) {
var sibling = siblings[i];
//如果这个元素是siblings数组中的元素,则执行递归操作;arguments.callee代表当前函数的名称
if (sibling == element) {
return readXPath(element.parentNode, type, node) + '/' + element.tagName.toLowerCase() + '[' + (ix) + ']';
//如果不符合,判断是否是element元素,并且是否是相同元素,如果是相同的就开始累加
} else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
//注意此处,为了防止多计算了插入的操作台的3个div元素导致定位错误,这里需要屏蔽掉三个元素的索引号
if(sibling.id != "wrapperDiv" && sibling.id != "wrapperTdiv" &&sibling.id != "wrapperToolkit"){
ix++;
}
}
}
} catch {
return "/"
}
};
//创造div作为选中元素后的样式存在
var div = document.createElement('div');
div.style.zIndex = -2147483647;
div.setAttribute("id", "wrapperDiv");
div.style.position = "fixed";
div.style.boxSizing = "border-box";
div.style.border = "dotted";
var tdiv = document.createElement('div');
tdiv.style.zIndex = 2147483647;
tdiv.style.position = "fixed";
tdiv.setAttribute("id", "wrapperTdiv");
tdiv.classList = "tdiv";
tdiv.style.top = "0px";
tdiv.style.width = "3000px";
tdiv.style.height = "3000px";
tdiv.style.pointerEvents = "none";
var mousemovebind = false; //如果出现元素默认绑定了mousemove事件导致匹配不到元素的时候,开启第二种模式获得元素
var toolkit = document.createElement("div")
toolkit.classList = "tooltips"; //添加样式
toolkit.setAttribute("id", "wrapperToolkit");
var tooltips = false; //标记鼠标是否在提示框上
var defaultbgColor = 'rgba(221,221,255,0.8)'; //移动到元素的背景颜色
var selectedColor = "rgba(151,255,255, 0.6)"; //选中元素的背景颜色
var boxShadowColor = "blue 0px 0px 5px"; //待选元素的边框属性
//右键菜单屏蔽
document.oncontextmenu = () => false;
var nodeList = []; //已被选中的节点列表
var readyList = []; //预备选中的list
var outputParameters = []; //输出参数列表
var outputParameterNodes = []; //输出参数节点列表
NowNode = null;
var xnode = null;
var step = 0; //记录这是第几次点击操作
var style = ""; //记录上个元素的颜色
document.addEventListener("mousemove", function() {
if (mousemovebind) {
tdiv.style.pointerEvents = "none";
}
//如果鼠标在元素框内则点击和选中失效
var x = event.clientX;
var y = event.clientY;
var divx1 = toolkit.offsetLeft;
var divy1 = toolkit.offsetTop;
var divx2 = toolkit.offsetLeft + toolkit.offsetWidth;
var divy2 = toolkit.offsetTop + toolkit.offsetHeight;
if (x >= divx1 && x <= divx2 && y >= divy1 && y <= divy2) {
tooltips = true;
return;
}
oe = document.elementFromPoint(event.x, event.y);
if (oe == tdiv) {
return;
}
tooltips = false;
NowNode = oe;
te = 0;
exist = 0;
exist2 = 0;
for (o of nodeList) {
if (o["node"] == oe) {
exist = 1;
break;
}
}
for (o of nodeList) {
if (o["node"] == xnode) {
exist2 = 1;
break;
}
}
// console.log(oe);
if (xnode == null) {
xnode = oe;
}
if (xnode != oe) {
if (exist2 == 0) { //如果上个元素不在数组里,改回上个元素的初始颜色
try {
xnode.style.backgroundColor = style; //上个元素改回原来元素的背景颜色
} catch {
xnode.style.backgroundColor = ""; //上个元素改回原来元素的背景颜色
}
}
try {
style = oe.style.backgroundColor;
} catch {
style = "";
}
if (exist == 1) {
} else {
try {
oe.style.backgroundColor = defaultbgColor; //设置新元素的背景元素
} catch {}
}
xnode = oe;
div.style.display = "none";
}
if (mousemovebind) {
tdiv.style.pointerEvents = "";
}
});
//点击没反应时候的替代方案
document.onkeydown = function(event) {
// console.log("keydown");
var e = event || window.event || arguments.callee.caller.arguments[0];
if (e && e.keyCode == 118) { // 按 F7
addEl();
} else if (e && e.keyCode == 119) { //按F8
clearEl();
} else if (e && e.keyCode == 120) { //按F9
NowNode.focus();
NowNode.click();
// console.log("click",NowNode);
} else {
return event.keyCode;
}
};
//选中元素到列表中
function addEl() {
// if (tooltips) {
// return;
// }
let exist = false;
for (o of nodeList) {
if (o["node"] == oe) {
exist = true;
break;
}
}
//元素没有被添加过才去添加
if (!exist) {
step++;
exist = false; //判断刚加入的元素是否在readyList中,如果在,则将所有readylist中的元素全部放入list中
for (o of readyList) {
if (o["node"] == oe) {
exist = true;
break;
}
}
if (exist) { //存在在readylist就全选中
readyToList(step);
if (app._data.selectedDescendents) {
handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
}
} else //不然只添加一个元素
{
clearReady(); //readylist清零重新算
nodeList.push({ node: NowNode, "step": step, bgColor: style, "boxShadow": NowNode.style.boxShadow == "" || boxShadowColor ? "none" : NowNode.style.boxShadow, xpath: readXPath(NowNode, 1) });
NowNode.style.backgroundColor = selectedColor;
}
handleElement(); //处理新状态
//将虚线框显示在元素上方但屏蔽其鼠标操作
var pos = NowNode.getBoundingClientRect();
div.style.display = "block";
div.style.height = NowNode.offsetHeight + "px";
div.style.width = NowNode.offsetWidth + "px";
div.style.left = pos.left + "px";
div.style.top = pos.top + "px";
div.style.zIndex = 2147483645;
div.style.pointerEvents = "none";
}
// console.log("------");
// for (i = 0; i < nodeList.length; i++) {
// console.log(nodeList[i]["xpath"]);
// }
//对于可点击元素,屏蔽a标签默认点击事件
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault ? event.preventDefault() : event.returnValue = false;
}
document.addEventListener("mousedown", addEl);
toolkit.addEventListener("mousedown", function(e) { e.stopPropagation(); }); //重新定义toolkit里的点击事件
//清除选择项
function clearEl() {
//如果最后停留的元素被选中,则调整此元素的style为原始style,否则不进行调整
for (node of nodeList) {
node["node"].style.backgroundColor = node["bgColor"];
node["node"].style.boxShadow = node["boxShadow"];
if (NowNode == node["node"]) {
style = node["bgColor"];
}
}
step = 0;
clearReady();
clearParameters();
nodeList.splice(0, nodeList.length); //清空数组
app._data.option = 0; //选项重置
app._data.page = 0; //恢复原始页面
}
//清除预备数组
function clearReady() {
for (node of readyList) //节点列表状态恢复原状
{
node["node"].style.boxShadow = node["boxShadow"];
}
readyList.splice(0, readyList.length); //清空数组
}
document.body.append(div); //默认如果toolkit不存在则div和tdiv也不存在
document.body.append(tdiv);
document.body.append(toolkit);
var timer;
@@ -0,0 +1,933 @@
//表现逻辑层的处理
if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
}
//Vue元素
var app;
generateToolkit();
//生成Toolkit
function generateToolkit() {
$(".tooltips").html(`
<div id="realcontent">
<div class="tooldrag">✍操作提示框(可点此拖动)</div>
<div class="realcontent">
<div v-if="page==0">
<input type="checkbox" style="width:15px;height:15px;vertical-align:middle;" v-on:mousedown="specialSelect"> </input>
<p style="margin-bottom:10px;display:inline-block">特殊点选模式</p>
<div v-if="list.nl.length==0">
<p style="color:black">● 鼠标移动到元素上后,请<strong>右键</strong>点击或者按<strong>F7</strong>键选中页面元素。</p>
<p style="color:black">● 如果不小心左键点选了元素导致页面跳转,直接后退或者切换回标签页即可。</p>
{{initial()}}
</div>
<div v-if="list.nl.length==1">
<div v-if="tname()!='null'">
● 已选中{{numOfList()}}个{{tname()}}<span v-if="numOfReady()>0&&tname()!='下一页元素'">同时发现{{numOfReady()}}个同类元素,</span>您可以:
<div class="innercontent">
<div v-if="numOfReady()>0 && !selectStatus"> <a v-on:mousedown="selectAll">选中全部</a> <span title="">☺</span></div>
<div v-if="existDescendents()&& !selectStatus &&(tname()=='元素' || tname()=='链接')"> <a v-on:mousedown="selectDescendents">选中子元素</a> <span title="">☺</span></div>
<div v-if="!selectedDescendents && !selectStatus" id="Single">
<div v-if="tname()=='选择框'"> <a>循环切换下拉选项</a><span title="">☺</span></div>
<div v-if="tname()=='文本框'"> <a v-on:mousedown="setInput">输入文字</a><span title="">☺</span></div>
<div v-if="tname()!='图片'"> <a v-on:mousedown="getText">采集该{{tname()}}的文本</a><span title="采集文本">☺</span></div>
<div v-if="tname()=='选择框'"> <a>采集选中项的文本</a><span title="">☺</span></div>
<div v-if="tname()=='链接'||tname()=='图片'"> <a v-on:mousedown="getLink">采集该{{tname()}}的地址</a><span title="">☺</span></div>
<div v-if="tname()!='选择框' && tname()!='文本框'"> <a v-on:mousedown="clickElement">点击该{{tname()}}</a><span title="">☺</span></div>
<div v-if="tname()!='选择框' && tname()!='文本框'"> <a v-on:mousedown="loopClickSingleElement">循环点击该{{tname()}}</a><span title="">☺</span></div>
<div v-if="tname()=='链接'||tname()=='元素'"> <a v-on:mousedown="getInnerHtml">采集该{{tname()}}的Inner Html</a><span title="">☺</span></div>
<div> <a v-on:mousedown="getOuterHtml">采集该{{tname()}}的Outer Html</a><span title="">☺</span></div>
<div> <a href="#">鼠标移动到该{{tname()}}上</a><span title="">☺</span></div>
<div v-if="tname()=='文本框'"> <a>识别验证码</a><span title="">☺</span></div>
</div>
<div v-if="selectedDescendents" id="Single">
<div><a v-on:mousedown="confirmCollectSingle">采集数据</a><span title="">☺</span></div>
</div>
<div v-if="selectStatus" id="Confirm">
<div><a v-on:mousedown="confirmCollectSingle">确认采集</a><span title="">☺</span></div>
</div>
</div>
</div>
</div>
<div v-if="list.nl.length>1">
<div v-if="option==100">
● 已选择了以下元素,您可以:
<div class="innercontent">
<div> <a v-on:mousedown="confirmCollectMulti">采集数据</a><span title="">☺</span> </div>
<div> <a v-on:mousedown="revoke">撤销本次选择</a><span title="">☺</span></div>
</div>
</div>
<div v-if="option!=100">
● 已选择了{{numOfList()}}个同类元素,<span v-if="numOfReady()>0">另外发现{{numOfReady()}}个同类元素,</span>您可以:
<div class="innercontent">
<div v-if="numOfReady()>0"> <a v-on:mousedown="selectAll">选中全部</a><span title="">☺</span></div>
<div v-if="existDescendents()&&(tname()=='元素' || tname()=='链接')"> <a v-on:mousedown="selectDescendents">选中子元素</a><span title="">☺</span></div>
<div> <a v-on:mousedown="confirmCollectMultiAndDescendents">采集数据</a><span title="">☺</span></div>
<div v-if="tname()!='选择框' && tname()!='文本框' && !selectedDescendents"> <a v-on:mousedown="loopClickEveryElement">循环点击每个{{tname()}}</a><span title="">☺</span></div>
<div> <a v-on:mousedown="revoke">撤销本次选择</a><span title="">☺</span></div>
</div>
</div>
</div>
<div v-if="valTable.length>0">
<div class="toolkitcontain">{{setWidth("290px")}}
<table class="toolkittb2" cellspacing="0">
<tbody>
<th v-for="i in list.opp">{{i["name"]}}</th>
<th style="width:40px">删除</td>
</tbody>
</table>
<table class="toolkittb4" cellspacing="0">
<tbody>
<tr v-for="i in valTable[0].length">
<td v-for="j in list.opp.length">{{valTable[j-1][i-1]}}</td>
<td v-on:mousedown="deleteSingleLine" style="font-size: 22px!important;width:40px;cursor:pointer" v-bind:index="i-1">×</td>
</tr>
</table>
</div>
</div>
<div v-if="valTable.length==0&&tname()!='下一页元素'">{{setWidth("290px")}}</div>
<div v-if="list.nl.length>0" style="bottom:12px;position:absolute;color:black!important;left:17px;font-size:13px">
<div style="margin-bottom:5px">
<button v-on:mousedown="cancel">取消选择</button>
<button v-if="!selectStatus" v-on:mousedown="enlarge">扩大选区</button>
</div>
<p style="margin-left:16px;margin-bottom:0px">{{lastElementXPath()}}</p>
</div>
</div>
<div v-if="page==1">
● 请输入文字:
<input type="text" v-model="text" autofocus="autofocus" id="WTextBox"></input>
<button v-on:click="getInput" style="margin-left:0px!important;">确定</button>
<button v-on:click="cancelInput" style="margin-left:0px!important;">取消</button>
<div class="innercontent">
</div>
</div>
</div>
`);
app = new Vue({
el: '#realcontent',
data: {
option: 0,
list: { nl: nodeList, opp: outputParameters },
valTable: [], // 用来存储转换后的参数列表
special: false, //是否为特殊选择模式
selectedDescendents: false, // 标记是否选中了子元素
selectStatus: false, //标记单个元素是否点击了采集
page: 0, //默认页面,1为输入文字页面
text: "", // 记录输入的文字
tNodeName: "", // 记录临时节点列表
nowPath: "", //现在元素的xpath
},
watch: {
nowPath: { //变量发生变化的时候进行一些操作
handler: function(newVal, oldVal) {
console.log("xpath:", newVal);
}
}
},
methods: {
initial: function() { //每当元素是0的时候,执行值的初始化操作
this.selectedDescendents = false;
this.selectStatus = false;
this.nowPath = "";
},
confirmCollectSingle: function() { //单元素确认采集
collectSingle();
clearEl();
},
confirmCollectMulti: function() { //无规律多元素确认采集
collectMultiNoPattern();
clearEl();
},
confirmCollectMultiAndDescendents: function() { //有规律多元素确认采集
collectMultiWithPattern();
clearEl();
},
deleteSingleLine: function(event) { //删除单行元素
let at = new Date().getTime()
//流程图送元素的时候,默认的使用不固定循环列表,但是一旦有删除元素的操作发生,则按照固定元素列表采集元素
index = event.target.getAttribute("index");
let tnode = nodeList.splice(index, 1)[0]; //删掉当前元素
tnode["node"].style.backgroundColor = tnode["bgColor"];
tnode["node"].style.boxShadow = tnode["boxShadow"];
if (nodeList.length > 1) { // 如果删到没有就没有其他的操作了
handleElement();
if (this.selectedDescendents) {
handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
}
} else {
this.valTable = [];
this.selectStatus = false;
clearParameters(); //直接撤销重选
}
let at2 = parseInt(new Date().getTime());
console.log("delete:", at2, at, at2 - at);
},
clickElement: function() { //点击元素操作
sendSingleClick();
//先发送数据
nodeList[0]["node"].focus(); //获得元素焦点
nodeList[0]["node"].click(); //点击元素
clearEl();
},
loopClickSingleElement: function() { //循环点击单个元素
sendLoopClickSingle(this.tname()); //识别下一页,循环点击单个元素和点击多个元素
if (this.tname() != "下一页元素") { //下一页元素不进行点击操作
nodeList[0]["node"].focus(); //获得元素焦点
nodeList[0]["node"].click(); //点击元素
}
clearEl();
},
loopClickEveryElement: function() { //循环点击每个元素
sendLoopClickEvery(); //识别下一页,循环点击单个元素和点击多个元素
nodeList[0]["node"].focus(); //获得元素焦点
nodeList[0]["node"].click(); //点击元素
clearEl();
},
setInput: function() { //输入文字
this.page = 1;
this.$nextTick(function() { //下一时刻获得焦点
document.getElementById("WTextBox").focus();
})
},
getInput: function() { //得到输入的文字
nodeList[0]["node"].focus(); //获得文字焦点
// nodeList[0]["node"].setAttribute("value", this.text); // 设置输入框内容
input(this.text); // 设置输入
this.text = "";
clearEl();
},
cancelInput: function() {
this.page = 0;
},
setWidth: function(width) { //根据是否出现表格调整最外框宽度
$(".tooltips").css("width", width);
return "";
},
getText: function() { //采集文字
generateParameters(0, true, false);
this.selectStatus = true;
clearReady();
},
getLink: function() { //采集链接地址
generateParameters(0, false, true);
this.selectStatus = true;
clearReady();
},
getOuterHtml: function() { //采集OuterHtml
generateParameters(3, true, false);
this.selectStatus = true;
clearReady();
},
getInnerHtml: function() { //采集InnerHtml
generateParameters(2, true, false);
this.selectStatus = true;
clearReady();
},
tname: function() {
let tag = nodeList.length == 0 ? "" : nodeList[0]["node"].tagName;
let inputType = nodeList.length == 0 ? "" : nodeList[0]["node"].getAttribute("type");
if (inputType != null) { //如果没有type属性,则默认为text
inputType = inputType.toLowerCase();
} else {
inputType = "text";
}
if (tag == "") {
return "null";
} else if ($(nodeList[0]["node"]).contents().filter(function() { return this.nodeType === 3; }).text().indexOf("下一页") >= 0) {
this.setWidth("250px");
return "下一页元素";
} else if (tag == "A") {
return "链接";
} else if (tag == "IMG") {
return "图片";
} else if (tag == "BUTTON" || (tag == "INPUT" && (inputType == "button" || inputType == "submit"))) {
return "按钮";
} else if (tag == "TEXTAREA" || (tag == "INPUT" && (inputType != "checkbox" || inputType != "ratio"))) { //普通输入框
return "文本框";
} else if (tag == "SELECT") {
return "选择框";
} else {
return "元素";
}
},
existDescendents: function() { //检测选中的元素是否存在子元素,已经选中了子元素也不要再出现了
return nodeList.length > 0 && nodeList[0]["node"].children.length > 0 && !this.selectedDescendents;
},
numOfReady: function() {
return readyList.length;
},
numOfList: function() {
return nodeList.length;
},
lastElementXPath: function() { //用来显示元素的最大最后5个xpath路劲元素
path = nodeList[nodeList.length - 1]["xpath"];
path = path.split("/");
tp = "";
if (path.length > 5) { //只保留最后五个元素
path = path.splice(path.length - 5, 5);
tp = ".../"
}
for (i = 0; i < path.length; i++) {
path[i] = path[i].split("[")[0];
}
path = path.join("/");
path = "Path: " + tp + path;
return path;
},
cancel: function() {
clearEl();
},
specialSelect: function() { //特殊选择模式
if (mousemovebind) {
tdiv.style.pointerEvents = "none";
this.special = false;
} else {
this.special = true;
}
mousemovebind = !mousemovebind;
},
enlarge: function() { // 扩大选区功能,总是扩大最后一个选中的元素的选区
if (nodeList[nodeList.length - 1]["node"].tagName != "BODY") {
nodeList[nodeList.length - 1]["node"].style.backgroundColor = nodeList[nodeList.length - 1]["bgColor"]; //之前元素恢复原来的背景颜色
nodeList[nodeList.length - 1]["node"].style.boxShadow = nodeList[nodeList.length - 1]["boxShadow"]; //之前元素恢复原来的背景颜色
tNode = nodeList[nodeList.length - 1]["node"].parentNode; //向上走一层
if (tNode != NowNode) { //扩大选区之后背景颜色的判断,当前正好选中的颜色应该是不同的
sty = tNode.style.backgroundColor;
} else {
sty = style;
}
nodeList[nodeList.length - 1]["node"] = tNode;
nodeList[nodeList.length - 1]["bgColor"] = sty;
nodeList[nodeList.length - 1]["xpath"] = readXPath(tNode, 1);
//显示框
var pos = tNode.getBoundingClientRect();
div.style.display = "block";
div.style.height = tNode.offsetHeight + "px";
div.style.width = tNode.offsetWidth + "px";
div.style.left = pos.left + "px";
div.style.top = pos.top + "px";
div.style.zIndex = 2147483645;
div.style.pointerEvents = "none";
handleElement(); //每次数组元素有变动,都需要重新处理下
oe = tNode;
tNode.style.backgroundColor = "rgba(0,191,255,0.5)";
this.selectedDescendents = false;
}
},
selectAll: function() { //选中全部元素
step++;
readyToList(step, false);
handleElement();
if (this.selectedDescendents) {
handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
}
},
revoke: function() { //撤销选择当前节点
var tstep = step;
step--; //步数-1
while (tstep == nodeList[nodeList.length - 1]["step"]) //删掉所有当前步数的元素节点
{
let node = nodeList.splice(nodeList.length - 1, 1)[0]; //删除数组最后一项
node["node"].style.backgroundColor = node["bgColor"]; //还原原始属性和边框
node["node"].style.boxShadow = node["boxShadow"];
if (NowNode == node["node"]) {
style = node["bgColor"];
}
//处理已经有选中子元素的情况
// if (this.selectedDescendents) {
clearParameters(); //直接撤销重选
// }
}
handleElement(); //每次数组元素有变动,都需要重新处理下
},
selectDescendents: function() { //选择所有子元素操作
handleDescendents();
}
},
});
h = $(".tooldrag").height();
difference = 26 - h; //获得高度值差
if (difference > 0) {
$(".tooldrag").css("cssText", "height:" + (26 + difference) + "px!important")
}
timer = setInterval(function() { //时刻监测相应元素是否存在(防止出现如百度一样元素消失重写body的情况),如果不存在,添加进来
if (document.body != null && document.getElementById("wrapperToolkit") == null) {
this.clearInterval(); //先取消原来的计时器,再设置新的计时器
document.body.append(div); //默认如果toolkit不存在则div和tdiv也不存在
document.body.append(tdiv);
document.body.append(toolkit);
generateToolkit();
// var list = document.getElementsByTagName("a");
// // 对于没有特殊绑定函数的a标签,使他们在新标签页中打开
// for (var i = 0; i < list.length; i++) {
// if (list[i].href.indexOf("javascript") == -1 && list[i].href.indexOf("void") == -1 && list[i].href.indexOf("#") == -1 && list[i].href) {
// list[i].setAttribute("target", "_blank");
// }
// };
// list = document.getElementsByTagName("form");
// // 对于没有特殊绑定函数的form标签,使他们在新标签页中打开
// for (var i = 0; i < list.length; i++) {
// list[i].setAttribute("target", "_blank");
// };
}
}, 3000);
}
//每次对元素进行增删之后需要执行的操作
function handleElement() {
clearReady(); //预备元素每次处理都先处理掉
if (nodeList.length > 1) { //选中了许多元素的情况
app._data.option = relatedTest();
if (app._data.option == 100) {
generateMultiParameters();
} else {
generateParameters(0);
}
} else if (nodeList.length == 1) {
findRelated(); //寻找和元素相关的元素
}
}
function clearParameters(deal = true) //清空参数列表
{
if (deal) //是否取消对选中的子元素进行处理
{
app._data.selectedDescendents = false;
}
for (o of outputParameterNodes) {
o["node"].style.boxShadow = o["boxShadow"];
}
outputParameterNodes.splice(0);
outputParameters.splice(0); //清空原来的参数列表
app._data.valTable = []; //清空展现数组
app._data.selectStatus = false;
}
//根据nodelist列表内的元素生成参数列表
//适合:nodelist中的元素为同类型元素
//type:0为全部文本 1为节点内直接的文字 2为innerhtml 3为outerhtml
//nodetype:0,对应全type0123
//nodetype:1 链接,对应type0123
//nodetype:2 链接地址 对应type0
//nodetype:3 按钮和输入文本框 对应type
//nodetype:4 按钮和输入文本框 对应type
function generateParameters(type, linktext = true, linkhref = true) {
clearParameters(false);
let n = 1;
chrome.storage.local.get({ parameterNum: 1 }, function(items) {
let at = parseInt(new Date().getTime());
n = items.parameterNum;
for (let num = 0; num < nodeList.length; num++) {
let nd = nodeList[num]["node"];
ndPath = nodeList[num]["xpath"];
outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow });
nd.style.boxShadow = boxShadowColor;
let pname = "文本";
let ndText = "";
if (type == 0) {
ndText = $(nd).text();
pname = "文本";
if (nd.tagName == "IMG") {
ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src");
pname = "地址";
} else if (nd.tagName == "INPUT") {
ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
}
} else if (type == 1) {
ndText = $(nd).contents().filter(function() { return this.nodeType === 3; }).text().replace(/\s+/g, '');
pname = "文本";
if (nd.tagName == "IMG") {
ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src");
pname = "地址";
} else if (nd.tagName == "INPUT") {
ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
}
} else if (type == 2) {
ndText = $(nd).html();
pname = "Innerhtml";
} else if (type == 3) {
ndText = $(nd).prop("outerHTML");
pname = "outerHTML";
}
if (num == 0) { //第一个节点新建,后面的增加即可
if (nd.tagName == "IMG") { //如果元素是图片
outputParameters.push({
"nodeType": 4, //节点类型
"contentType": type, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_图片" + pname,
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? "" : ndPath,
"exampleValues": [{ "num": num, "value": ndText }]
});
} else if (nd.tagName == "A") { //如果元素是超链接
if (linktext) {
outputParameters.push({
"nodeType": 1,
"contentType": type, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接" + pname,
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? "" : ndPath,
"exampleValues": [{ "num": num, "value": ndText }]
});
}
if (linkhref) {
outputParameters.push({
"nodeType": 2,
"contentType": type, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接地址",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? "" : ndPath,
"exampleValues": [{ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }]
});
}
} else if (nd.tagName == "INPUT") { //如果元素是输入项
outputParameters.push({
"nodeType": 3,
"contentType": type, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_" + pname,
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? "" : ndPath,
"exampleValues": [{ "num": num, "value": ndText }]
});
} else { //其他所有情况
outputParameters.push({
"nodeType": 0,
"contentType": type, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_" + pname,
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? "" : ndPath,
"exampleValues": [{ "num": num, "value": ndText }]
});
}
} else { //如果元素节点已经存在,则只需要插入值就可以了
if (nd.tagName == "IMG") { //如果元素是图片
outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
} else if (nd.tagName == "A") { //如果元素是超链接
outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
outputParameters[1]["exampleValues"].push({ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") });
} else if (nd.tagName == "INPUT") { //如果元素是输入项
outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
} else { //其他所有情况
outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
}
}
}
let at2 = parseInt(new Date().getTime());
console.log("generateParameters:", at2, at, at2 - at);
generateValTable();
console.log(outputParameters);
});
}
//根据nodelist列表内的元素生成参数列表
//适合:nodelist中的元素为不同类型元素
function generateMultiParameters() {
clearParameters(false);
let n = 1;
chrome.storage.local.get({ parameterNum: 1 }, function(items) {
let at = parseInt(new Date().getTime());
n = items.parameterNum;
for (let num = 0; num < nodeList.length; num++) {
let nd = nodeList[num]["node"];
ndPath = nodeList[num]["xpath"];
outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow });
nd.style.boxShadow = boxShadowColor;
ndText = $(nd).text();
if (nd.tagName == "IMG") { //如果元素是图片
outputParameters.push({
"nodeType": 4, //节点类型
"contentType": 0, // 内容类型
"relative": false, //是否为相对xpath路径
"name": "参数" + (n++) + "_图片地址",
"desc": "", //参数描述
"relativeXpath": ndPath,
"exampleValues": [{ "num": 0, "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src") }]
});
} else if (nd.tagName == "A") { //如果元素是超链接
outputParameters.push({
"nodeType": 1,
"contentType": 0, // 内容类型
"relative": false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接文本",
"desc": "", //参数描述
"relativeXpath": ndPath,
"exampleValues": [{ "num": 0, "value": ndText }]
});
outputParameters.push({
"nodeType": 2,
"contentType": 0, // 内容类型
"relative": false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接地址",
"desc": "", //参数描述
"relativeXpath": ndPath,
"exampleValues": [{ "num": 0, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }]
});
} else if (nd.tagName == "INPUT") { //如果元素是输入项
outputParameters.push({
"nodeType": 3,
"contentType": 0, // 内容类型
"relative": false, //是否为相对xpath路径
"name": "参数" + (n++) + "_文本",
"desc": "", //参数描述
"relativeXpath": ndPath,
"exampleValues": [{ "num": 0, "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value") }]
});
} else { //其他所有情况
outputParameters.push({
"nodeType": 0,
"contentType": 0, // 内容类型
"relative": false, //是否为相对xpath路径
"name": "参数" + (n++) + "_文本",
"desc": "", //参数描述
"relativeXpath": ndPath,
"exampleValues": [{ "num": 0, "value": ndText }]
});
}
}
// console.log(outputParameters);
let at2 = parseInt(new Date().getTime());
console.log("generateMultiParameters", at2, at, at2 - at);
generateValTable(false);
});
}
//处理子元素,对于每个块中多出的特殊元素,需要特殊处理
function handleDescendents() {
let n = 1;
chrome.storage.local.get({ parameterNum: 1 }, function(items) {
let at = parseInt(new Date().getTime());
n = items.parameterNum;
clearParameters(); //清除原来的参数列表
app._data.selectedDescendents = true;
for (let num = 0; num < nodeList.length; num++) {
let tnode = nodeList[num]["node"];
let stack = new Array(); //深度优先搜索遍历元素
stack.push(tnode); //从此节点开始
while (stack.length > 0) {
let nd = stack.pop(); // 挨个取出元素
if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") {
continue; //对A标签内的SPAN元素不进行处理,剪枝,此时子元素根本不加入stack,即实现了此功能
}
ndPath = readXPath(nd, 1, tnode);
let index = -1;
for (let i = 0; i < outputParameters.length; i++) {
if (outputParameters[i]["relativeXpath"] == ndPath) {
index = i;
break;
}
}
outputParameterNodes.push({
"node": nd,
"boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow
});
nd.style.boxShadow = boxShadowColor;
ndText = $(nd).contents().filter(function() {
return this.nodeType === 3;
}).text().replace(/\s+/g, '');
if (index == -1) { //从第二个节点开始,只插入那些不在参数列表中的元素,根据xpath进行寻址
//如果当前节点除了子元素外仍然有其他文字或者该元素是图片/表单项,加入子元素节点
if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") {
if (nd.tagName == "IMG") { //如果元素是图片
outputParameters.push({
"nodeType": 4, //节点类型
"contentType": 1, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只选择了子元素没有选中全部的时候,需要判断
"name": "参数" + (n++) + "_图片地址",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), //同理需要判断
"exampleValues": [{
"num": num,
"value": nd.getAttribute("src") == null ? "" : $(nd).prop("src")
}]
});
} else if (nd.tagName == "A") { //如果元素是超链接
outputParameters.push({
"nodeType": 1,
"contentType": 0, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接文本",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
"exampleValues": [{ "num": num, "value": $(nd).text() }] //注意这里的ndtext是整个a的文字!!!
});
outputParameters.push({
"nodeType": 2,
"contentType": 0, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_链接地址",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
"exampleValues": [{
"num": num,
"value": nd.getAttribute("href") == null ? "" : $(nd).prop("href")
}]
});
} else if (nd.tagName == "INPUT") { //如果元素是输入项
outputParameters.push({
"nodeType": 3,
"contentType": 1, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_文本",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
"exampleValues": [{
"num": num,
"value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
}]
});
} else { //其他所有情况
outputParameters.push({
"nodeType": 0,
"contentType": 1, // 内容类型
"relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
"name": "参数" + (n++) + "_文本",
"desc": "", //参数描述
"relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
"exampleValues": [{ "num": num, "value": ndText }]
});
}
}
} else //如果元素节点已经存在,则只需要插入值就可以了
{
if (nd.tagName == "IMG") { //如果元素是图片
outputParameters[index]["exampleValues"].push({
"num": num,
"value": nd.getAttribute("src") == null ? "" : $(nd).prop("src")
});
} else if (nd.tagName == "A") { //如果元素是超链接
outputParameters[index]["exampleValues"].push({ "num": num, "value": $(nd).text() });
outputParameters[index + 1]["exampleValues"].push({
"num": num,
"value": nd.getAttribute("href") == null ? "" : $(nd).prop("href")
});
} else if (nd.tagName == "INPUT") { //如果元素是输入项
outputParameters[index]["exampleValues"].push({
"num": num,
"value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
});
} else { //其他所有情况
outputParameters[index]["exampleValues"].push({ "num": num, "value": ndText });
}
}
for (let i = nd.children.length - 1; i >= 0; i--) {
stack.push(nd.children[i]);
}
}
}
let at2 = parseInt(new Date().getTime());
console.log("选中子元素", at2, at, at2 - at);
generateValTable();
});
}
//根据参数列表生成可视化参数界面
function generateValTable(multiline = true) {
let paravalues = [];
for (let i = 0; i < outputParameters.length; i++) {
let tvalues = [];
let tindex = 0;
let l = multiline ? nodeList.length : 1;
for (let j = 0; j < l; j++) {
//注意第一个循环条件,index超出界限了就不需要再寻找了,其他的全是空
if (tindex < outputParameters[i]["exampleValues"].length && outputParameters[i]["exampleValues"][tindex]["num"] == j) {
tvalues.push(outputParameters[i]["exampleValues"][tindex]["value"]);
tindex++;
} else {
tvalues.push(" ");
}
}
paravalues.push(tvalues);
}
app._data.valTable = paravalues;
}
// 选中第一个节点,自动寻找同类节点
// 方法:/div[1]/div[2]/div[2]/a[1]
// 从倒数第一个节点开始找,看去掉方括号之后是否元素数目变多,如上面的变成/div[1]/div[2]/div[2]/a
// 如果没有,则恢复原状,然后试试倒数第二个:/div[1]/div[2]/div/a[1]
// 直到找到第一个变多的节点或者追溯到根节点为止
function findRelated() {
let at = parseInt(new Date().getTime());
let testPath = nodeList[0]["xpath"].split("/").splice(1); //分离xpath成 ["html","body","div[0]"]这样子
let nodeNameList = [];
let nodeIndexList = [];
for (i = 0; i < testPath.length; i++) {
nodeNameList.push(testPath[i].split("[")[0]);
if (testPath[i].indexOf("[") >= 0) { //如果存在索引值
nodeIndexList.push(parseInt(testPath[i].split("[")[1].replace("]", ""))); //只留下数字
} else {
nodeIndexList.push(-1);
}
}
var tempPath = "";
for (let i = nodeIndexList.length - 1; i >= 0; i--) {
if (nodeIndexList[i] == -1) { //没有索引值直接跳过
continue;
}
tempIndexList = [...nodeIndexList]; //复刻一个index数组
tempIndexList[i] = -1; //删除索引值
tempPath = combineXpath(nodeNameList, tempIndexList); //生成新的xpath
var result = document.evaluate(tempPath, document, null, XPathResult.ANY_TYPE, null);
result.iterateNext(); //枚举第一个元素
if (result.iterateNext() != null) { //如果能枚举到第二个元素,说明存在同类元素,选中同类元素,结束循环
app.$data.nowPath = tempPath; //标记此元素xpath
pushToReadyList(tempPath);
break;
}
}
let at2 = parseInt(new Date().getTime());
console.log("findRelated", at2, at, at2 - at);
}
//根据path将元素放入readylist中
function pushToReadyList(path) {
result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null);
var node = result.iterateNext(); //枚举第一个元素
while (node) { //只添加不在已选中列表内的元素
let exist = false;
for (o of nodeList) {
if (o["node"] == node) {
exist = true;
break;
}
}
if (!exist) {
readyList.push({ "node": node, "bgColor": node.style.backgroundColor, "boxShadow": node.style.boxShadow == "" || boxShadowColor ? "none" : node.style.boxShadow });
}
node.style.boxShadow = boxShadowColor;
node = result.iterateNext(); //枚举下一个元素
}
}
//将readyList中的元素放入选中节点中
function readyToList(step, dealparameters = true) {
for (o of readyList) {
nodeList.push({ node: o["node"], "step": step, bgColor: o["bgColor"], "boxShadow": o["boxShadow"], xpath: readXPath(o["node"], 1) });
o["node"].style.backgroundColor = selectedColor;
}
clearReady();
if (dealparameters) { //防止出现先选中子元素再选中全部失效的问题
generateParameters(0); //根据nodelist列表内的元素生成参数列表,0代表纯文本
}
}
//根据节点列表和索引列表生成XPATH
// 如:["html","body","div"],[-1,-1,2],生成/html/body/div[2]
function combineXpath(nameList, indexList) {
let finalPath = "";
for (i = 0; i < nameList.length; i++) {
finalPath = finalPath + "/" + nameList[i];
if (indexList[i] != -1) {
finalPath = finalPath + "[" + indexList[i] + "]";
}
}
return finalPath;
}
//专门测试已经选中的这些元素之间有没有相关性
// 举例:
// /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[1]/div[3]/a[22]
// /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/a[25]
// 最终转换为:
// /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div/div[3]/a
function relatedTest() {
let at = new Date().getTime()
var testList = [];
var testpath = "";
for (i = 0; i < nodeList.length; i++) {
var testnumList = []; //用于比较节点索引号不同
var tpath = nodeList[i]["xpath"].split("/").splice(1); //清理第一个空元素
for (j = 0; j < tpath.length; j++) {
if (tpath[j].indexOf("[") >= 0) { //如果存在索引值
testnumList.push(parseInt(tpath[j].split("[")[1].replace("]", ""))); //只留下数字
} else {
testnumList.push(-1);
}
tpath[j] = tpath[j].split("[")[0];
}
tp = tpath.join("/");
if (i > 0 && testpath != tp) { //如果去除括号后元素内存在不一致情况,直接返回默认情况代码100
app.$data.nowPath = ""; //标记此元素xpath
return 100;
}
testpath = tp;
testList.push(testnumList);
}
testpath = testpath.split("/"); //清理第一个空元素
var indexList = []; //记录新生成的xpath
//如果选中的元素属于同样的序列,则计算出序列的最佳xpath表达式
for (j = 0; j < testList[0].length; j++) {
indexList.push(testList[0][j]);
for (i = 1; i < testList.length; i++) {
if (testList[i][j] != testList[i - 1][j]) {
indexList[j] = -1; //不一致就记录成-1
break;
}
}
}
var finalPath = combineXpath(testpath, indexList);
app.$data.nowPath = finalPath; //标记此元素xpath
pushToReadyList(finalPath);
let at2 = parseInt(new Date().getTime());
console.log("手动:", at2, at, at2 - at);
return 50; //先返回给默认码
}
//实现提示框拖拽功能
$('.tooldrag').mousedown(function(e) {
// e.pageX
var positionDiv = $(this).offset();
var distanceX = e.pageX - positionDiv.left;
var distanceY = e.pageY - positionDiv.top;
//alert(distanceX)
// alert(positionDiv.left);
$(document).mousemove(function(e) {
var x = e.clientX - distanceX;
var y = e.clientY - distanceY;
if (x < 0) {
x = 0;
} else if (x > window.innerWidth - $('.tooldrag').outerWidth(true)) {
x = window.innerWidth - $('.tooldrag').outerWidth(true);
}
if (y < 0) {
y = 0;
} else if (y > window.innerHeight - $('.tooldrag').outerHeight(true)) {
y = window.innerHeight - $('.tooldrag').outerHeight(true);
}
$('.tooltips').css({
'right': window.innerWidth - x - $('.tooltips').outerWidth(true) + 'px',
'bottom': window.innerHeight - y - $('.tooltips').outerHeight(true) + 'px',
});
});
$(document).mouseup(function() {
$(document).off('mousemove');
});
});
@@ -0,0 +1 @@
console.log(`'Allo 'Allo! Devtools Extension`)
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,164 @@
//实现与后台和流程图部分的交互
if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
}
startMsg = { "type": 0, msg: "" };
chrome.runtime.sendMessage(startMsg, function(response) {
console.log(response.msg);
}); //每次打开新页面的时候需要告诉后台
console.log("test");
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
if (request["type"] == 1);
sendResponse("回答处理结果");
}
);
function input(value) {
let message = {
"type": "InputText",
"history": history.length, //记录history的长度
"tabIndex": -1,
"xpath": readXPath(nodeList[0]["node"], 0),
"value": value,
};
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
msg = { "type": 2, msg: value };
chrome.runtime.sendMessage(msg);
}
//点击元素操作
function sendSingleClick() {
let message = {
"type": "singleClick",
"history": history.length, //记录history的长度
"tabIndex": -1,
"useLoop": false, //是否使用循环内元素
"xpath": readXPath(nodeList[0]["node"], 0),
};
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//采集单个元素
function collectSingle() {
let message = {
"type": "singleCollect",
"history": history.length, //记录history的长度
"tabIndex": -1,
"parameters": outputParameters,
};
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//采集无规律多元素
function collectMultiNoPattern() {
let message = {
"type": "multiCollectNoPattern",
"history": history.length, //记录history的长度
"tabIndex": -1,
"parameters": outputParameters,
};
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//采集有规律多元素
function collectMultiWithPattern() {
//先点击选择全部然后再
let message = {
"type": "multiCollectWithPattern",
"history": history.length, //记录history的长度
"tabIndex": -1,
"loopType": 1,
"xpath": "", //默认值设置为空
"isDescendents": app._data.selectedDescendents, //标记是否采集的是子元素
"parameters": outputParameters,
};
if (!detectAllSelected()) //如果不是全部选中的话
{
message.loopType = 2; //固定元素列表
}
if (message.loopType == 1) {
message["xpath"] = app._data.nowPath;
} else { //固定元素列表
message["pathList"] = [];
for (let i = 0; i < nodeList.length; i++) {
message["pathList"].push(readXPath(nodeList[i]["node"], 0));
}
}
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//循环点击单个元素
function sendLoopClickSingle(name) {
let message = {
"type": "loopClickSingle",
"history": history.length, //记录history的长度
"tabIndex": -1,
"useLoop": true, //是否使用循环内元素
"xpath": readXPath(nodeList[0]["node"], 0),
"loopType": 0, //循环类型,0为单个元素
"nextPage": false, //是否循环点击下一页
};
if (name == "下一页元素") {
message.nextPage = true;
}
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//循环点击每个元素
function sendLoopClickEvery() {
let message = {
"type": "loopClickEvery",
"history": history.length, //记录history的长度
"tabIndex": -1,
"xpath": "", //默认值设置为空
"useLoop": true, //是否使用循环内元素
"loopType": 1, //循环类型,1为不固定元素列表
};
if (!detectAllSelected()) //如果不是全部选中的话
{
message.loopType = 2; //固定元素列表
}
if (message.loopType == 1) {
message["xpath"] = app._data.nowPath;
} else { //固定元素列表
//有的网站像淘宝,每个元素都有一个独一无二的ID号,这时候就不适用用id进行xpath定位了,这个问题暂时搁置
message["pathList"] = [];
for (let i = 0; i < nodeList.length; i++) {
message["pathList"].push(readXPath(nodeList[i]["node"], 0));
}
}
let msg = { "type": 3, msg: message };
chrome.runtime.sendMessage(msg);
}
//检测是否xpath对应的元素被全选了,个数判断即可
function detectAllSelected() {
if (app._data.nowPath == "") {
return false;
} else {
let num = 0;
let result = document.evaluate(app._data.nowPath, document, null, XPathResult.ANY_TYPE, null);
var node = result.iterateNext(); //枚举第一个元素
while (node) {
// console.log(node.innerHTML);
num++;
node = result.iterateNext();
}
if (num == nodeList.length) {
return true;
} else {
return false;
}
}
}
@@ -0,0 +1 @@
console.log(`'Allo 'Allo! Options`)
+1
View File
@@ -0,0 +1 @@
console.log(`'Allo 'Allo! Popup`)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,139 @@
.tooltips {
width: 330px;
min-height: 300px;
background-color: white;
position: fixed;
z-index: 2147483647;
right: 30px;
bottom: 30px;
font-size: 13px!important;
font-weight: normal!important;
border: solid navy 2px;
-webkit-user-select: none;
/* 文字不可被选中 */
}
.tooldrag {
background-color: navy;
width: 100%;
text-align: center;
font-size: 13px;
height: 26px!important;
padding-top: 8px!important;
color: white;
}
.realcontent {
text-align: left;
padding-top: 10px!important;
padding-bottom: 80px!important;
padding-left: 20px!important;
padding-right: 10px!important;
}
.innercontent {
text-align: left;
padding-top: 5px!important;
padding-left: 12px!important;
}
.innercontent a {
display: inline-block;
text-decoration: none;
margin-top: 2px!important;
font-size: 13px;
color: navy!important;
cursor: pointer;
text-decoration: none!important;
}
.innercontent a:hover {
color: blue!important;
}
.innercontent span {
font-size: 20px;
color: navy;
line-height: normal;
padding-left: 5px!important;
}
.tooltips button {
margin-top: 7px!important;
font-size: 13px;
border-radius: 5px;
border: solid 2px navy;
background-color: white;
color: navy;
width: 100px;
height: 30px;
cursor: pointer;
margin-left: 15px!important;
}
.tooltips input[type=text] {
display: block;
margin-top: 7px!important;
padding-left: 5px!important;
margin-bottom: 7px!important;
font-size: 15px;
border-radius: 5px;
border: solid 2px navy;
width: 204px;
height: 30px;
}
.tooltips button:hover {
color: blue;
}
/* 下面用来对冻结表格首行元素和固定表格宽度和高度设定样式 */
.toolkitcontain {
border: 1px solid #cdd!important;
width: 250px!important;
/* 上面的宽度设定很重要 */
height: 150px;
overflow: auto;
margin-top: 10px!important;
position: relative;
}
.toolkitcontain table {
table-layout: fixed;
word-break: break-all;
word-wrap: break-word;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
.toolkitcontain th,
.toolkitcontain td,
.toolkitcontain tr {
border: 1px solid rgb(78, 78, 78)!important;
height: 25px!important;
width: 100px!important;
text-align: center!important;
font-weight: normal!important;
overflow: hidden!important;
font-size: 11px!important;
padding-left: 1px!important;
padding-right: 0px!important;
padding-top: 0px!important;
padding-bottom: 0px!important
}
.toolkitcontain .toolkittb2 {
position: sticky;
top: 0px;
margin-bottom: 0px;
background-color: azure;
z-index: 1000;
}
.toolkitcontain .toolkittb4 {
position: absolute;
}

Some files were not shown because too many files have changed in this diff Show More