index.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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.getSelected(null, function (tab) {
  316. let crxId = tab.url.split("/")[6].split('?')[0];
  317. let crxName = tab.title.split(" - Chrome")[0] + ".crx";
  318. crxName = crxName.replace(/[&\/\\:"*<>|?]/g, '');
  319. downloadCrxFileByCrxId(crxId, crxName, callback);
  320. });
  321. };
  322. /**
  323. * 通过右键菜单下载或者分享crx
  324. * @param tab
  325. * @private
  326. */
  327. let _downloadCrx = function (tab) {
  328. let isWebStoreDetailPage = tab.url.indexOf('https://chrome.google.com/webstore/detail/') === 0;
  329. if (isWebStoreDetailPage) {
  330. // 如果是某个chrome extension的详情页面了,直接下载当前crx文件
  331. downloadCrxFileFromWebStoreDetailPage(() => {
  332. alert('下载失败,可能是当前网络无法访问Google站点!');
  333. });
  334. } else {
  335. // 否则,下载FeHelper并分享出去:ID:pkgccpejnmalmdinmhkkfafefagiiiad
  336. // feHelper.manifest.name
  337. if (confirm('下载最新版【FeHelper】并分享给其他小伙伴儿,走你~~~')) {
  338. let crxId = MSG_TYPE.STABLE_EXTENSION_ID;
  339. let crxName = feHelper.manifest.name + '- latestVersion.crx';
  340. downloadCrxFileByCrxId(crxId, crxName, () => {
  341. chrome.tabs.create({
  342. url: MSG_TYPE.DOWNLOAD_FROM_GITHUB
  343. });
  344. });
  345. }
  346. }
  347. };
  348. /**
  349. * 右键菜单创建工具
  350. * @param menuList
  351. * @private
  352. */
  353. let _contextMenuCreator = function (menuList) {
  354. let menus = Settings.getMenuOpts();
  355. menuList.forEach(m => {
  356. if (m === 'MENU_PAGE_ENCODING') {
  357. // 网页编码设置的menu
  358. PageEncoding.createMenu(feHelper.contextMenuId, menus.MENU_PAGE_ENCODING);
  359. } else {
  360. let onClick = {
  361. MENU_QRCODE_CREATE: function (info, tab) {
  362. chrome.tabs.executeScript(tab.id, {
  363. code: '(' + (function (pInfo) {
  364. let linkUrl = pInfo.linkUrl;
  365. let pageUrl = pInfo.pageUrl;
  366. let imgUrl = pInfo.srcUrl;
  367. let selection = pInfo.selectionText;
  368. return linkUrl || imgUrl || selection || pageUrl;
  369. }).toString() + ')(' + JSON.stringify(info) + ')',
  370. allFrames: false
  371. }, function (txt) {
  372. _openFileAndRun(tab, MSG_TYPE.QR_CODE, (typeof txt === 'object') ? txt[0] : txt);
  373. });
  374. },
  375. MENU_QRCODE_DECODE: function (info, tab) {
  376. _qrDecode(info, tab);
  377. },
  378. MENU_PAGE_CAPTURE: function (info, tab) {
  379. PageCapture.full(tab);
  380. },
  381. MENU_COLOR_PICKER: function (info, tab) {
  382. _showColorPicker();
  383. },
  384. MENU_STR_ENDECODE: function (info, tab) {
  385. chrome.tabs.executeScript(tab.id, {
  386. code: '(' + (function (pInfo) {
  387. return pInfo.selectionText;
  388. }).toString() + ')(' + JSON.stringify(info) + ')',
  389. allFrames: false
  390. }, function (txt) {
  391. _openFileAndRun(tab, MSG_TYPE.EN_DECODE, (typeof txt === 'object') ? txt[0] : txt);
  392. });
  393. },
  394. MENU_JSON_FORMAT: function (info, tab) {
  395. chrome.tabs.executeScript(tab.id, {
  396. code: '(' + (function (pInfo) {
  397. return pInfo.selectionText;
  398. }).toString() + ')(' + JSON.stringify(info) + ')',
  399. allFrames: false
  400. }, function (txt) {
  401. _openFileAndRun(tab, MSG_TYPE.JSON_FORMAT, (typeof txt === 'object') ? txt[0] : txt);
  402. });
  403. },
  404. MENU_CODE_FORMAT: function (info, tab) {
  405. chrome.tabs.executeScript(tab.id, {
  406. code: '(' + (function (pInfo) {
  407. return pInfo.selectionText;
  408. }).toString() + ')(' + JSON.stringify(info) + ')',
  409. allFrames: false
  410. }, function (txt) {
  411. _openFileAndRun(tab, MSG_TYPE.CODE_BEAUTIFY, (typeof txt === 'object') ? txt[0] : txt);
  412. });
  413. },
  414. MENU_AJAX_DEBUGGER: function (info, tab) {
  415. _debuggerSwitchOn(() => {
  416. _tellDevToolsDbgSwitchOn(null, true);
  417. });
  418. },
  419. MENU_CODE_STANDARD: function (info, tab) {
  420. _doFcpDetect(tab);
  421. },
  422. MENU_PAGE_OPTIMI: function (info, tab) {
  423. _getPageWpoInfo();
  424. },
  425. MENU_IMAGE_BASE64: function (info, tab) {
  426. _openFileAndRun(tab, MSG_TYPE.IMAGE_BASE64, info.srcUrl);
  427. },
  428. MENU_JSON_COMPARE: function (info, tab) {
  429. _openFileAndRun(tab, MSG_TYPE.JSON_COMPARE);
  430. },
  431. MENU_CODE_COMPRESS: function (info, tab) {
  432. _openFileAndRun(tab, MSG_TYPE.CODE_COMPRESS);
  433. },
  434. MENU_TIME_STAMP: function (info, tab) {
  435. _openFileAndRun(tab, MSG_TYPE.TIME_STAMP);
  436. },
  437. MENU_RANDOM_PASS: function (info, tab) {
  438. _openFileAndRun(tab, MSG_TYPE.RANDOM_PASSWORD);
  439. },
  440. MENU_JS_REGEXP: function (info, tab) {
  441. _openFileAndRun(tab, MSG_TYPE.REGEXP_TOOL);
  442. },
  443. MENU_MARKDOWN_TL: function (info, tab) {
  444. _openFileAndRun(tab, MSG_TYPE.HTML_TO_MARKDOWN);
  445. },
  446. MENU_STICKY_NOTE: function (info, tab) {
  447. _openFileAndRun(tab, MSG_TYPE.STICKY_NOTES);
  448. },
  449. MENU_REMOVE_BG: function (info, tab) {
  450. _openFileAndRun(tab, MSG_TYPE.REMOVE_BG);
  451. },
  452. MENU_MULTI_TOOLKIT: function (info, tab) {
  453. _openFileAndRun(tab, MSG_TYPE.MULTI_TOOLKIT);
  454. },
  455. MENU_PAGE_MODIFIER: function (info, tab) {
  456. _openFileAndRun(tab, MSG_TYPE.PAGE_MODIFIER);
  457. },
  458. MENU_GRID_RULER: function (info, tab) {
  459. _doGridDetect(tab);
  460. },
  461. MENU_DOWNLOAD_CRX: function (info, tab) {
  462. _downloadCrx(tab);
  463. }
  464. };
  465. chrome.contextMenus.create({
  466. title: menus[m].icon + ' ' + menus[m].text,
  467. contexts: menus[m].contexts || ['all'],
  468. parentId: feHelper.contextMenuId,
  469. onclick: onClick[m]
  470. });
  471. }
  472. });
  473. };
  474. /**
  475. * 创建扩展专属的右键菜单
  476. */
  477. let _createContextMenu = function () {
  478. _removeContextMenu();
  479. feHelper.contextMenuId = chrome.contextMenus.create({
  480. title: "FeHelper工具",
  481. contexts: ['page', 'selection', 'editable', 'link', 'image'],
  482. documentUrlPatterns: ['http://*/*', 'https://*/*', 'file://*/*']
  483. });
  484. if (!Settings.didMenuSettingSaved()) {
  485. _contextMenuCreator(Settings.getDefaultContextMenus());
  486. } else {
  487. Settings.getOptsFromBgPage((opts) => {
  488. _contextMenuCreator(Object.keys(opts).filter(m => /^MENU_/.test(m)));
  489. });
  490. }
  491. };
  492. /**
  493. * 移除扩展专属的右键菜单
  494. */
  495. let _removeContextMenu = function () {
  496. if (!feHelper.contextMenuId) return;
  497. chrome.contextMenus.remove(feHelper.contextMenuId);
  498. feHelper.contextMenuId = null;
  499. };
  500. /**
  501. * 创建或移除扩展专属的右键菜单
  502. */
  503. let _createOrRemoveContextMenu = function () {
  504. Settings.getOptsFromBgPage((opts) => {
  505. if (opts['opt_item_contextMenus']) {
  506. _createContextMenu();
  507. } else {
  508. _removeContextMenu();
  509. }
  510. });
  511. };
  512. /**
  513. * 二维码转码
  514. * @param info
  515. * @param tab
  516. * @private
  517. */
  518. let _qrDecode = function (info, tab) {
  519. let qrcode = Tarp.require('../static/vendor/zxing/zxing.min.js');
  520. qrcode.callback = function (text) {
  521. if ((text || '').indexOf('error decoding QR Code') !== -1) {
  522. let image = new Image();
  523. image.src = info.srcUrl;
  524. image.onload = function () {
  525. let width = this.naturalWidth;
  526. let height = this.naturalHeight;
  527. // url方式解码失败,再转换成data uri后继续解码
  528. (function createCanvasContext(img, t, l, w, h) {
  529. let canvas = document.createElement('canvas');
  530. canvas.setAttribute('id', 'qr-canvas');
  531. canvas.height = h + 100;
  532. canvas.width = w + 100;
  533. let context = canvas.getContext('2d');
  534. context.fillStyle = 'rgb(255,255,255)';
  535. context.fillRect(0, 0, canvas.width, canvas.height);
  536. context.drawImage(img, l, t, w, h, 50, 50, w, h);
  537. qrcode.callback = function (txt) {
  538. chrome.tabs.sendMessage(tab.id, {
  539. type: MSG_TYPE.QR_DECODE,
  540. result: txt
  541. });
  542. };
  543. qrcode.decode(canvas.toDataURL());
  544. })(image, 0, 0, width, height);
  545. }
  546. } else {
  547. chrome.tabs.sendMessage(tab.id, {
  548. type: MSG_TYPE.QR_DECODE,
  549. result: text
  550. });
  551. }
  552. };
  553. qrcode.decode(info.srcUrl);
  554. };
  555. /**
  556. * 显示color picker
  557. * @private
  558. */
  559. let _showColorPicker = function () {
  560. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  561. let tab = tabs[0];
  562. let tabid = tab.id;
  563. chrome.tabs.sendMessage(tabid, {
  564. type: MSG_TYPE.SHOW_COLOR_PICKER,
  565. enableColorPicker: true
  566. }, function (response) {
  567. chrome.tabs.sendMessage(tabid, {
  568. type: MSG_TYPE.SHOW_COLOR_PICKER,
  569. doPick: true
  570. }, function (r) {
  571. });
  572. });
  573. });
  574. };
  575. /**
  576. * 将网页截成一张图,实现取色
  577. * @param callback
  578. * @private
  579. */
  580. let _drawColorPicker = function (callback) {
  581. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  582. let tab = tabs[0];
  583. let tabid = tab.id;
  584. chrome.tabs.captureVisibleTab(null, {format: 'png'}, function (dataUrl) {
  585. chrome.tabs.sendMessage(tabid, {
  586. type: MSG_TYPE.SHOW_COLOR_PICKER,
  587. setPickerImage: true,
  588. pickerImage: dataUrl
  589. }, function (response) {
  590. callback && callback();
  591. });
  592. });
  593. });
  594. };
  595. /**
  596. * 在当前页面的控制台输出console
  597. * @param request
  598. * @private
  599. */
  600. let _ajaxDebugger = function (request) {
  601. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  602. let tab = tabs[0];
  603. chrome.tabs.executeScript(tab.id, {
  604. code: "(" + (function (jsonStr) {
  605. let args = JSON.parse(unescape(jsonStr));
  606. console[args[0]].apply(console, Array.prototype.slice.call(args, 1));
  607. }).toString() + ")('" + request.content + "');"
  608. });
  609. });
  610. };
  611. //判断是否可以针对json页面进行自动格式化
  612. let _jsonAutoFormatRequest = function () {
  613. Settings.getOptsFromBgPage(opts => {
  614. opts.JSON_PAGE_FORMAT && chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  615. chrome.tabs.sendMessage(tabs[0].id, {
  616. type: MSG_TYPE.JSON_PAGE_FORMAT,
  617. options: {
  618. MAX_JSON_KEYS_NUMBER: opts.MAX_JSON_KEYS_NUMBER,
  619. AUTO_TEXT_DECODE: opts.AUTO_TEXT_DECODE === 'true'
  620. }
  621. });
  622. });
  623. });
  624. };
  625. //判断是否可以针对js、css自动检测格式化
  626. let _jsCssAutoDetectRequest = function () {
  627. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  628. let tab = tabs[0];
  629. chrome.tabs.executeScript(tab.id, {
  630. code: '(' + (() => {
  631. let ext = location.pathname.substring(location.pathname.lastIndexOf(".") + 1).toLowerCase();
  632. let fileType = ({'js': 'javascript', 'css': 'css'})[ext];
  633. let contentType = document.contentType.toLowerCase();
  634. if (!fileType) {
  635. if (/\/javascript$/.test(contentType)) {
  636. fileType = 'javascript';
  637. } else if (/\/css$/.test(contentType)) {
  638. fileType = 'css';
  639. }
  640. } else if (contentType === 'text/html') {
  641. fileType = undefined;
  642. }
  643. return fileType;
  644. }).toString() + ')()'
  645. }, function (fileType) {
  646. if (fileType && fileType.length && (fileType[0] === 'javascript' || fileType[0] === 'css')) {
  647. Settings.getOptsFromBgPage(opts => {
  648. opts.JS_CSS_PAGE_BEAUTIFY && chrome.tabs.sendMessage(tab.id, {
  649. type: MSG_TYPE.JS_CSS_PAGE_BEAUTIFY,
  650. content: fileType[0]
  651. });
  652. });
  653. }
  654. });
  655. });
  656. };
  657. /**
  658. * 存储 网页涂鸦精灵 的配置
  659. * @param params
  660. * @param callback
  661. * @private
  662. */
  663. let _savePageModifierConfigs = function (params, callback) {
  664. !RegExp.prototype.toJSON && Object.defineProperty(RegExp.prototype, "toJSON", {
  665. value: RegExp.prototype.toString
  666. });
  667. localStorage.setItem(MSG_TYPE.PAGE_MODIFIER_KEY, JSON.stringify(params));
  668. callback && callback();
  669. };
  670. /**
  671. * 获取 网页涂鸦精灵 的配置,如果指定了url参数,则表示只获取对应的一条配置,否则获取全部
  672. * @param params
  673. * @param callback
  674. * @returns {*}
  675. * @private
  676. */
  677. let _getPageModifierConfigs = function (params, callback) {
  678. let cacheModifiers = JSON.parse(localStorage.getItem(MSG_TYPE.PAGE_MODIFIER_KEY) || '[]');
  679. if (params && params.url) {
  680. let result = null;
  681. cacheModifiers.some(cm => {
  682. let m = cm.mPattern.match(/\/(.*)\/(.*)?/);
  683. if ((new RegExp(m[1], m[2] || "")).test(params.url)) {
  684. result = cm;
  685. return true;
  686. }
  687. return false;
  688. });
  689. callback && callback(result);
  690. } else {
  691. callback && callback(cacheModifiers);
  692. }
  693. };
  694. /**
  695. * 接收来自content_scripts发来的消息
  696. */
  697. let _addExtensionListener = function () {
  698. chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  699. //提取配置项
  700. if (request.type === MSG_TYPE.GET_OPTIONS) {
  701. Settings.getOptsFromBgPage(callback);
  702. }
  703. //保存配置项
  704. else if (request.type === MSG_TYPE.SET_OPTIONS) {
  705. Settings.setOptsFromBgPage(request.items);
  706. //管理右键菜单
  707. _createOrRemoveContextMenu();
  708. notifyText({
  709. message: '配置已生效,请继续使用!',
  710. autoClose: 2000
  711. });
  712. }
  713. // 判断菜单是否保存过
  714. else if (request.type === MSG_TYPE.MENU_SAVED) {
  715. Settings.didMenuSettingSaved(callback);
  716. }
  717. //判断是否可以针对json页面进行自动格式化
  718. else if (request.type === MSG_TYPE.JSON_PAGE_FORMAT_REQUEST) {
  719. _jsonAutoFormatRequest();
  720. }
  721. //判断是否可以针对js、css自动检测格式化
  722. else if (request.type === MSG_TYPE.JS_CSS_PAGE_BEAUTIFY_REQUEST) {
  723. _jsCssAutoDetectRequest();
  724. }
  725. //保存当前网页加载时间
  726. else if (request.type === MSG_TYPE.CALC_PAGE_LOAD_TIME) {
  727. _showPageWpoInfo(request.wpo);
  728. }
  729. // color picker
  730. else if (request.type === MSG_TYPE.COLOR_PICKER) {
  731. _drawColorPicker(callback);
  732. }
  733. // console switch
  734. else if (request.type === MSG_TYPE.AJAX_DEBUGGER_SWITCH) {
  735. _tellDevToolsDbgSwitchOn(callback);
  736. }
  737. // console show
  738. else if (request.type === MSG_TYPE.AJAX_DEBUGGER_CONSOLE) {
  739. _ajaxDebugger(request);
  740. }
  741. // 打开设置页
  742. else if (request.type === MSG_TYPE.OPEN_OPTIONS_PAGE) {
  743. chrome.runtime.openOptionsPage();
  744. }
  745. // 开启remove-bg功能
  746. else if (request.type === MSG_TYPE.REMOVE_PERSON_IMG_BG) {
  747. Tarp.require('../remove-bg/proxy').addBackgroundRemoveListener(callback);
  748. }
  749. // 网页涂鸦精灵:获取配置
  750. else if (request.type === MSG_TYPE.GET_PAGE_MODIFIER_CONFIG) {
  751. _getPageModifierConfigs(request.params, callback);
  752. }
  753. // 网页涂鸦精灵:保存配置
  754. else if (request.type === MSG_TYPE.SAVE_PAGE_MODIFIER_CONFIG) {
  755. _savePageModifierConfigs(request.params, callback);
  756. }
  757. // ===========================以下为编码规范检测====start==================================
  758. //处理CSS的请求
  759. else if (request.type === MSG_TYPE.GET_CSS) {
  760. //直接AJAX获取CSS文件内容
  761. Network.readFileContent(request.link, callback);
  762. }
  763. //处理JS的请求
  764. else if (request.type === MSG_TYPE.GET_JS) {
  765. //直接AJAX获取JS文件内容
  766. Network.readFileContent(request.link, callback);
  767. }
  768. //处理HTML的请求
  769. else if (request.type === MSG_TYPE.GET_HTML) {
  770. //直接AJAX获取JS文件内容
  771. Network.readFileContent(request.link, callback);
  772. }
  773. //处理cookie
  774. else if (request.type === MSG_TYPE.GET_COOKIE) {
  775. Network.getCookies(request, callback);
  776. }
  777. //移除cookie
  778. else if (request.type === MSG_TYPE.REMOVE_COOKIE) {
  779. Network.removeCookie(request, callback);
  780. }
  781. //设置cookie
  782. else if (request.type === MSG_TYPE.SET_COOKIE) {
  783. Network.setCookie(request, callback);
  784. }
  785. //CSS准备就绪
  786. else if (request.type === MSG_TYPE.CSS_READY) {
  787. _detectReadyState('css', callback);
  788. }
  789. //JS准备就绪
  790. else if (request.type === MSG_TYPE.JS_READY) {
  791. _detectReadyState('js', callback);
  792. }
  793. //HTML准备就绪
  794. else if (request.type === MSG_TYPE.HTML_READY) {
  795. _detectReadyState('html', callback);
  796. }
  797. // ===========================以上为编码规范检测====end==================================
  798. return true;
  799. });
  800. // 检测DevTools是否打开
  801. let openCount = 0;
  802. chrome.runtime.onConnect.addListener(function (port) {
  803. if (port.name === MSG_TYPE.DEV_TOOLS) {
  804. if (openCount === 0) {
  805. devToolsDetected = true;
  806. }
  807. openCount++;
  808. port.onDisconnect.addListener(function (port) {
  809. openCount--;
  810. if (openCount === 0) {
  811. devToolsDetected = false;
  812. }
  813. });
  814. }
  815. });
  816. // 安装与更新
  817. chrome.runtime.onInstalled.addListener(({reason, previousVersion}) => {
  818. switch (reason) {
  819. case 'install':
  820. chrome.runtime.openOptionsPage();
  821. break;
  822. case 'update':
  823. setTimeout(() => {
  824. chrome.browserAction.setBadgeText({text: '+++1'});
  825. setTimeout(() => {
  826. chrome.browserAction.setBadgeText({text: ''});
  827. }, 1500);
  828. }, 1500);
  829. break;
  830. }
  831. });
  832. // 卸载
  833. chrome.runtime.setUninstallURL(feHelper.manifest.homepage_url);
  834. };
  835. /**
  836. * 检查插件更新
  837. * @private
  838. */
  839. let _checkUpdate = function () {
  840. setTimeout(() => {
  841. chrome.runtime.requestUpdateCheck((status) => {
  842. if (status === "update_available") {
  843. chrome.runtime.reload();
  844. }
  845. });
  846. }, 1000 * 10);
  847. };
  848. /**
  849. * 初始化
  850. */
  851. let _init = function () {
  852. _checkUpdate();
  853. _addExtensionListener();
  854. _createOrRemoveContextMenu();
  855. };
  856. /**
  857. * 打开任意一个URL
  858. * @param url
  859. * @private
  860. */
  861. let _openUrl = function(url){
  862. chrome.tabs.create({url: url});
  863. };
  864. return {
  865. init: _init,
  866. runHelper: _runHelper,
  867. notify: notifyText,
  868. showColorPicker: _showColorPicker,
  869. tellMeAjaxDbgSwitch: _tellDevToolsDbgSwitchOn,
  870. getCapturedData: PageCapture.getCapturedData,
  871. openUrl: _openUrl
  872. };
  873. })();
  874. //初始化
  875. BgPageInstance.init();