index.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. /**
  2. * FE-Helper后台运行程序
  3. * @author zhaoxianlie
  4. */
  5. var BgPageInstance = (function () {
  6. let MSG_TYPE = Tarp.require('../static/js/msg_type');
  7. let Settings = Tarp.require('../options/settings');
  8. let Network = Tarp.require('../background/network');
  9. let PageCapture = Tarp.require('../page-capture/capture-api')(MSG_TYPE);
  10. let feHelper = {
  11. codeStandardMgr: {},
  12. ajaxDebuggerMgr: {},
  13. csDetectIntervals: [],
  14. manifest: chrome.runtime.getManifest(),
  15. notifyTimeoutId: -1
  16. };
  17. let devToolsDetected = false;
  18. //侦测就绪情况
  19. let _detectReadyState = function (getType, callback) {
  20. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  21. let tabId = tabs[0].id;
  22. feHelper.codeStandardMgr[tabId][getType] = true;
  23. if (feHelper.codeStandardMgr[tabId].css && feHelper.codeStandardMgr[tabId].js) {
  24. feHelper.codeStandardMgr[tabId].allDone = true;
  25. }
  26. if (feHelper.codeStandardMgr[tabId].allDone && typeof callback === 'function') {
  27. callback();
  28. }
  29. });
  30. };
  31. /**
  32. * 执行前端FCPHelper检测
  33. */
  34. let _doFcpDetect = function (tab) {
  35. feHelper.codeStandardMgr[tab.id] = feHelper.codeStandardMgr[tab.id] || {};
  36. //所有元素都准备就绪
  37. if (feHelper.codeStandardMgr[tab.id].allDone) {
  38. clearInterval(feHelper.csDetectIntervals[tab.id]);
  39. chrome.tabs.sendMessage(tab.id, {
  40. type: MSG_TYPE.CODE_STANDARDS,
  41. event: MSG_TYPE.FCP_HELPER_DETECT
  42. });
  43. } else if (feHelper.csDetectIntervals[tab.id] === undefined) {
  44. chrome.tabs.sendMessage(tab.id, {
  45. type: MSG_TYPE.CODE_STANDARDS,
  46. event: MSG_TYPE.FCP_HELPER_INIT
  47. });
  48. //显示桌面提醒
  49. notifyText({
  50. message: "正在准备数据,请稍等..."
  51. });
  52. feHelper.csDetectIntervals[tab.id] = setInterval(function () {
  53. _doFcpDetect(tab);
  54. }, 200);
  55. }
  56. };
  57. /**
  58. * 文本格式,可以设置一个图标和标题
  59. * @param {Object} options
  60. * @config {string} type notification的类型,可选值:html、text
  61. * @config {string} icon 图标
  62. * @config {string} title 标题
  63. * @config {string} message 内容
  64. */
  65. let notifyText = function (options) {
  66. let notifyId = 'fehleper-notify-id';
  67. clearTimeout(feHelper.notifyTimeoutId);
  68. if (options.closeImmediately) {
  69. return chrome.notifications.clear(notifyId);
  70. }
  71. if (!options.icon) {
  72. options.icon = "static/img/fe-48.png";
  73. }
  74. if (!options.title) {
  75. options.title = "温馨提示";
  76. }
  77. chrome.notifications.create(notifyId, {
  78. type: 'basic',
  79. title: options.title,
  80. iconUrl: chrome.runtime.getURL(options.icon),
  81. message: options.message
  82. });
  83. feHelper.notifyTimeoutId = setTimeout(() => {
  84. chrome.notifications.clear(notifyId);
  85. }, parseInt(options.autoClose || 3000, 10));
  86. };
  87. /**
  88. * 查看页面wpo信息
  89. */
  90. let _showPageWpoInfo = function (wpoInfo) {
  91. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  92. if (!wpoInfo) {
  93. notifyText({
  94. message: "对不起,检测失败"
  95. });
  96. } else {
  97. chrome.tabs.create({
  98. url: "wpo/index.html?" + btoa(encodeURIComponent(JSON.stringify(wpoInfo))),
  99. active: true
  100. });
  101. }
  102. });
  103. };
  104. /**
  105. * 获取页面wpo信息
  106. * @return {[type]}
  107. */
  108. let _getPageWpoInfo = function () {
  109. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  110. let tab = tabs[0];
  111. //显示桌面提醒
  112. chrome.tabs.sendMessage(tab.id, {
  113. type: MSG_TYPE.GET_PAGE_WPO_INFO
  114. });
  115. });
  116. };
  117. /**
  118. * 创建或更新成功执行的动作
  119. * @param evt
  120. * @param content
  121. * @private
  122. */
  123. let _tabUpdatedCallback = function (evt, content) {
  124. return function (newTab) {
  125. if (content) {
  126. setTimeout(function () {
  127. chrome.tabs.sendMessage(newTab.id, {
  128. type: MSG_TYPE.TAB_CREATED_OR_UPDATED,
  129. content: content,
  130. event: evt
  131. });
  132. }, 300)
  133. }
  134. };
  135. };
  136. /**
  137. * 打开对应文件,运行该Helper
  138. * @param tab
  139. * @param file
  140. * @param txt
  141. * @private
  142. */
  143. let _openFileAndRun = function (tab, file, txt) {
  144. chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, function (tabs) {
  145. Settings.getOptsFromBgPage((opts) => {
  146. let isOpened = false;
  147. let tabId;
  148. // 允许在新窗口打开
  149. if (opts['FORBID_OPEN_IN_NEW_TAB']) {
  150. let reg = new RegExp("^chrome.*/" + file + "/index.html$", "i");
  151. for (let i = 0, len = tabs.length; i < len; i++) {
  152. if (reg.test(tabs[i].url)) {
  153. isOpened = true;
  154. tabId = tabs[i].id;
  155. break;
  156. }
  157. }
  158. }
  159. if (!isOpened) {
  160. chrome.tabs.create({
  161. url: '' + file + '/index.html',
  162. active: true
  163. }, _tabUpdatedCallback(file, txt));
  164. } else {
  165. chrome.tabs.update(tabId, {highlighted: true}, _tabUpdatedCallback(file, txt));
  166. }
  167. });
  168. });
  169. };
  170. /**
  171. * ajax debugger 开关切换
  172. * @private
  173. */
  174. let _debuggerSwitchOn = function (callback) {
  175. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  176. let tab = tabs[0];
  177. feHelper.ajaxDebuggerMgr[tab.id] = !feHelper.ajaxDebuggerMgr[tab.id];
  178. chrome.tabs.executeScript(tab.id, {
  179. code: 'console.info("FeHelper提醒:Ajax Debugger开关已' + (feHelper.ajaxDebuggerMgr[tab.id] ? '开启' : '关闭') + '!");',
  180. allFrames: false
  181. });
  182. callback && callback();
  183. });
  184. };
  185. /**
  186. * 告诉DevTools页面,当前的debug开关是否打开
  187. * @param callback
  188. * @param withAlert
  189. * @private
  190. */
  191. let _tellDevToolsDbgSwitchOn = function (callback, withAlert) {
  192. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  193. let tab = tabs[0];
  194. if (tab) {
  195. callback && callback(feHelper.ajaxDebuggerMgr[tab.id]);
  196. if (withAlert) {
  197. let msg = '';
  198. if (feHelper.ajaxDebuggerMgr[tab.id]) {
  199. if (devToolsDetected) {
  200. msg = 'DevTools已打开,确保已切换到【Console】界面,并关注信息输出,愉快的进行Ajax Debugger!'
  201. } else {
  202. msg = '请打开DevTools,并切换到【Console】界面,关注信息输出,愉快的进行Ajax Debugger!';
  203. }
  204. } else {
  205. msg = '已停止当前页面的Ajax Debugger功能!';
  206. }
  207. alert(msg);
  208. }
  209. }
  210. });
  211. };
  212. /**
  213. * 屏幕栅格标尺
  214. */
  215. let _doGridDetect = function (tab) {
  216. chrome.tabs.sendMessage(tab.id, {
  217. type: MSG_TYPE.GRID_RULER
  218. });
  219. };
  220. /**
  221. * 根据给定参数,运行对应的Helper
  222. */
  223. let _runHelper = function (config, callback) {
  224. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  225. let tab = tabs[0];
  226. // 如果是采用独立文件方式访问,直接打开该页面即可
  227. if (config.useFile === 1) {
  228. let content = config.msgType === MSG_TYPE.QR_CODE ? tab.url : '';
  229. _openFileAndRun(tab, config.msgType, content);
  230. } else {
  231. switch (config.msgType) {
  232. //编码规范检测
  233. case MSG_TYPE.FCP_HELPER_DETECT:
  234. _doFcpDetect(tab);
  235. break;
  236. //将当前网页转为图片
  237. case MSG_TYPE.PAGE_CAPTURE:
  238. PageCapture.full(tab);
  239. break;
  240. //查看网页加载时间
  241. case MSG_TYPE.SHOW_PAGE_LOAD_TIME:
  242. _getPageWpoInfo();
  243. break;
  244. //Ajax调试
  245. case MSG_TYPE.AJAX_DEBUGGER:
  246. _debuggerSwitchOn(callback);
  247. break;
  248. // 屏幕栅格标尺
  249. case MSG_TYPE.GRID_RULER:
  250. _doGridDetect(tab);
  251. break;
  252. default :
  253. break;
  254. }
  255. }
  256. });
  257. };
  258. /**
  259. * 检测Google chrome服务能不能访问,在2s内检测心跳
  260. * @param success
  261. * @param failure
  262. */
  263. let detectGoogleDotCom = function (success, failure) {
  264. Promise.race([
  265. fetch('https://clients2.google.com/service/update2/crx'),
  266. new Promise(function (resolve, reject) {
  267. setTimeout(() => reject(new Error('request timeout')), 2000)
  268. })])
  269. .then((data) => {
  270. success && success();
  271. }).catch(() => {
  272. failure && failure();
  273. });
  274. };
  275. /**
  276. * 从google官方渠道下载chrome扩展
  277. * @param crxId 需要下载的extension id
  278. * @param crxName 扩展名称
  279. * @param callback 下载动作结束后的回调
  280. */
  281. let downloadCrxFileByCrxId = function (crxId, crxName, callback) {
  282. detectGoogleDotCom(() => {
  283. // google可以正常访问,则正常下载
  284. let url = "https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D"
  285. + crxId + "%26uc&prodversion=" + navigator.userAgent.split("Chrome/")[1].split(" ")[0];
  286. if (!chrome.downloads) {
  287. let a = document.createElement('a');
  288. a.href = url;
  289. a.download = crxName || (crxId + '.crx');
  290. (document.body || document.documentElement).appendChild(a);
  291. a.click();
  292. a.remove();
  293. } else {
  294. chrome.downloads.download({
  295. url: url,
  296. filename: crxName || crxId,
  297. conflictAction: 'overwrite',
  298. saveAs: true
  299. }, function (downloadId) {
  300. if (chrome.runtime.lastError) {
  301. alert('抱歉,下载失败!错误信息:' + chrome.runtime.lastError.message);
  302. }
  303. });
  304. }
  305. }, () => {
  306. // google不能正常访问
  307. callback ? callback() : alert('抱歉,下载失败!');
  308. });
  309. };
  310. /**
  311. * 从chrome webstore下载crx文件
  312. * 在chrome extension详情页使用
  313. */
  314. let downloadCrxFileFromWebStoreDetailPage = function (callback) {
  315. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  316. let tab = tabs[0];
  317. let crxId = tab.url.split("/")[6].split('?')[0];
  318. let crxName = tab.title.split(" - Chrome")[0] + ".crx";
  319. crxName = crxName.replace(/[&\/\\:"*<>|?]/g, '');
  320. downloadCrxFileByCrxId(crxId, crxName, callback);
  321. });
  322. };
  323. /**
  324. * 通过右键菜单下载或者分享crx
  325. * @param tab
  326. * @private
  327. */
  328. let _downloadCrx = function (tab) {
  329. let isWebStoreDetailPage = tab.url.indexOf('https://chrome.google.com/webstore/detail/') === 0;
  330. if (isWebStoreDetailPage) {
  331. // 如果是某个chrome extension的详情页面了,直接下载当前crx文件
  332. downloadCrxFileFromWebStoreDetailPage(() => {
  333. alert('下载失败,可能是当前网络无法访问Google站点!');
  334. });
  335. } else {
  336. // 否则,下载FeHelper并分享出去:ID:pkgccpejnmalmdinmhkkfafefagiiiad
  337. // feHelper.manifest.name
  338. if (confirm('下载最新版【FeHelper】并分享给其他小伙伴儿,走你~~~')) {
  339. let crxId = MSG_TYPE.STABLE_EXTENSION_ID;
  340. let crxName = feHelper.manifest.name + '- latestVersion.crx';
  341. downloadCrxFileByCrxId(crxId, crxName, () => {
  342. chrome.tabs.create({
  343. url: MSG_TYPE.DOWNLOAD_FROM_GITHUB
  344. });
  345. });
  346. }
  347. }
  348. };
  349. /**
  350. * 右键菜单创建工具
  351. * @param menuList
  352. * @private
  353. */
  354. let _contextMenuCreator = function (menuList) {
  355. let menus = Settings.getMenuOpts();
  356. menuList.forEach(m => {
  357. if (m === 'MENU_PAGE_ENCODING') {
  358. // 网页编码设置的menu
  359. PageEncoding.createMenu(feHelper.contextMenuId, menus.MENU_PAGE_ENCODING);
  360. } else {
  361. let onClick = {
  362. MENU_QRCODE_CREATE: function (info, tab) {
  363. chrome.tabs.executeScript(tab.id, {
  364. code: '(' + (function (pInfo) {
  365. let linkUrl = pInfo.linkUrl;
  366. let pageUrl = pInfo.pageUrl;
  367. let imgUrl = pInfo.srcUrl;
  368. let selection = pInfo.selectionText;
  369. return linkUrl || imgUrl || selection || pageUrl;
  370. }).toString() + ')(' + JSON.stringify(info) + ')',
  371. allFrames: false
  372. }, function (txt) {
  373. _openFileAndRun(tab, MSG_TYPE.QR_CODE, (typeof txt === 'object') ? txt[0] : txt);
  374. });
  375. },
  376. MENU_QRCODE_DECODE: function (info, tab) {
  377. _qrDecode(info, tab);
  378. },
  379. MENU_PAGE_CAPTURE: function (info, tab) {
  380. PageCapture.full(tab);
  381. },
  382. MENU_COLOR_PICKER: function (info, tab) {
  383. _showColorPicker();
  384. },
  385. MENU_STR_ENDECODE: function (info, tab) {
  386. chrome.tabs.executeScript(tab.id, {
  387. code: '(' + (function (pInfo) {
  388. return pInfo.selectionText;
  389. }).toString() + ')(' + JSON.stringify(info) + ')',
  390. allFrames: false
  391. }, function (txt) {
  392. _openFileAndRun(tab, MSG_TYPE.EN_DECODE, (typeof txt === 'object') ? txt[0] : txt);
  393. });
  394. },
  395. MENU_JSON_FORMAT: function (info, tab) {
  396. chrome.tabs.executeScript(tab.id, {
  397. code: '(' + (function (pInfo) {
  398. return pInfo.selectionText;
  399. }).toString() + ')(' + JSON.stringify(info) + ')',
  400. allFrames: false
  401. }, function (txt) {
  402. _openFileAndRun(tab, MSG_TYPE.JSON_FORMAT, (typeof txt === 'object') ? txt[0] : txt);
  403. });
  404. },
  405. MENU_CODE_FORMAT: function (info, tab) {
  406. chrome.tabs.executeScript(tab.id, {
  407. code: '(' + (function (pInfo) {
  408. return pInfo.selectionText;
  409. }).toString() + ')(' + JSON.stringify(info) + ')',
  410. allFrames: false
  411. }, function (txt) {
  412. _openFileAndRun(tab, MSG_TYPE.CODE_BEAUTIFY, (typeof txt === 'object') ? txt[0] : txt);
  413. });
  414. },
  415. MENU_AJAX_DEBUGGER: function (info, tab) {
  416. _debuggerSwitchOn(() => {
  417. _tellDevToolsDbgSwitchOn(null, true);
  418. });
  419. },
  420. MENU_CODE_STANDARD: function (info, tab) {
  421. _doFcpDetect(tab);
  422. },
  423. MENU_PAGE_OPTIMI: function (info, tab) {
  424. _getPageWpoInfo();
  425. },
  426. MENU_IMAGE_BASE64: function (info, tab) {
  427. _openFileAndRun(tab, MSG_TYPE.IMAGE_BASE64, info.srcUrl);
  428. },
  429. MENU_JSON_COMPARE: function (info, tab) {
  430. _openFileAndRun(tab, MSG_TYPE.JSON_COMPARE);
  431. },
  432. MENU_CODE_COMPRESS: function (info, tab) {
  433. _openFileAndRun(tab, MSG_TYPE.CODE_COMPRESS);
  434. },
  435. MENU_TIME_STAMP: function (info, tab) {
  436. _openFileAndRun(tab, MSG_TYPE.TIME_STAMP);
  437. },
  438. MENU_RANDOM_PASS: function (info, tab) {
  439. _openFileAndRun(tab, MSG_TYPE.RANDOM_PASSWORD);
  440. },
  441. MENU_JS_REGEXP: function (info, tab) {
  442. _openFileAndRun(tab, MSG_TYPE.REGEXP_TOOL);
  443. },
  444. MENU_MARKDOWN_TL: function (info, tab) {
  445. _openFileAndRun(tab, MSG_TYPE.HTML_TO_MARKDOWN);
  446. },
  447. MENU_STICKY_NOTE: function (info, tab) {
  448. _openFileAndRun(tab, MSG_TYPE.STICKY_NOTES);
  449. },
  450. MENU_REMOVE_BG: function (info, tab) {
  451. _openFileAndRun(tab, MSG_TYPE.REMOVE_BG);
  452. },
  453. MENU_MULTI_TOOLKIT: function (info, tab) {
  454. _openFileAndRun(tab, MSG_TYPE.MULTI_TOOLKIT);
  455. },
  456. MENU_PAGE_MODIFIER: function (info, tab) {
  457. _openFileAndRun(tab, MSG_TYPE.PAGE_MODIFIER);
  458. },
  459. MENU_GRID_RULER: function (info, tab) {
  460. _doGridDetect(tab);
  461. },
  462. MENU_DOWNLOAD_CRX: function (info, tab) {
  463. _downloadCrx(tab);
  464. }
  465. };
  466. chrome.contextMenus.create({
  467. title: menus[m].icon + ' ' + menus[m].text,
  468. contexts: menus[m].contexts || ['all'],
  469. parentId: feHelper.contextMenuId,
  470. onclick: onClick[m]
  471. });
  472. }
  473. });
  474. };
  475. /**
  476. * 创建扩展专属的右键菜单
  477. */
  478. let _createContextMenu = function () {
  479. _removeContextMenu();
  480. feHelper.contextMenuId = chrome.contextMenus.create({
  481. title: "FeHelper工具",
  482. contexts: ['page', 'selection', 'editable', 'link', 'image'],
  483. documentUrlPatterns: ['http://*/*', 'https://*/*', 'file://*/*']
  484. });
  485. if (!Settings.didMenuSettingSaved()) {
  486. _contextMenuCreator(Settings.getDefaultContextMenus());
  487. } else {
  488. Settings.getOptsFromBgPage((opts) => {
  489. _contextMenuCreator(Object.keys(opts).filter(m => /^MENU_/.test(m)));
  490. });
  491. }
  492. };
  493. /**
  494. * 移除扩展专属的右键菜单
  495. */
  496. let _removeContextMenu = function () {
  497. if (!feHelper.contextMenuId) return;
  498. chrome.contextMenus.remove(feHelper.contextMenuId);
  499. feHelper.contextMenuId = null;
  500. };
  501. /**
  502. * 创建或移除扩展专属的右键菜单
  503. */
  504. let _createOrRemoveContextMenu = function () {
  505. Settings.getOptsFromBgPage((opts) => {
  506. if (opts['opt_item_contextMenus']) {
  507. _createContextMenu();
  508. } else {
  509. _removeContextMenu();
  510. }
  511. });
  512. };
  513. /**
  514. * 二维码转码
  515. * @param info
  516. * @param tab
  517. * @private
  518. */
  519. let _qrDecode = function (info, tab) {
  520. let qrcode = Tarp.require('../static/vendor/zxing/zxing.min.js');
  521. qrcode.callback = function (text) {
  522. if ((text || '').indexOf('error decoding QR Code') !== -1) {
  523. let image = new Image();
  524. image.src = info.srcUrl;
  525. image.onload = function () {
  526. let width = this.naturalWidth;
  527. let height = this.naturalHeight;
  528. // url方式解码失败,再转换成data uri后继续解码
  529. (function createCanvasContext(img, t, l, w, h) {
  530. let canvas = document.createElement('canvas');
  531. canvas.setAttribute('id', 'qr-canvas');
  532. canvas.height = h + 100;
  533. canvas.width = w + 100;
  534. let context = canvas.getContext('2d');
  535. context.fillStyle = 'rgb(255,255,255)';
  536. context.fillRect(0, 0, canvas.width, canvas.height);
  537. context.drawImage(img, l, t, w, h, 50, 50, w, h);
  538. qrcode.callback = function (txt) {
  539. chrome.tabs.sendMessage(tab.id, {
  540. type: MSG_TYPE.QR_DECODE,
  541. result: txt
  542. });
  543. };
  544. qrcode.decode(canvas.toDataURL());
  545. })(image, 0, 0, width, height);
  546. }
  547. } else {
  548. chrome.tabs.sendMessage(tab.id, {
  549. type: MSG_TYPE.QR_DECODE,
  550. result: text
  551. });
  552. }
  553. };
  554. qrcode.decode(info.srcUrl);
  555. };
  556. /**
  557. * 显示color picker
  558. * @private
  559. */
  560. let _showColorPicker = function () {
  561. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  562. let tab = tabs[0];
  563. let tabid = tab.id;
  564. chrome.tabs.sendMessage(tabid, {
  565. type: MSG_TYPE.SHOW_COLOR_PICKER,
  566. enableColorPicker: true
  567. }, function (response) {
  568. chrome.tabs.sendMessage(tabid, {
  569. type: MSG_TYPE.SHOW_COLOR_PICKER,
  570. doPick: true
  571. }, function (r) {
  572. });
  573. });
  574. });
  575. };
  576. /**
  577. * 将网页截成一张图,实现取色
  578. * @param callback
  579. * @private
  580. */
  581. let _drawColorPicker = function (callback) {
  582. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  583. let tab = tabs[0];
  584. let tabid = tab.id;
  585. chrome.tabs.captureVisibleTab(null, {format: 'png'}, function (dataUrl) {
  586. chrome.tabs.sendMessage(tabid, {
  587. type: MSG_TYPE.SHOW_COLOR_PICKER,
  588. setPickerImage: true,
  589. pickerImage: dataUrl
  590. }, function (response) {
  591. callback && callback();
  592. });
  593. });
  594. });
  595. };
  596. /**
  597. * 在当前页面的控制台输出console
  598. * @param request
  599. * @private
  600. */
  601. let _ajaxDebugger = function (request) {
  602. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  603. let tab = tabs[0];
  604. chrome.tabs.executeScript(tab.id, {
  605. code: "(" + (function (jsonStr) {
  606. let args = JSON.parse(unescape(jsonStr));
  607. console[args[0]].apply(console, Array.prototype.slice.call(args, 1));
  608. }).toString() + ")('" + request.content + "');"
  609. });
  610. });
  611. };
  612. //判断是否可以针对json页面进行自动格式化
  613. let _jsonAutoFormatRequest = function () {
  614. Settings.getOptsFromBgPage(opts => {
  615. opts.JSON_PAGE_FORMAT && chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  616. chrome.tabs.sendMessage(tabs[0].id, {
  617. type: MSG_TYPE.JSON_PAGE_FORMAT,
  618. options: {
  619. MAX_JSON_KEYS_NUMBER: opts.MAX_JSON_KEYS_NUMBER,
  620. AUTO_TEXT_DECODE: opts.AUTO_TEXT_DECODE === 'true'
  621. }
  622. });
  623. });
  624. });
  625. };
  626. //判断是否可以针对js、css自动检测格式化
  627. let _jsCssAutoDetectRequest = function () {
  628. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  629. let tab = tabs[0];
  630. chrome.tabs.executeScript(tab.id, {
  631. code: '(' + (() => {
  632. let ext = location.pathname.substring(location.pathname.lastIndexOf(".") + 1).toLowerCase();
  633. let fileType = ({'js': 'javascript', 'css': 'css'})[ext];
  634. let contentType = document.contentType.toLowerCase();
  635. if (!fileType) {
  636. if (/\/javascript$/.test(contentType)) {
  637. fileType = 'javascript';
  638. } else if (/\/css$/.test(contentType)) {
  639. fileType = 'css';
  640. }
  641. } else if (contentType === 'text/html') {
  642. fileType = undefined;
  643. }
  644. return fileType;
  645. }).toString() + ')()'
  646. }, function (fileType) {
  647. if (fileType && fileType.length && (fileType[0] === 'javascript' || fileType[0] === 'css')) {
  648. Settings.getOptsFromBgPage(opts => {
  649. opts.JS_CSS_PAGE_BEAUTIFY && chrome.tabs.sendMessage(tab.id, {
  650. type: MSG_TYPE.JS_CSS_PAGE_BEAUTIFY,
  651. content: fileType[0]
  652. });
  653. });
  654. }
  655. });
  656. });
  657. };
  658. /**
  659. * 存储 网页涂鸦精灵 的配置
  660. * @param params
  661. * @param callback
  662. * @private
  663. */
  664. let _savePageModifierConfigs = function (params, callback) {
  665. !RegExp.prototype.toJSON && Object.defineProperty(RegExp.prototype, "toJSON", {
  666. value: RegExp.prototype.toString
  667. });
  668. localStorage.setItem(MSG_TYPE.PAGE_MODIFIER_KEY, JSON.stringify(params));
  669. callback && callback();
  670. };
  671. /**
  672. * 获取 网页涂鸦精灵 的配置,如果指定了url参数,则表示只获取对应的一条配置,否则获取全部
  673. * @param params
  674. * @param callback
  675. * @returns {*}
  676. * @private
  677. */
  678. let _getPageModifierConfigs = function (params, callback) {
  679. let cacheModifiers = JSON.parse(localStorage.getItem(MSG_TYPE.PAGE_MODIFIER_KEY) || '[]');
  680. if (params && params.url) {
  681. let result = null;
  682. cacheModifiers.some(cm => {
  683. let m = cm.mPattern.match(/\/(.*)\/(.*)?/);
  684. if ((new RegExp(m[1], m[2] || "")).test(params.url)) {
  685. result = cm;
  686. return true;
  687. }
  688. return false;
  689. });
  690. callback && callback(result);
  691. } else {
  692. callback && callback(cacheModifiers);
  693. }
  694. };
  695. /**
  696. * 接收来自content_scripts发来的消息
  697. */
  698. let _addExtensionListener = function () {
  699. chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  700. //提取配置项
  701. if (request.type === MSG_TYPE.GET_OPTIONS) {
  702. Settings.getOptsFromBgPage(callback);
  703. }
  704. //保存配置项
  705. else if (request.type === MSG_TYPE.SET_OPTIONS) {
  706. Settings.setOptsFromBgPage(request.items);
  707. //管理右键菜单
  708. _createOrRemoveContextMenu();
  709. notifyText({
  710. message: '配置已生效,请继续使用!',
  711. autoClose: 2000
  712. });
  713. }
  714. // 判断菜单是否保存过
  715. else if (request.type === MSG_TYPE.MENU_SAVED) {
  716. Settings.didMenuSettingSaved(callback);
  717. }
  718. //判断是否可以针对json页面进行自动格式化
  719. else if (request.type === MSG_TYPE.JSON_PAGE_FORMAT_REQUEST) {
  720. _jsonAutoFormatRequest();
  721. }
  722. //判断是否可以针对js、css自动检测格式化
  723. else if (request.type === MSG_TYPE.JS_CSS_PAGE_BEAUTIFY_REQUEST) {
  724. _jsCssAutoDetectRequest();
  725. }
  726. //保存当前网页加载时间
  727. else if (request.type === MSG_TYPE.CALC_PAGE_LOAD_TIME) {
  728. _showPageWpoInfo(request.wpo);
  729. }
  730. // color picker
  731. else if (request.type === MSG_TYPE.COLOR_PICKER) {
  732. _drawColorPicker(callback);
  733. }
  734. // console switch
  735. else if (request.type === MSG_TYPE.AJAX_DEBUGGER_SWITCH) {
  736. _tellDevToolsDbgSwitchOn(callback);
  737. }
  738. // console show
  739. else if (request.type === MSG_TYPE.AJAX_DEBUGGER_CONSOLE) {
  740. _ajaxDebugger(request);
  741. }
  742. // 打开设置页
  743. else if (request.type === MSG_TYPE.OPEN_OPTIONS_PAGE) {
  744. chrome.runtime.openOptionsPage();
  745. }
  746. // 开启remove-bg功能
  747. else if (request.type === MSG_TYPE.REMOVE_PERSON_IMG_BG) {
  748. Tarp.require('../remove-bg/proxy').addBackgroundRemoveListener(callback);
  749. }
  750. // 网页涂鸦精灵:获取配置
  751. else if (request.type === MSG_TYPE.GET_PAGE_MODIFIER_CONFIG) {
  752. _getPageModifierConfigs(request.params, callback);
  753. }
  754. // 网页涂鸦精灵:保存配置
  755. else if (request.type === MSG_TYPE.SAVE_PAGE_MODIFIER_CONFIG) {
  756. _savePageModifierConfigs(request.params, callback);
  757. }
  758. // ===========================以下为编码规范检测====start==================================
  759. //处理CSS的请求
  760. else if (request.type === MSG_TYPE.GET_CSS) {
  761. //直接AJAX获取CSS文件内容
  762. Network.readFileContent(request.link, callback);
  763. }
  764. //处理JS的请求
  765. else if (request.type === MSG_TYPE.GET_JS) {
  766. //直接AJAX获取JS文件内容
  767. Network.readFileContent(request.link, callback);
  768. }
  769. //处理HTML的请求
  770. else if (request.type === MSG_TYPE.GET_HTML) {
  771. //直接AJAX获取JS文件内容
  772. Network.readFileContent(request.link, callback);
  773. }
  774. //处理cookie
  775. else if (request.type === MSG_TYPE.GET_COOKIE) {
  776. Network.getCookies(request, callback);
  777. }
  778. //移除cookie
  779. else if (request.type === MSG_TYPE.REMOVE_COOKIE) {
  780. Network.removeCookie(request, callback);
  781. }
  782. //设置cookie
  783. else if (request.type === MSG_TYPE.SET_COOKIE) {
  784. Network.setCookie(request, callback);
  785. }
  786. //CSS准备就绪
  787. else if (request.type === MSG_TYPE.CSS_READY) {
  788. _detectReadyState('css', callback);
  789. }
  790. //JS准备就绪
  791. else if (request.type === MSG_TYPE.JS_READY) {
  792. _detectReadyState('js', callback);
  793. }
  794. //HTML准备就绪
  795. else if (request.type === MSG_TYPE.HTML_READY) {
  796. _detectReadyState('html', callback);
  797. }
  798. // ===========================以上为编码规范检测====end==================================
  799. return true;
  800. });
  801. // 检测DevTools是否打开
  802. let openCount = 0;
  803. chrome.runtime.onConnect.addListener(function (port) {
  804. if (port.name === MSG_TYPE.DEV_TOOLS) {
  805. if (openCount === 0) {
  806. devToolsDetected = true;
  807. }
  808. openCount++;
  809. port.onDisconnect.addListener(function (port) {
  810. openCount--;
  811. if (openCount === 0) {
  812. devToolsDetected = false;
  813. }
  814. });
  815. }
  816. });
  817. // 安装与更新
  818. chrome.runtime.onInstalled.addListener(({reason, previousVersion}) => {
  819. switch (reason) {
  820. case 'install':
  821. chrome.runtime.openOptionsPage();
  822. break;
  823. case 'update':
  824. setTimeout(() => {
  825. chrome.browserAction.setBadgeText({text: '+++1'});
  826. setTimeout(() => {
  827. chrome.browserAction.setBadgeText({text: ''});
  828. }, 1500);
  829. }, 1500);
  830. break;
  831. }
  832. });
  833. // 卸载
  834. chrome.runtime.setUninstallURL(feHelper.manifest.homepage_url);
  835. };
  836. /**
  837. * 检查插件更新
  838. * @private
  839. */
  840. let _checkUpdate = function () {
  841. setTimeout(() => {
  842. chrome.runtime.requestUpdateCheck((status) => {
  843. if (status === "update_available") {
  844. chrome.runtime.reload();
  845. }
  846. });
  847. }, 1000 * 10);
  848. };
  849. /**
  850. * 初始化
  851. */
  852. let _init = function () {
  853. _checkUpdate();
  854. _addExtensionListener();
  855. _createOrRemoveContextMenu();
  856. };
  857. /**
  858. * 打开任意一个URL
  859. * @param url
  860. * @private
  861. */
  862. let _openUrl = function(url){
  863. chrome.tabs.create({url: url});
  864. };
  865. return {
  866. init: _init,
  867. runHelper: _runHelper,
  868. notify: notifyText,
  869. showColorPicker: _showColorPicker,
  870. tellMeAjaxDbgSwitch: _tellDevToolsDbgSwitchOn,
  871. getCapturedData: PageCapture.getCapturedData,
  872. openUrl: _openUrl
  873. };
  874. })();
  875. //初始化
  876. BgPageInstance.init();