page.js 14 KB

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