+
✍操作提示框(可点此拖动)
+
+
+
+
特殊点选模式
+
+
● 鼠标移动到元素上后,请右键点击或者按F7键选中页面元素。
+
● 如果不小心左键点选了元素导致页面跳转,直接后退或者切换回标签页即可。
+ {{initial()}}
+
+
+
+ ● 已选中{{numOfList()}}个{{tname()}},
同时发现{{numOfReady()}}个同类元素,您可以:
+
+
+
+
+
+
+
+
+
+ ● 已选择了{{numOfList()}}个同类元素,
另外发现{{numOfReady()}}个同类元素,您可以:
+
+
+
+
+
+
+
+
{{setWidth("290px")}}
+
+
+
+
+
+
+
{{lastElementXPath()}}
+
+
+
+ ● 请输入文字:
+
+
+
+
+
+
+
+`);
+ 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');
+ });
+});
\ No newline at end of file
diff --git a/Extension/EasySpider_zh/scripts/devtools.js b/Extension/EasySpider_zh/scripts/devtools.js
new file mode 100644
index 0000000..cc74945
--- /dev/null
+++ b/Extension/EasySpider_zh/scripts/devtools.js
@@ -0,0 +1 @@
+console.log(`'Allo 'Allo! Devtools Extension`)
diff --git a/Extension/EasySpider_zh/scripts/jquery-3.4.1.min.js b/Extension/EasySpider_zh/scripts/jquery-3.4.1.min.js
new file mode 100644
index 0000000..a1c07fd
--- /dev/null
+++ b/Extension/EasySpider_zh/scripts/jquery-3.4.1.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0
+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/
+
+
\ No newline at end of file
diff --git a/ServiceGrid/frontEnd/FlowChart_CN.html b/ServiceGrid/frontEnd/FlowChart_CN.html
index 5655d43..33b2fad 100644
--- a/ServiceGrid/frontEnd/FlowChart_CN.html
+++ b/ServiceGrid/frontEnd/FlowChart_CN.html
@@ -18,11 +18,22 @@
提示:保存成功!
+