1
0

global.js 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. var language = "en";
  2. var config = {
  3. language: language
  4. };
  5. var global = {
  6. nodeList: [], //已被选中的节点列表
  7. readyList: [], //预备选中的list
  8. outputParameters: [], //输出参数列表
  9. outputParameterNodes: [], //输出参数节点列表
  10. NowNode: null,
  11. xnode: null,
  12. step: 0, //记录这是第几次点击操作
  13. style: "", //记录上个元素的颜色
  14. oe: null, //记录上个元素
  15. app: null,
  16. div: null,
  17. tdiv: null,
  18. selectedColor: "rgba(151,255,255, 0.6)",
  19. defaultbgColor: 'rgba(221,221,255,0.8)',
  20. boxShadowColor: "blue 0px 0px 5px",
  21. lang: config.language,
  22. id: "C" + Math.floor(Math.random() * (99999999)).toString(), //处理不同标签页的handles,生成的id
  23. ws: null,
  24. iframe: false,
  25. markElements: [],
  26. justSend: false,
  27. };
  28. function isInIframe() {
  29. try {
  30. return window.self !== window.parent;
  31. } catch (e) {
  32. return true;
  33. }
  34. }
  35. function getOS() {
  36. if (navigator.userAgent.indexOf('Window') > 0) {
  37. return 'Windows'
  38. } else if (navigator.userAgent.indexOf('Mac') > 0) {
  39. return 'Mac'
  40. } else if (navigator.userAgent.indexOf('Linux') > 0) {
  41. return 'Linux'
  42. } else {
  43. return 'NULL'
  44. }
  45. }
  46. function getElementXPaths(element, parentElement = document.body) {
  47. let paths = [];
  48. let pre_xpath = "";
  49. // if(global.iframe){
  50. // pre_xpath = "//iframe";
  51. // }
  52. paths.push(readXPath(element, 1, parentElement));
  53. paths.push(pre_xpath + "//" + element.tagName.toLowerCase() + "[contains(., '" + element.textContent.slice(0, 10).trim() + "')]");
  54. if (element.id) {
  55. paths.push(pre_xpath + `id("${element.id}")`);
  56. }
  57. if (element.className) {
  58. paths.push(pre_xpath + "//" + element.tagName.toLowerCase() + "[@class='" + element.className + "']");
  59. }
  60. if (element.name) {
  61. paths.push(pre_xpath + "//" + element.tagName.toLowerCase() + "[@name='" + element.name + "']");
  62. }
  63. if (element.alt) {
  64. paths.push(pre_xpath + "//" + element.tagName.toLowerCase() + "[@alt='" + element.alt + "']");
  65. }
  66. paths.push(getAbsoluteXPathWithReverseIndex(element));
  67. console.log("ALL PATHS: " + paths);
  68. return paths;
  69. }
  70. function getAbsoluteXPathWithReverseIndex(element) {
  71. let pre_xpath = "";
  72. // if(global.iframe){
  73. // pre_xpath = "//iframe";
  74. // }
  75. let path = [];
  76. while (element && element.nodeType == Node.ELEMENT_NODE) {
  77. let index = 0;
  78. for (let sibling = element.nextSibling; sibling; sibling = sibling.nextSibling) {
  79. // Ignore document type declaration.
  80. if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
  81. continue;
  82. if (sibling.nodeName == element.nodeName)
  83. ++index;
  84. }
  85. let tagName = element.nodeName.toLowerCase();
  86. let pathIndex = (index ? "[last()-" + index + "]" : "");
  87. path.unshift(tagName + pathIndex);
  88. element = element.parentNode;
  89. }
  90. return pre_xpath + "/" + path.join("/");
  91. }
  92. //返回element相对node节点的xpath,默认的node节点是: /
  93. function readXPath(element, type = 1, node = document.body) {
  94. let pre_xpath = "";
  95. // if(global.iframe){
  96. // pre_xpath = "//iframe";
  97. // }
  98. try {
  99. if (type == 0) //type=0代表默认可通过id生成xpath type=1代表只能从根节点生成xpath, nodeList里必须使用绝对xpath!
  100. {
  101. if (element.id !== "") { //判断id属性,如果这个元素有id,则显示//*[@id="xPath"] 形式内容
  102. return pre_xpath + '//*[@id=\"' + element.id + '\"]';
  103. }
  104. if (element.className != "") { //如果有class且某个class name只有一个元素,则使用class name生成xpath
  105. console.log("class name: " + element.className);
  106. let names = element.className.split(" ");
  107. for (let i = 0; i < names.length; i++) {
  108. if (names[i] != "") {
  109. // return '//*[@class=\"' + names[i] + '\"]';
  110. // console.log('//*[@contains(@class, \"' + names[i] + '\")]');
  111. let elements_of_class = node.getElementsByClassName(names[i]);
  112. // console.log("Length of elements_of_class: " + elements_of_class.length);
  113. if (elements_of_class.length == 1) {
  114. return pre_xpath + '//*[contains(@class, \"' + names[i] + '\")]'
  115. }
  116. }
  117. }
  118. }
  119. }
  120. //这里需要需要主要字符串转译问题,可参考js 动态生成html时字符串和变量转译(注意引号的作用)
  121. if (element == node) { //递归到body处,结束递归
  122. if (node == document.body) {
  123. return pre_xpath + '/html/' + element.tagName.toLowerCase();
  124. } else {
  125. return "";
  126. }
  127. }
  128. let ix = 1, //在nodelist中的位置,且每次点击初始化
  129. siblings = element.parentNode.childNodes; //同级的子元素
  130. for (let i = 0, l = siblings.length; i < l; i++) {
  131. let sibling = siblings[i];
  132. //如果这个元素是siblings数组中的元素,则执行递归操作;arguments.callee代表当前函数的名称
  133. if (sibling == element) {
  134. return readXPath(element.parentNode, type, node) + '/' + element.tagName.toLowerCase() + '[' + (ix) + ']';
  135. //如果不符合,判断是否是element元素,并且是否是相同元素,如果是相同的就开始累加
  136. } else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
  137. //注意此处,为了防止多计算了插入的操作台的3个div元素导致定位错误,这里需要屏蔽掉三个元素的索引号
  138. if (sibling.id != "wrapperDiv" && sibling.id != "wrapperTdiv" && sibling.id != "wrapperToolkit") {
  139. ix++;
  140. }
  141. }
  142. }
  143. } catch {
  144. return pre_xpath + "/"
  145. }
  146. }
  147. //选中元素到列表中
  148. function addEl(e, node = global.NowNode, handle = true) {
  149. // if (tooltips) {
  150. // return;
  151. // }
  152. //如果元素不是鼠标选中的,记录该元素的style,不然按照鼠标选中的元素的style
  153. let style = node == global.NowNode ? global.style : node.style.backgroundColor;
  154. global.NowNode = node;
  155. let exist = false;
  156. for (let o of global.nodeList) {
  157. if (o["node"] == global.oe) {
  158. exist = true;
  159. break;
  160. }
  161. }
  162. //元素没有被添加过才去添加
  163. if (!exist) {
  164. global.step++;
  165. exist = false; //判断刚加入的元素是否在readyList中,如果在,则将所有readylist中的元素全部放入list中
  166. for (let o of global.readyList) {
  167. if (o["node"] == global.oe) {
  168. exist = true;
  169. break;
  170. }
  171. }
  172. if (exist) { //存在在readylist就全选中
  173. readyToList(global.step, false);
  174. if (global.app._data.selectedDescendents) {
  175. handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
  176. }
  177. } else //不然只添加一个元素
  178. {
  179. clearReady(); //readylist清零重新算
  180. global.nodeList.push({
  181. node: global.NowNode,
  182. "step": global.step,
  183. bgColor: style,
  184. "boxShadow": global.NowNode.style.boxShadow == "" || global.boxShadowColor ? "none" : global.NowNode.style.boxShadow,
  185. xpath: readXPath(global.NowNode, 1),
  186. "allXPaths": getElementXPaths(global.NowNode)
  187. });
  188. global.NowNode.style.backgroundColor = global.selectedColor;
  189. }
  190. if(handle){
  191. handleElement(); //处理新状态
  192. }
  193. //将虚线框显示在元素上方但屏蔽其鼠标操作
  194. let pos = global.NowNode.getBoundingClientRect();
  195. global.div.style.display = "block";
  196. global.div.style.height = global.NowNode.offsetHeight + "px";
  197. global.div.style.width = global.NowNode.offsetWidth + "px";
  198. global.div.style.left = pos.left + "px";
  199. global.div.style.top = pos.top + "px";
  200. global.div.style.zIndex = 2147483645;
  201. global.div.style.pointerEvents = "none";
  202. }
  203. // console.log("------");
  204. // for (i = 0; i < global.nodeList.length; i++) {
  205. // console.log(global.nodeList[i]["xpath"]);
  206. // }
  207. //对于可点击元素,屏蔽a标签默认点击事件
  208. event.stopImmediatePropagation();
  209. event.stopPropagation();
  210. event.preventDefault ? event.preventDefault() : event.returnValue = false;
  211. }
  212. //清除选择项
  213. function clearEl(trail=false) {
  214. //如果最后停留的元素被选中,则调整此元素的style为原始style,否则不进行调整
  215. for (let node of global.nodeList) {
  216. node["node"].style.backgroundColor = node["bgColor"];
  217. node["node"].style.boxShadow = node["boxShadow"];
  218. if (global.NowNode == node["node"] && !trail) ;
  219. }
  220. for (let node of global.markElements) {
  221. let element = node.element;
  222. element.style.boxShadow = "none";
  223. }
  224. global.markElements = [];
  225. global.step = 0;
  226. clearReady();
  227. clearParameters();
  228. global.nodeList.splice(0, global.nodeList.length); //清空数组
  229. global.app._data.option = 0; //选项重置
  230. global.app._data.page = 0; //恢复原始页面
  231. // global.app._data.nextPage = 0; //不出现翻页操作提示
  232. }
  233. //清除预备数组
  234. function clearReady() {
  235. for (let node of global.readyList) //节点列表状态恢复原状
  236. {
  237. node["node"].style.boxShadow = node["boxShadow"];
  238. }
  239. global.readyList.splice(0, global.readyList.length); //清空数组
  240. }
  241. //每次对元素进行增删之后需要执行的操作
  242. function handleElement() {
  243. clearReady(); //预备元素每次处理都先处理掉
  244. if (global.nodeList.length > 1) { //选中了许多元素的情况
  245. global.app._data.option = relatedTest();
  246. if (global.app._data.option == 100) {
  247. generateMultiParameters();
  248. } else {
  249. generateParameters(0);
  250. }
  251. } else if (global.nodeList.length == 1) {
  252. findRelated(); //寻找和元素相关的元素
  253. }
  254. }
  255. function clearParameters(deal = true) //清空参数列表
  256. {
  257. if (deal) //是否取消对选中的子元素进行处理
  258. {
  259. global.app._data.selectedDescendents = false;
  260. global.app._data.selectStatus = false;
  261. }
  262. for (let o of global.outputParameterNodes) {
  263. o["node"].style.boxShadow = o["boxShadow"];
  264. }
  265. global.outputParameterNodes.splice(0);
  266. global.outputParameters.splice(0); //清空原来的参数列表
  267. global.app._data.valTable = []; //清空展现数组
  268. }
  269. function LANG(zh, en) {
  270. if (global.lang == "zh") {
  271. return zh;
  272. } else {
  273. return en;
  274. }
  275. }
  276. function parameterName(value) {
  277. if (global.lang == 'zh') {
  278. return value;
  279. } else {
  280. switch (value) {
  281. case "文本":
  282. return "text";
  283. case "链接":
  284. return "link";
  285. case "_链接":
  286. return "_link";
  287. case "_文本":
  288. return "_text";
  289. case "链接文本":
  290. return "link_text";
  291. case "_链接文本":
  292. return "_link_text";
  293. case "链接地址":
  294. return "link_address";
  295. case "_链接地址":
  296. return "_link_address";
  297. case "按钮":
  298. return "button";
  299. case "输入文本框":
  300. return "input_text";
  301. case "单选框":
  302. return "radio";
  303. case "复选框":
  304. return "checkbox";
  305. case "下拉框":
  306. return "select";
  307. case "下拉框选项":
  308. return "select_option";
  309. case "地址":
  310. return "address";
  311. case "参数":
  312. return "param";
  313. case "_图片":
  314. return "_image";
  315. case "_图片地址":
  316. return "_image_address";
  317. case "背景图片地址":
  318. return "background_image_address";
  319. case "_背景图片":
  320. return "_background_image";
  321. case "页面网址":
  322. return "page_url";
  323. case "_页面网址":
  324. return "_page_url";
  325. case "页面标题":
  326. return "page_title";
  327. case "_页面标题":
  328. return "_page_title";
  329. case "选择的选项文本":
  330. return "selected_option_text";
  331. case "_选择的选项文本":
  332. return "_selected_option_text";
  333. case "选择的选项值":
  334. return "selected_option_value";
  335. case "_选择的选项值":
  336. return "_selected_option_value";
  337. default:
  338. return "";
  339. }
  340. }
  341. }
  342. //根据nodelist列表内的元素生成参数列表
  343. //适合:nodelist中的元素为同类型元素
  344. //type:0为全部文本 1为节点内直接的文字 2为innerhtml 3为outerhtml 4为backgroundImg 5为当前页面网址 6为当前页面标题 7为元素截图 8为OCR识别 9为JavaScript返回值 10为选择框选择的值 11为选择框选择的文本
  345. //nodetype:0,对应全type0123
  346. //nodetype:1 链接,对应type0123
  347. //nodetype:2 链接地址 对应type0
  348. //nodetype:3 按钮和输入文本框 对应type
  349. //nodetype:4 按钮和输入文本框 对应type
  350. function generateParameters(type, linktext = true, linkhref = true) {
  351. clearParameters(false);
  352. let n = 1;
  353. chrome.storage.local.get('parameterNum', function (items) {
  354. // let at = parseInt(new Date().getTime());
  355. n = items.parameterNum;
  356. let ndPath = "";
  357. let ndAllXPaths = [];
  358. clearParameters(false);
  359. for (let num = 0; num < global.nodeList.length; num++) {
  360. let nd = global.nodeList[num]["node"];
  361. ndPath = global.nodeList[num]["xpath"];
  362. ndAllXPaths = global.nodeList[num]["allXPaths"];
  363. let unique_index = Math.random().toString(36).substring(2) + Date.now().toString(36);
  364. global.outputParameterNodes.push({
  365. "node": nd,
  366. "unique_index": unique_index,
  367. "boxShadow": nd.style.boxShadow == "" || global.boxShadowColor ? "none" : nd.style.boxShadow
  368. });
  369. nd.style.boxShadow = global.boxShadowColor;
  370. let pname = parameterName("文本");
  371. let ndText = "";
  372. if (type == 0) {
  373. // ndText = $(nd).text();
  374. ndText = nd.textContent;
  375. pname = parameterName("文本");
  376. if (nd.tagName == "IMG") {
  377. ndText = nd.getAttribute("src") == null ? "" : nd.getAttribute("src");
  378. pname = parameterName("地址");
  379. } else if (nd.tagName == "INPUT") {
  380. ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
  381. }
  382. } else if (type == 1) {
  383. // ndText = $(nd).contents().filter(function() { return this.nodeType === 3; }).text().replace(/\s+/g, '');
  384. ndText = "";
  385. let ndContents = nd.childNodes;
  386. for (let i = 0; i < ndContents.length; i++) {
  387. if (ndContents[i].nodeType === 3) { // if it's a text node
  388. ndText += ndContents[i].textContent.trim(); // add its content to the string
  389. }
  390. }
  391. ndText = ndText.replace(/\s+/g, ''); // remove any whitespace characters
  392. pname = parameterName("文本");
  393. if (nd.tagName == "IMG") {
  394. ndText = nd.getAttribute("src") == null ? "" : nd.getAttribute("src");
  395. pname = parameterName("地址");
  396. } else if (nd.tagName == "INPUT") {
  397. ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
  398. }
  399. } else if (type == 2) {
  400. // ndText = $(nd).html();
  401. ndText = nd.innerHTML;
  402. pname = "Innerhtml";
  403. } else if (type == 3) {
  404. // ndText = $(nd).prop("outerHTML");
  405. ndText = nd.outerHTML;
  406. pname = "outerHTML";
  407. } else if (type == 4) {
  408. ndText = nd.style.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, '$2').split(',')[0];
  409. pname = parameterName("背景图片地址");
  410. } else if (type == 5) {
  411. ndText = window.location.href;
  412. pname = parameterName("页面网址");
  413. } else if (type == 6) {
  414. ndText = document.title;
  415. pname = parameterName("页面标题");
  416. } else if (type == 10) {
  417. ndText = nd.value;
  418. pname = parameterName("选择的选项值");
  419. } else if (type == 11) {
  420. ndText = nd.options[nd.selectedIndex].text;
  421. pname = parameterName("选择的选项文本");
  422. }
  423. if (num == 0) { //第一个节点新建,后面的增加即可
  424. if (nd.tagName == "IMG") { //如果元素是图片
  425. global.outputParameters.push({
  426. "nodeType": 4, //节点类型
  427. "contentType": type, // 内容类型
  428. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  429. "name": parameterName("参数") + (n++) + parameterName("_图片") + pname,
  430. "desc": "", //参数描述
  431. "extractType": 0, //提取方式 0 普通 1 OCR
  432. "relativeXPath": global.nodeList.length > 1 ? "" : ndPath,
  433. "allXPaths": global.nodeList.length > 1 ? "" : ndAllXPaths,
  434. "exampleValues": [{"num": num, "value": ndText}],
  435. "unique_index": unique_index,
  436. "iframe": global.iframe,
  437. });
  438. } else if (nd.tagName == "A") { //如果元素是超链接
  439. if (linktext) {
  440. global.outputParameters.push({
  441. "nodeType": 1,
  442. "contentType": type, // 内容类型
  443. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  444. "name": parameterName("参数") + (n++) + parameterName("_链接") + pname,
  445. "desc": "", //参数描述
  446. "extractType": 0, //提取方式 0 普通 1 OCR
  447. "relativeXPath": global.nodeList.length > 1 ? "" : ndPath,
  448. "allXPaths": global.nodeList.length > 1 ? "" : ndAllXPaths,
  449. "exampleValues": [{"num": num, "value": ndText}],
  450. "unique_index": unique_index,
  451. "iframe": global.iframe,
  452. });
  453. }
  454. if (linkhref) {
  455. global.outputParameters.push({
  456. "nodeType": 2,
  457. "contentType": type, // 内容类型
  458. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  459. "name": parameterName("参数") + (n++) + parameterName("_链接地址"),
  460. "desc": "", //参数描述
  461. "relativeXPath": global.nodeList.length > 1 ? "" : ndPath,
  462. "allXPaths": global.nodeList.length > 1 ? "" : ndAllXPaths,
  463. "exampleValues": [{
  464. "num": num,
  465. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  466. }],
  467. "unique_index": unique_index,
  468. "iframe": global.iframe,
  469. });
  470. }
  471. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  472. global.outputParameters.push({
  473. "nodeType": 3,
  474. "contentType": type, // 内容类型
  475. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  476. "name": parameterName("参数") + (n++) + "_" + pname,
  477. "desc": "", //参数描述
  478. "extractType": 0, //提取方式 0 普通 1 OCR
  479. "relativeXPath": global.nodeList.length > 1 ? "" : ndPath,
  480. "allXPaths": global.nodeList.length > 1 ? "" : ndAllXPaths,
  481. "exampleValues": [{"num": num, "value": ndText}],
  482. "unique_index": unique_index,
  483. "iframe": global.iframe,
  484. });
  485. } else { //其他所有情况
  486. global.outputParameters.push({
  487. "nodeType": 0,
  488. "contentType": type, // 内容类型
  489. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  490. "name": parameterName("参数") + (n++) + "_" + pname,
  491. "desc": "", //参数描述
  492. "extractType": 0, //提取方式 0 普通 1 OCR
  493. "relativeXPath": global.nodeList.length > 1 ? "" : ndPath,
  494. "allXPaths": global.nodeList.length > 1 ? "" : ndAllXPaths,
  495. "exampleValues": [{"num": num, "value": ndText}],
  496. "unique_index": unique_index,
  497. "iframe": global.iframe,
  498. });
  499. }
  500. } else { //如果元素节点已经存在,则只需要插入值就可以了
  501. if (nd.tagName == "IMG") { //如果元素是图片
  502. global.outputParameters[0]["exampleValues"].push({"num": num, "value": ndText});
  503. } else if (nd.tagName == "A") { //如果元素是超链接
  504. global.outputParameters[0]["exampleValues"].push({"num": num, "value": ndText});
  505. global.outputParameters[1]["exampleValues"].push({
  506. "num": num,
  507. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  508. });
  509. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  510. global.outputParameters[0]["exampleValues"].push({"num": num, "value": ndText});
  511. } else { //其他所有情况
  512. global.outputParameters[0]["exampleValues"].push({"num": num, "value": ndText});
  513. }
  514. }
  515. }
  516. // let at2 = parseInt(new Date().getTime());
  517. // console.log("generateParameters:", at2, at, at2 - at);
  518. generateValTable();
  519. console.log(global.outputParameters);
  520. });
  521. console.log("Generate Parameters");
  522. }
  523. //根据nodelist列表内的元素生成参数列表
  524. //适合:nodelist中的元素为不同类型元素
  525. function generateMultiParameters() {
  526. clearParameters(false);
  527. let n = 1;
  528. chrome.storage.local.get({parameterNum: 1}, function (items) {
  529. // let at = parseInt(new Date().getTime());
  530. n = items.parameterNum;
  531. let ndText, ndPath, ndAllXPaths;
  532. for (let num = 0; num < global.nodeList.length; num++) {
  533. let nd = global.nodeList[num]["node"];
  534. ndPath = global.nodeList[num]["xpath"];
  535. ndAllXPaths = global.nodeList[num]["allXPaths"];
  536. let unique_index = Math.random().toString(36).substring(2) + Date.now().toString(36);
  537. global.outputParameterNodes.push({
  538. "node": nd,
  539. "unique_index": unique_index,
  540. "boxShadow": nd.style.boxShadow == "" || global.boxShadowColor ? "none" : nd.style.boxShadow
  541. });
  542. nd.style.boxShadow = global.boxShadowColor;
  543. // ndText = $(nd).text();
  544. ndText = nd.textContent;
  545. if (nd.tagName == "IMG") { //如果元素是图片
  546. global.outputParameters.push({
  547. "nodeType": 4, //节点类型
  548. "contentType": 0, // 内容类型
  549. "relative": false, //是否为相对xpath路径
  550. "name": parameterName("参数") + (n++) + parameterName("_图片地址"),
  551. "desc": "", //参数描述
  552. "relativeXPath": ndPath,
  553. "allXPaths": ndAllXPaths,
  554. "exampleValues": [{
  555. "num": 0,
  556. "value": nd.getAttribute("src") == null ? "" : nd.getAttribute("src")
  557. }],
  558. "unique_index": unique_index,
  559. "iframe": global.iframe,
  560. });
  561. } else if (nd.tagName == "A") { //如果元素是超链接
  562. global.outputParameters.push({
  563. "nodeType": 1,
  564. "contentType": 0, // 内容类型
  565. "relative": false, //是否为相对xpath路径
  566. "name": parameterName("参数") + (n++) + parameterName("_链接文本"),
  567. "desc": "", //参数描述
  568. "relativeXPath": ndPath,
  569. "allXPaths": ndAllXPaths,
  570. "exampleValues": [{"num": 0, "value": ndText}],
  571. "unique_index": unique_index,
  572. "iframe": global.iframe,
  573. });
  574. global.outputParameters.push({
  575. "nodeType": 2,
  576. "contentType": 0, // 内容类型
  577. "relative": false, //是否为相对xpath路径
  578. "name": parameterName("参数") + (n++) + parameterName("_链接地址"),
  579. "desc": "", //参数描述
  580. "relativeXPath": ndPath,
  581. "allXPaths": ndAllXPaths,
  582. "exampleValues": [{
  583. "num": 0,
  584. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  585. }],
  586. "unique_index": unique_index,
  587. "iframe": global.iframe,
  588. });
  589. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  590. global.outputParameters.push({
  591. "nodeType": 3,
  592. "contentType": 0, // 内容类型
  593. "relative": false, //是否为相对xpath路径
  594. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  595. "desc": "", //参数描述
  596. "relativeXPath": ndPath,
  597. "allXPaths": ndAllXPaths,
  598. "exampleValues": [{
  599. "num": 0,
  600. "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
  601. }],
  602. "unique_index": unique_index,
  603. "iframe": global.iframe,
  604. });
  605. } else { //其他所有情况
  606. global.outputParameters.push({
  607. "nodeType": 0,
  608. "contentType": 0, // 内容类型
  609. "relative": false, //是否为相对xpath路径
  610. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  611. "desc": "", //参数描述
  612. "relativeXPath": ndPath,
  613. "allXPaths": ndAllXPaths,
  614. "exampleValues": [{"num": 0, "value": ndText}],
  615. "unique_index": unique_index,
  616. "iframe": global.iframe,
  617. });
  618. }
  619. }
  620. // console.log(global.outputParameters);
  621. // let at2 = parseInt(new Date().getTime());
  622. // console.log("generateMultiParameters", at2, at, at2 - at);
  623. generateValTable(false);
  624. });
  625. }
  626. //处理子元素,对于每个块中多出的特殊元素,需要特殊处理
  627. function handleDescendents(mode = 0) {
  628. let n = 1;
  629. chrome.storage.local.get({parameterNum: 1}, function (items) {
  630. // let at = parseInt(new Date().getTime());
  631. n = items.parameterNum;
  632. clearParameters(); //清除原来的参数列表
  633. global.app._data.selectedDescendents = true;
  634. let ndText, ndPath, ndAllPaths;
  635. if (mode == 2) {
  636. let xpath_list = [];
  637. // mode == 1; //如果是选中全部块的共有子元素,则先选中和第一个块相同的子元素,然后最后再删除第一个块中和其他块不同的子元素
  638. for (let num = 0; num < global.nodeList.length; num++) {
  639. let node_xpaths = [];
  640. let tnode = global.nodeList[num]["node"];
  641. let stack = new Array(); //深度优先搜索遍历元素
  642. stack.push(tnode); //从此节点开始
  643. while (stack.length > 0) {
  644. let nd = stack.pop(); // 挨个取出元素
  645. if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") {
  646. continue; //对A标签内的SPAN元素不进行处理,剪枝,此时子元素根本不加入stack,即实现了此功能
  647. }
  648. ndPath = readXPath(nd, 1, tnode);
  649. node_xpaths.push(ndPath);
  650. for (let i = nd.children.length - 1; i >= 0; i--) {
  651. stack.push(nd.children[i]);
  652. }
  653. }
  654. xpath_list.push(node_xpaths);
  655. }
  656. // 取第一个子数组作为初始的共有元素集合
  657. let commonXPaths = new Set(xpath_list[0]);
  658. // 遍历剩余的子数组
  659. for (let i = 1; i < xpath_list.length; i++) {
  660. // 使用过滤函数来筛选出与共有元素集合中的元素相同的元素
  661. commonXPaths = new Set(xpath_list[i].filter(element => commonXPaths.has(element)));
  662. }
  663. // 将共有元素集合转换为数组
  664. let commonXPathList = Array.from(commonXPaths);
  665. // console.log(commonXPathList);
  666. let hash = {}; //记录index和数组位置的对应关系
  667. for (let num = 0; num < global.nodeList.length; num++) {
  668. let tnode = global.nodeList[num]["node"];
  669. let stack = new Array(); //深度优先搜索遍历元素
  670. stack.push(tnode); //从此节点开始
  671. while (stack.length > 0) {
  672. let nd = stack.pop(); // 挨个取出元素
  673. if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") {
  674. continue; //对A标签内的SPAN元素不进行处理,剪枝,此时子元素根本不加入stack,即实现了此功能
  675. }
  676. ndPath = readXPath(nd, 1, tnode);
  677. ndAllPaths = getElementXPaths(nd, tnode);
  678. let index = -1;
  679. for (let i = 0; i < commonXPathList.length; i++) {
  680. if (commonXPathList[i] == ndPath) {
  681. index = i;
  682. break;
  683. }
  684. }
  685. if (index != -1) { //如果是共有元素
  686. let unique_index = ndPath;
  687. ndText = "";
  688. let ndContents = nd.childNodes;
  689. for (let i = 0; i < ndContents.length; i++) {
  690. if (ndContents[i].nodeType === 3) { // if it's a text node
  691. ndText += ndContents[i].textContent.trim(); // add its content to the string
  692. }
  693. }
  694. ndText = ndText.replace(/\s+/g, ''); // remove any whitespace characters
  695. if (ndText != "" || nd == tnode) {
  696. global.outputParameterNodes.push({
  697. "node": nd,
  698. "unique_index": unique_index,
  699. "boxShadow": nd.style.boxShadow == "" || global.boxShadowColor ? "none" : nd.style.boxShadow
  700. });
  701. nd.style.boxShadow = global.boxShadowColor;
  702. }
  703. // console.log("Hash", hash);
  704. if (num == 0) { //从第二个节点开始,只插入那些不在参数列表中的元素,根据xpath进行寻址
  705. //如果当前节点除了子元素外仍然有其他文字或者该元素是图片/表单项,加入子元素节点
  706. if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") {
  707. hash[index] = global.outputParameters.length;
  708. if (nd.tagName == "IMG") { //如果元素是图片
  709. global.outputParameters.push({
  710. "nodeType": 4, //节点类型
  711. "contentType": 1, // 内容类型
  712. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只选择了子元素没有选中全部的时候,需要判断
  713. "name": parameterName("参数") + (n++) + parameterName("_图片地址"),
  714. "desc": "", //参数描述
  715. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd), //同理需要判断
  716. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  717. "exampleValues": [{
  718. "num": num,
  719. "value": nd.getAttribute("src") == null ? "" : nd.getAttribute("src")
  720. }],
  721. "unique_index": unique_index,
  722. "iframe": global.iframe,
  723. });
  724. } else if (nd.tagName == "A") { //如果元素是超链接
  725. global.outputParameters.push({
  726. "nodeType": 1,
  727. "contentType": 0, // 内容类型
  728. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  729. "name": parameterName("参数") + (n++) + parameterName("_链接文本"),
  730. "desc": "", //参数描述
  731. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  732. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  733. "exampleValues": [{"num": num, "value": nd.textContent}], //注意这里的ndtext是整个a的文字!!!
  734. "unique_index": unique_index,
  735. "iframe": global.iframe,
  736. });
  737. global.outputParameters.push({
  738. "nodeType": 2,
  739. "contentType": 0, // 内容类型
  740. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  741. "name": parameterName("参数") + (n++) + parameterName("_链接地址"),
  742. "desc": "", //参数描述
  743. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  744. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  745. "exampleValues": [{
  746. "num": num,
  747. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  748. }],
  749. "unique_index": unique_index,
  750. "iframe": global.iframe,
  751. });
  752. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  753. global.outputParameters.push({
  754. "nodeType": 3,
  755. "contentType": 1, // 内容类型
  756. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  757. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  758. "desc": "", //参数描述
  759. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  760. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  761. "exampleValues": [{
  762. "num": num,
  763. "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
  764. }],
  765. "unique_index": unique_index,
  766. "iframe": global.iframe,
  767. });
  768. } else { //其他所有情况
  769. global.outputParameters.push({
  770. "nodeType": 0,
  771. "contentType": 1, // 内容类型
  772. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  773. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  774. "desc": "", //参数描述
  775. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  776. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  777. "exampleValues": [{"num": num, "value": ndText}],
  778. "unique_index": unique_index,
  779. "iframe": global.iframe,
  780. });
  781. }
  782. }
  783. } else //如果元素节点已经存在,则只需要插入值就可以了
  784. {
  785. try {
  786. if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") {
  787. if (nd.tagName == "IMG") { //如果元素是图片
  788. global.outputParameters[hash[index]]["exampleValues"].push({
  789. "num": num,
  790. "value": nd.getAttribute("src") == null ? "" : nd.getAttribute("src")
  791. });
  792. } else if (nd.tagName == "A") { //如果元素是超链接
  793. global.outputParameters[hash[index]]["exampleValues"].push({
  794. "num": num,
  795. "value": nd.textContent
  796. });
  797. global.outputParameters[hash[index] + 1]["exampleValues"].push({
  798. "num": num,
  799. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  800. });
  801. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  802. global.outputParameters[hash[index]]["exampleValues"].push({
  803. "num": num,
  804. "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
  805. });
  806. } else { //其他所有情况
  807. global.outputParameters[hash[index]]["exampleValues"].push({
  808. "num": num,
  809. "value": ndText
  810. });
  811. }
  812. }
  813. } catch (e) {
  814. console.log("Error: -----------------------\n\n", e);
  815. }
  816. }
  817. }
  818. for (let i = nd.children.length - 1; i >= 0; i--) {
  819. stack.push(nd.children[i]);
  820. }
  821. }
  822. }
  823. } else {
  824. for (let num = 0; num < global.nodeList.length; num++) {
  825. let tnode = global.nodeList[num]["node"];
  826. let stack = new Array(); //深度优先搜索遍历元素
  827. stack.push(tnode); //从此节点开始
  828. while (stack.length > 0) {
  829. let nd = stack.pop(); // 挨个取出元素
  830. if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") {
  831. continue; //对A标签内的SPAN元素不进行处理,剪枝,此时子元素根本不加入stack,即实现了此功能
  832. }
  833. ndPath = readXPath(nd, 1, tnode);
  834. ndAllPaths = getElementXPaths(nd, tnode);
  835. let index = -1;
  836. for (let i = 0; i < global.outputParameters.length; i++) {
  837. if (global.outputParameters[i]["relativeXPath"] == ndPath) {
  838. index = i;
  839. break;
  840. }
  841. }
  842. ndText = "";
  843. let ndContents = nd.childNodes;
  844. for (let i = 0; i < ndContents.length; i++) {
  845. if (ndContents[i].nodeType === 3) { // if it's a text node
  846. ndText += ndContents[i].textContent.trim(); // add its content to the string
  847. }
  848. }
  849. ndText = ndText.replace(/\s+/g, ''); // remove any whitespace characters
  850. let unique_index = ndPath;
  851. if (ndText != "" || nd == tnode) {
  852. if (mode == 0 || (mode == 1 && (index != -1 || num == 0))) { //如果不是应选尽选,则只添加和第一个元素相同类型的子元素
  853. global.outputParameterNodes.push({
  854. "node": nd,
  855. "unique_index": unique_index,
  856. "boxShadow": nd.style.boxShadow == "" || global.boxShadowColor ? "none" : nd.style.boxShadow
  857. });
  858. nd.style.boxShadow = global.boxShadowColor;
  859. } else if (mode == 1 && nd == tnode) { //最外层元素标记一下
  860. nd.style.boxShadow = global.boxShadowColor;
  861. }
  862. }
  863. if (index == -1) { //从第二个节点开始,只插入那些不在参数列表中的元素,根据xpath进行寻址
  864. //如果当前节点除了子元素外仍然有其他文字或者该元素是图片/表单项,加入子元素节点
  865. if (!(mode == 1 && num > 0)) { //如果不是应选尽选,则只添加和第一个元素相同类型的子元素
  866. if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") {
  867. if (nd.tagName == "IMG") { //如果元素是图片
  868. global.outputParameters.push({
  869. "nodeType": 4, //节点类型
  870. "contentType": 1, // 内容类型
  871. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只选择了子元素没有选中全部的时候,需要判断
  872. "name": parameterName("参数") + (n++) + parameterName("_图片地址"),
  873. "desc": "", //参数描述
  874. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd), //同理需要判断
  875. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  876. "exampleValues": [{
  877. "num": num,
  878. "value": nd.getAttribute("src") == null ? "" : nd.getAttribute("src")
  879. }],
  880. "unique_index": unique_index,
  881. "iframe": global.iframe,
  882. });
  883. } else if (nd.tagName == "A") { //如果元素是超链接
  884. global.outputParameters.push({
  885. "nodeType": 1,
  886. "contentType": 0, // 内容类型
  887. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  888. "name": parameterName("参数") + (n++) + parameterName("_链接文本"),
  889. "desc": "", //参数描述
  890. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  891. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  892. "exampleValues": [{"num": num, "value": nd.textContent}], //注意这里的ndtext是整个a的文字!!!
  893. "unique_index": unique_index,
  894. "iframe": global.iframe,
  895. });
  896. global.outputParameters.push({
  897. "nodeType": 2,
  898. "contentType": 0, // 内容类型
  899. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  900. "name": parameterName("参数") + (n++) + parameterName("_链接地址"),
  901. "desc": "", //参数描述
  902. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  903. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  904. "exampleValues": [{
  905. "num": num,
  906. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  907. }],
  908. "unique_index": unique_index,
  909. "iframe": global.iframe,
  910. });
  911. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  912. global.outputParameters.push({
  913. "nodeType": 3,
  914. "contentType": 1, // 内容类型
  915. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  916. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  917. "desc": "", //参数描述
  918. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  919. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  920. "exampleValues": [{
  921. "num": num,
  922. "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
  923. }],
  924. "unique_index": unique_index,
  925. "iframe": global.iframe,
  926. });
  927. } else { //其他所有情况
  928. global.outputParameters.push({
  929. "nodeType": 0,
  930. "contentType": 1, // 内容类型
  931. "relative": global.nodeList.length > 1 ? true : false, //是否为相对xpath路径
  932. "name": parameterName("参数") + (n++) + parameterName("_文本"),
  933. "desc": "", //参数描述
  934. "relativeXPath": global.nodeList.length > 1 ? ndPath : readXPath(nd),
  935. "allXPaths": global.nodeList.length > 1 ? ndAllPaths : getElementXPaths(nd),
  936. "exampleValues": [{"num": num, "value": ndText}],
  937. "unique_index": unique_index,
  938. "iframe": global.iframe,
  939. });
  940. }
  941. }
  942. }
  943. } else //如果元素节点已经存在,则只需要插入值就可以了
  944. {
  945. if (nd.tagName == "IMG") { //如果元素是图片
  946. global.outputParameters[index]["exampleValues"].push({
  947. "num": num,
  948. "value": nd.getAttribute("src") == null ? "" : nd.getAttribute("src")
  949. });
  950. } else if (nd.tagName == "A") { //如果元素是超链接
  951. global.outputParameters[index]["exampleValues"].push({"num": num, "value": nd.textContent});
  952. global.outputParameters[index + 1]["exampleValues"].push({
  953. "num": num,
  954. "value": nd.getAttribute("href") == null ? "" : nd.getAttribute("href")
  955. });
  956. } else if (nd.tagName == "INPUT") { //如果元素是输入项
  957. global.outputParameters[index]["exampleValues"].push({
  958. "num": num,
  959. "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
  960. });
  961. } else { //其他所有情况
  962. global.outputParameters[index]["exampleValues"].push({"num": num, "value": ndText});
  963. }
  964. }
  965. for (let i = nd.children.length - 1; i >= 0; i--) {
  966. stack.push(nd.children[i]);
  967. }
  968. }
  969. }
  970. }
  971. // let at2 = parseInt(new Date().getTime());
  972. // console.log("选中子元素", at2, at, at2 - at);
  973. generateValTable();
  974. });
  975. }
  976. //根据参数列表生成可视化参数界面
  977. function generateValTable(multiline = true) {
  978. let paraValues = [];
  979. for (let i = 0; i < global.outputParameters.length; i++) {
  980. let tValues = [];
  981. let tindex = 0;
  982. let l = multiline ? global.nodeList.length : 1;
  983. for (let j = 0; j < l; j++) {
  984. //注意第一个循环条件,index超出界限了就不需要再寻找了,其他的全是空
  985. if (tindex < global.outputParameters[i]["exampleValues"].length && global.outputParameters[i]["exampleValues"][tindex]["num"] == j) {
  986. tValues.push(global.outputParameters[i]["exampleValues"][tindex]["value"]);
  987. tindex++;
  988. } else {
  989. tValues.push(" ");
  990. }
  991. }
  992. paraValues.push(tValues);
  993. }
  994. global.app._data.valTable = paraValues;
  995. // console.log("生成参数表格", paraValues);
  996. }
  997. // 选中第一个节点,自动寻找同类节点
  998. // 方法:/div[1]/div[2]/div[2]/a[1]
  999. // 从倒数第一个节点开始找,看去掉方括号之后是否元素数目变多,如上面的变成/div[1]/div[2]/div[2]/a
  1000. // 如果没有,则恢复原状,然后试试倒数第二个:/div[1]/div[2]/div/a[1]
  1001. // 直到找到第一个变多的节点或者追溯到根节点为止
  1002. function findRelated() {
  1003. // let at = parseInt(new Date().getTime());
  1004. let testPath = global.nodeList[0]["xpath"].replace("//iframe", "").split("/").splice(1); //分离xpath成 ["html","body","div[0]"]这样子
  1005. let nodeNameList = [];
  1006. let nodeIndexList = [];
  1007. for (let i = 0; i < testPath.length; i++) {
  1008. nodeNameList.push(testPath[i].split("[")[0]);
  1009. if (testPath[i].indexOf("[") >= 0) { //如果存在索引值
  1010. nodeIndexList.push(parseInt(testPath[i].split("[")[1].replace("]", ""))); //只留下数字
  1011. } else {
  1012. nodeIndexList.push(-1);
  1013. }
  1014. }
  1015. let tempPath = "";
  1016. for (let i = nodeIndexList.length - 1; i >= 0; i--) {
  1017. if (nodeIndexList[i] == -1) { //没有索引值直接跳过
  1018. continue;
  1019. }
  1020. let tempIndexList = [...nodeIndexList]; //复刻一个index数组
  1021. tempIndexList[i] = -1; //删除索引值
  1022. tempPath = combineXpath(nodeNameList, tempIndexList); //生成新的xpath
  1023. let result = document.evaluate(tempPath, document, null, XPathResult.ANY_TYPE, null);
  1024. result.iterateNext(); //枚举第一个元素
  1025. if (result.iterateNext() != null) { //如果能枚举到第二个元素,说明存在同类元素,选中同类元素,结束循环
  1026. global.app.$data.nowPath = tempPath; //标记此元素xpath
  1027. let element = document.evaluate(tempPath, document, null, XPathResult.ANY_TYPE, null).iterateNext();
  1028. console.log("tempPath:", tempPath, "element:", element);
  1029. global.app.$data.nowAllPaths = getElementXPaths(element); //标记此元素xpath
  1030. pushToReadyList(tempPath);
  1031. break;
  1032. }
  1033. }
  1034. // let at2 = parseInt(new Date().getTime());
  1035. // console.log("findRelated:", at2, at, at2 - at);
  1036. }
  1037. //根据path将元素放入readylist中
  1038. function pushToReadyList(path) {
  1039. let result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null);
  1040. let node = result.iterateNext(); //枚举第一个元素
  1041. while (node) { //只添加不在已选中列表内的元素
  1042. let exist = false;
  1043. for (let o of global.nodeList) {
  1044. if (o["node"] == node) {
  1045. exist = true;
  1046. break;
  1047. }
  1048. }
  1049. if (!exist) {
  1050. global.readyList.push({
  1051. "node": node,
  1052. "bgColor": node.style.backgroundColor,
  1053. "boxShadow": node.style.boxShadow == "" || global.boxShadowColor ? "none" : node.style.boxShadow
  1054. });
  1055. }
  1056. node.style.boxShadow = global.boxShadowColor;
  1057. node = result.iterateNext(); //枚举下一个元素
  1058. }
  1059. }
  1060. function selectAllElements(context=null) {
  1061. global.step++;
  1062. readyToList(global.step, false);
  1063. handleElement();
  1064. if (context.selectedDescendents) {
  1065. handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
  1066. }
  1067. }
  1068. //将readyList中的元素放入选中节点中
  1069. function readyToList(step, dealparameters = true) {
  1070. for (let o of global.readyList) {
  1071. global.nodeList.push({
  1072. node: o["node"],
  1073. "step": global.step,
  1074. bgColor: o["bgColor"],
  1075. "boxShadow": o["boxShadow"],
  1076. xpath: readXPath(o["node"], 1),
  1077. "allXPaths": getElementXPaths(o["node"])
  1078. });
  1079. o["node"].style.backgroundColor = global.selectedColor;
  1080. }
  1081. clearReady();
  1082. if (dealparameters) { //防止出现先选中子元素再选中全部失效的问题
  1083. generateParameters(0); //根据nodelist列表内的元素生成参数列表,0代表纯文本
  1084. }
  1085. }
  1086. //根据节点列表和索引列表生成XPATH
  1087. // 如:["html","body","div"],[-1,-1,2],生成/html/body/div[2]
  1088. function combineXpath(nameList, indexList) {
  1089. let finalPath = "";
  1090. for (let i = 0; i < nameList.length; i++) {
  1091. finalPath = finalPath + "/" + nameList[i];
  1092. if (indexList[i] != -1) {
  1093. finalPath = finalPath + "[" + indexList[i] + "]";
  1094. }
  1095. }
  1096. return finalPath;
  1097. }
  1098. //专门测试已经选中的这些元素之间有没有相关性
  1099. // 举例:
  1100. // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[1]/div[3]/a[22]
  1101. // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/a[25]
  1102. // 最终转换为:
  1103. // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div/div[3]/a
  1104. function relatedTest() {
  1105. // let at = new Date().getTime()
  1106. let testList = [];
  1107. let testpath = "";
  1108. for (let i = 0; i < global.nodeList.length; i++) {
  1109. let testnumList = []; //用于比较节点索引号不同
  1110. let tpath = global.nodeList[i]["xpath"].replace("//iframe", "").split("/").splice(1); //清理第一个空元素
  1111. for (let j = 0; j < tpath.length; j++) {
  1112. if (tpath[j].indexOf("[") >= 0) { //如果存在索引值
  1113. testnumList.push(parseInt(tpath[j].split("[")[1].replace("]", ""))); //只留下数字
  1114. } else {
  1115. testnumList.push(-1);
  1116. }
  1117. tpath[j] = tpath[j].split("[")[0];
  1118. }
  1119. let tp = tpath.join("/");
  1120. if (i > 0 && testpath != tp) { //如果去除括号后元素内存在不一致情况,直接返回默认情况代码100
  1121. global.app.$data.nowPath = ""; //标记此元素xpath
  1122. return 100;
  1123. }
  1124. testpath = tp;
  1125. testList.push(testnumList);
  1126. }
  1127. testpath = testpath.split("/"); //清理第一个空元素
  1128. let indexList = []; //记录新生成的xpath
  1129. //如果选中的元素属于同样的序列,则计算出序列的最佳xpath表达式
  1130. for (let j = 0; j < testList[0].length; j++) {
  1131. indexList.push(testList[0][j]);
  1132. for (let i = 1; i < testList.length; i++) {
  1133. if (testList[i][j] != testList[i - 1][j]) {
  1134. indexList[j] = -1; //不一致就记录成-1
  1135. break;
  1136. }
  1137. }
  1138. }
  1139. let finalPath = combineXpath(testpath, indexList);
  1140. let element = document.evaluate(finalPath, document, null, XPathResult.ANY_TYPE, null).iterateNext();
  1141. global.app.$data.nowAllPaths = getElementXPaths(element); //标记此元素xpath
  1142. console.log("finalPath:", finalPath, "element:", element);
  1143. global.app.$data.nowPath = finalPath; //标记此元素xpath
  1144. pushToReadyList(finalPath);
  1145. // let at2 = parseInt(new Date().getTime());
  1146. // console.log("手动:", at2, at, at2 - at);
  1147. return 50; //先返回给默认码
  1148. }
  1149. export { LANG, addEl, clearEl, clearParameters, clearReady, combineXpath, findRelated, generateMultiParameters, generateParameters, generateValTable, getElementXPaths, getOS, global, handleDescendents, handleElement, isInIframe, pushToReadyList, readXPath, readyToList, relatedTest, selectAllElements };