page.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. let nowFileName = "";
  2. let jsonInfo = {};
  3. let tabId = "";
  4. let nodeObj;
  5. let jslist;
  6. function InitTable() {
  7. window.TabInstance = $("#filterTable")
  8. .dxDataGrid({
  9. dataSource: [],
  10. keyExpr: "resource_detail_id",
  11. remoteOperations: false,
  12. searchPanel: {
  13. visible: true,
  14. highlightCaseSensitive: true,
  15. },
  16. groupPanel: { visible: true },
  17. grouping: {
  18. allowCollapsing: true,
  19. autoExpandAll: true,
  20. expandMode: "rowClick",
  21. },
  22. selection: {
  23. mode: "single",
  24. },
  25. allowColumnReordering: true,
  26. rowAlternationEnabled: true,
  27. showBorders: true,
  28. height: "100%",
  29. columns: [
  30. {
  31. dataField: "JS文件",
  32. dataType: "JS文件",
  33. groupIndex: 0,
  34. },
  35. {
  36. dataField: "过滤器",
  37. caption: "过滤器",
  38. },
  39. {
  40. dataField: "选择器类型",
  41. dataType: "选择器类型",
  42. },
  43. {
  44. dataField: "调用方式",
  45. dataType: "调用方式",
  46. },
  47. {
  48. dataField: "所在位置",
  49. dataType: "所在位置",
  50. },
  51. {
  52. dataField: "DOM操作分类",
  53. dataType: "DOM操作分类",
  54. },
  55. ],
  56. onContentReady(e) {},
  57. onSelectionChanged: function (selectedItems) {
  58. let data = selectedItems.selectedRowsData[0];
  59. if (data) {
  60. let ast = data.astJSON;
  61. if (data.JS文件 !== nowFileName) {
  62. nowFileName = data.JS文件;
  63. let code = window.fileList.find((o) => o.name === data.JS文件).code;
  64. //更改JS代码
  65. jsCode.SetCode(code);
  66. //更改ast
  67. //window.ShowASTTree(ast, document.getElementById('astJson'))
  68. }
  69. //jscode定位
  70. let {
  71. defineNode: {
  72. iid,
  73. loc: { end, start },
  74. },
  75. } = data.source_data;
  76. {
  77. //移出所有高亮
  78. jsCode.RemoveAllHighlight();
  79. //设置高亮
  80. jsCode.CreateHighlight({
  81. startLine: start?.line,
  82. startColumn: start?.column + 1,
  83. endLine: end?.line,
  84. endColumn: end?.column + 1,
  85. });
  86. }
  87. {
  88. // //ast定位
  89. // let jsonNode = document.getElementById(iid);
  90. // if (jsonNode) {
  91. // let textNode = Array.from(jsonNode.parentNode.childNodes).find(item => item.classList.contains("node-text"));
  92. // $("#astJson").find(".monaco-highlight").removeClass("monaco-highlight");
  93. // textNode?.classList?.add("monaco-highlight");
  94. // scrollTo(jsonNode)
  95. // }
  96. }
  97. }
  98. },
  99. })
  100. .dxDataGrid("instance");
  101. window.CSSTabInstance = $("#cssJson")
  102. .dxDataGrid({
  103. dataSource: [],
  104. keyExpr: "id",
  105. remoteOperations: false,
  106. searchPanel: {
  107. visible: true,
  108. highlightCaseSensitive: true,
  109. },
  110. selection: {
  111. mode: "single",
  112. },
  113. allowColumnReordering: true,
  114. rowAlternationEnabled: true,
  115. showBorders: true,
  116. height: "100%",
  117. paging: {
  118. enabled: false,
  119. pageSize: 0,
  120. },
  121. columns: [
  122. {
  123. dataField: "key",
  124. caption: "名称",
  125. },
  126. {
  127. dataField: "value",
  128. caption: "生效值",
  129. },
  130. ],
  131. onSelectionChanged: function (selectedItems) {
  132. let data = selectedItems.selectedRowsData[0];
  133. if (data) {
  134. CSSBelongInstance.option({
  135. dataSource: findPropRef(data.key, jsonInfo).map((s, i) => ({
  136. ...s,
  137. id: i,
  138. })),
  139. });
  140. }
  141. },
  142. })
  143. .dxDataGrid("instance");
  144. window.CSSBelongInstance = $("#cssBelong")
  145. .dxDataGrid({
  146. dataSource: [],
  147. keyExpr: "id",
  148. remoteOperations: false,
  149. searchPanel: {
  150. visible: true,
  151. highlightCaseSensitive: true,
  152. },
  153. selection: {
  154. mode: "single",
  155. },
  156. allowColumnReordering: true,
  157. rowAlternationEnabled: true,
  158. showBorders: true,
  159. paging: {
  160. enabled: false,
  161. pageSize: 0,
  162. },
  163. height: "100%",
  164. columns: [
  165. {
  166. dataField: "来源",
  167. caption: "来源",
  168. width: 100,
  169. },
  170. {
  171. dataField: "选择器",
  172. caption: "选择器",
  173. },
  174. {
  175. dataField: "属性值",
  176. caption: "属性值",
  177. },
  178. ],
  179. })
  180. .dxDataGrid("instance");
  181. window.eventTableInstance = $("#eventTable")
  182. .dxDataGrid({
  183. dataSource: [],
  184. keyExpr: "id",
  185. remoteOperations: false,
  186. searchPanel: {
  187. visible: true,
  188. highlightCaseSensitive: true,
  189. },
  190. selection: {
  191. mode: "single",
  192. },
  193. allowColumnReordering: true,
  194. rowAlternationEnabled: true,
  195. showBorders: true,
  196. paging: {
  197. enabled: false,
  198. pageSize: 0,
  199. },
  200. height: "100%",
  201. columns: [
  202. {
  203. dataField: "事件名称",
  204. caption: "事件名称",
  205. },
  206. {
  207. dataField: "绑定对象",
  208. caption: "绑定对象",
  209. },
  210. {
  211. dataField: "事件文件",
  212. caption: "事件文件",
  213. },
  214. ],
  215. })
  216. .dxDataGrid("instance");
  217. }
  218. chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
  219. if (request.msgToPopup === "发送页面") {
  220. //初始化JS代码编辑器
  221. window.jsCode = new CodeEditor();
  222. jsCode.InitEditor($("#jscode")[0], false, false, [], false);
  223. jsCode.dataType = 3;
  224. InitTable();
  225. let ret = request.data;
  226. console.log(ret);
  227. let { jslist: _jslist, targe, csslist, tabId: _tabId, path } = ret;
  228. jslist = _jslist;
  229. tabId = _tabId;
  230. parseCodeToAST(
  231. jslist.map((item) => {
  232. return {
  233. code: item.data,
  234. name: item.fileName,
  235. };
  236. })
  237. );
  238. let data = window.findSelector();
  239. let id = $(targe).attr("id");
  240. let classList = $(targe).attr("class").split(" ");
  241. data = data.filter((m) => {
  242. let v = m.过滤器;
  243. if (v.includes(id)) return true;
  244. if (classList.length > 0) {
  245. for (const classitem of classList) {
  246. if (v.includes(classitem)) return true;
  247. }
  248. }
  249. });
  250. await attach();
  251. await getPathNodeInfo(path);
  252. let events = await findEvent();
  253. TabInstance.option({
  254. dataSource: data,
  255. });
  256. CSSTabInstance.option({
  257. dataSource: Object.entries(csslist).map((a, index) => ({
  258. id: index,
  259. key: a[0],
  260. value: a[1],
  261. })),
  262. });
  263. eventTableInstance.option({
  264. dataSource: translateEventData(events),
  265. });
  266. }
  267. });
  268. function findPropRef(key, json) {
  269. let matchedCSSRules = json.matchedCSSRules;
  270. let retArr = [];
  271. for (const matchedCSSRule of matchedCSSRules) {
  272. let cssProperties = matchedCSSRule.rule.style.cssProperties;
  273. let cssProp = cssProperties.find((m) => m.name == key);
  274. if (!cssProp) continue;
  275. let ret = {
  276. 来源: "CSS",
  277. 选择器: matchedCSSRule.rule.selectorList.text,
  278. 选中选择器: matchedCSSRule.matchingSelectors[0],
  279. 属性值: cssProp.value,
  280. };
  281. retArr.push(ret);
  282. }
  283. return retArr;
  284. }
  285. async function getPathNodeInfo(path) {
  286. const doc = await getDocument();
  287. // const htmlInfo = doc.children.find((m) => m.localName === "html");
  288. let info = doc;
  289. for (const index of path) {
  290. info = getpath(info, index);
  291. }
  292. nodeObj = info;
  293. let nodeId = info.nodeId;
  294. let cssInfo = await getMatchedStylesForNode(nodeId);
  295. jsonInfo = cssInfo;
  296. function getpath(info, index) {
  297. let children = info.children;
  298. return children[index];
  299. }
  300. }
  301. async function getMatchedStylesForNode(nodeId) {
  302. let ret = await chrome.debugger.sendCommand(
  303. { tabId },
  304. "CSS.getMatchedStylesForNode",
  305. {
  306. nodeId,
  307. }
  308. );
  309. return ret;
  310. }
  311. async function getDocument() {
  312. const doc = await chrome.debugger.sendCommand({ tabId }, "DOM.getDocument", {
  313. pierce: true,
  314. depth: -1,
  315. });
  316. return doc.root;
  317. }
  318. async function attach() {
  319. // const targets = await chrome.debugger.getTargets();
  320. // let target = targets.find((m) => m.tabId == tabId);
  321. // if (target?.attached === true) {
  322. // } else {
  323. // await chrome.debugger.attach({ tabId }, "1.3");
  324. // }
  325. await chrome.debugger.attach({ tabId }, "1.3").catch(() => {});
  326. await chrome.debugger.sendCommand({ tabId }, "DOM.enable");
  327. await chrome.debugger.sendCommand({ tabId }, "CSS.enable");
  328. await chrome.debugger.sendCommand({ tabId }, "Debugger.enable");
  329. }
  330. async function findEvent() {
  331. let winObj = await chrome.debugger.sendCommand(
  332. { tabId },
  333. "Runtime.evaluate",
  334. {
  335. expression: "self",
  336. objectGroup: "",
  337. includeCommandLineAPI: false,
  338. silent: true,
  339. returnByValue: false,
  340. generatePreview: false,
  341. userGesture: false,
  342. awaitPromise: false,
  343. }
  344. );
  345. let winEvents = await chrome.debugger.sendCommand(
  346. { tabId },
  347. "DOMDebugger.getEventListeners",
  348. {
  349. objectId: winObj.result.objectId,
  350. }
  351. );
  352. let documentObj = await chrome.debugger.sendCommand(
  353. { tabId },
  354. "Runtime.evaluate",
  355. {
  356. expression: "document",
  357. objectGroup: "",
  358. includeCommandLineAPI: false,
  359. silent: true,
  360. returnByValue: false,
  361. generatePreview: false,
  362. userGesture: false,
  363. awaitPromise: false,
  364. }
  365. );
  366. let documentEvents = await chrome.debugger.sendCommand(
  367. { tabId },
  368. "DOMDebugger.getEventListeners",
  369. {
  370. objectId: documentObj.result.objectId,
  371. }
  372. );
  373. let selfObj = await chrome.debugger.sendCommand(
  374. { tabId },
  375. "DOM.resolveNode",
  376. {
  377. nodeId: nodeObj.nodeId,
  378. }
  379. );
  380. let selfEvents = await chrome.debugger.sendCommand(
  381. { tabId },
  382. "DOMDebugger.getEventListeners",
  383. {
  384. objectId: selfObj.object.objectId,
  385. }
  386. );
  387. for (const listener of winEvents.listeners) {
  388. await listenerGetFile(listener);
  389. }
  390. for (const listener of documentEvents.listeners) {
  391. await listenerGetFile(listener);
  392. }
  393. for (const listener of selfEvents.listeners) {
  394. await listenerGetFile(listener);
  395. }
  396. return {
  397. winEvents: winEvents.listeners,
  398. documentEvents: documentEvents.listeners,
  399. selfEvents: selfEvents.listeners,
  400. };
  401. }
  402. async function listenerGetFile(listener) {
  403. let ret = await chrome.debugger.sendCommand(
  404. { tabId },
  405. "Debugger.getScriptSource",
  406. {
  407. scriptId: listener.scriptId,
  408. }
  409. );
  410. let js = jslist.find((m) => m.data == ret.scriptSource);
  411. if (js) {
  412. debugger;
  413. js.scriptId = listener.scriptId;
  414. listener.fileName = js.fileName;
  415. listener.fileUrl = js.url;
  416. listener.fileData = js.data;
  417. }
  418. }
  419. function translateEventData(eventObj) {
  420. debugger;
  421. let { winEvents, documentEvents, selfEvents } = eventObj;
  422. let result = [];
  423. result.push(
  424. ...winEvents.map((even) => ({
  425. 事件名称: even.type,
  426. 绑定对象: "window",
  427. 事件文件: even.fileName,
  428. }))
  429. );
  430. result.push(
  431. ...documentEvents.map((even) => ({
  432. 事件名称: even.type,
  433. 绑定对象: "document",
  434. 事件文件: even.fileName,
  435. }))
  436. );
  437. result.push(
  438. ...selfEvents.map((even) => ({
  439. 事件名称: even.type,
  440. 绑定对象: "selft",
  441. 事件文件: even.fileName,
  442. }))
  443. );
  444. return result.map((a, index) => ({ ...a, id: index }));
  445. }
  446. window.onload = function () {
  447. InitTabOperation();
  448. };
  449. /**
  450. * 设置操作页卡功能
  451. */
  452. function InitTabOperation() {
  453. document.querySelector(".tabs").addEventListener("click", function (e) {
  454. let target = e.target;
  455. if (target.classList.contains("tab")) {
  456. showContent(target);
  457. }
  458. });
  459. }
  460. function showContent(tab) {
  461. let id = tab.dataset.id; // 获取点击的页卡ID
  462. // 获取选中的页卡元素
  463. let activeTab = document.querySelector(".tabs .active");
  464. if (activeTab !== null) {
  465. if (id === activeTab.dataset.id) return;
  466. activeTab.classList.remove("active");
  467. }
  468. // 获取选中的容器的元素
  469. let activeContent = document.querySelector(".tab-container .active");
  470. if (activeContent !== null) {
  471. if (activeContent.id === id) return;
  472. activeContent.classList.remove("active");
  473. }
  474. // 给新选中的页卡加入选中效果
  475. tab.classList.add("active");
  476. let curActiveContent = document.querySelector(`.tab-container #${id}`);
  477. if (curActiveContent !== null) {
  478. curActiveContent.classList.add("active");
  479. }
  480. }