fe-background.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /**
  2. * FE-Helper后台运行程序
  3. * @author [email protected]
  4. */
  5. var BgPageInstance = (function () {
  6. // debug cache,主要记录每个tab的ajax debug 开关
  7. var ajaxDbgCache = {};
  8. //各种元素的就绪情况
  9. var _readyState = {
  10. css: false,
  11. js: false,
  12. html: true,
  13. allDone: false
  14. };
  15. /**
  16. * 文本格式,可以设置一个图标和标题
  17. * @param {Object} options
  18. * @config {string} type notification的类型,可选值:html、text
  19. * @config {string} icon 图标
  20. * @config {string} title 标题
  21. * @config {string} message 内容
  22. */
  23. var notifyText = function (options) {
  24. if (!window.Notification) {
  25. return;
  26. }
  27. if (!options.icon) {
  28. options.icon = "static/img/fe-48.png";
  29. }
  30. if (!options.title) {
  31. options.title = "温馨提示";
  32. }
  33. return chrome.notifications.create('', {
  34. type: 'basic',
  35. title: options.title,
  36. iconUrl: chrome.runtime.getURL(options.icon),
  37. message: options.message
  38. });
  39. };
  40. //侦测就绪情况
  41. var _detectReadyState = function (callback) {
  42. if (_readyState.css && _readyState.js && _readyState.html) {
  43. _readyState.allDone = true;
  44. }
  45. if (_readyState.allDone && typeof callback == 'function') {
  46. callback();
  47. }
  48. };
  49. var _fcp_detect_interval = [];
  50. /**
  51. * 执行前端FCPHelper检测
  52. */
  53. var _doFcpDetect = function (tab) {
  54. //所有元素都准备就绪
  55. if (_readyState.allDone) {
  56. clearInterval(_fcp_detect_interval[tab.id]);
  57. chrome.tabs.sendMessage(tab.id, {
  58. type: MSG_TYPE.BROWSER_CLICKED,
  59. event: MSG_TYPE.FCP_HELPER_DETECT
  60. });
  61. } else if (_fcp_detect_interval[tab.id] === undefined) {
  62. chrome.tabs.sendMessage(tab.id, {
  63. type: MSG_TYPE.BROWSER_CLICKED,
  64. event: MSG_TYPE.FCP_HELPER_INIT
  65. });
  66. //显示桌面提醒
  67. notifyText({
  68. message: "正在准备数据,请稍等..."
  69. });
  70. _fcp_detect_interval[tab.id] = setInterval(function () {
  71. _doFcpDetect(tab);
  72. }, 200);
  73. }
  74. };
  75. /**
  76. * 查看页面wpo信息
  77. */
  78. var _showPageWpoInfo = function (wpoInfo) {
  79. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  80. if (!wpoInfo) {
  81. notifyText({
  82. message: "对不起,检测失败"
  83. });
  84. } else {
  85. chrome.tabs.create({
  86. url: "template/fehelper_wpo.html?" + btoa(encodeURIComponent(JSON.stringify(wpoInfo))),
  87. active: true
  88. });
  89. }
  90. });
  91. };
  92. /**
  93. * 获取页面wpo信息
  94. * @return {[type]}
  95. */
  96. var _getPageWpoInfo = function () {
  97. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  98. var tab = tabs[0];
  99. //显示桌面提醒
  100. chrome.tabs.sendMessage(tab.id, {
  101. type: MSG_TYPE.GET_PAGE_WPO_INFO
  102. });
  103. });
  104. };
  105. /**
  106. * 代码压缩工具
  107. * @private
  108. */
  109. var _goCompressTool = function () {
  110. var url = "http://www.baidufe.com/fehelper/codecompress.html";
  111. chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, function (tabs) {
  112. var isOpened = false;
  113. var tabId;
  114. var reg = new RegExp("fehelper.*codecompress.html$", "i");
  115. for (var i = 0, len = tabs.length; i < len; i++) {
  116. if (reg.test(tabs[i].url)) {
  117. isOpened = true;
  118. tabId = tabs[i].id;
  119. break;
  120. }
  121. }
  122. if (!isOpened) {
  123. chrome.tabs.create({
  124. url: url,
  125. active: true
  126. });
  127. } else {
  128. chrome.tabs.update(tabId, {highlighted: true});
  129. }
  130. });
  131. };
  132. /**
  133. * 创建或更新成功执行的动作
  134. * @param evt
  135. * @param content
  136. * @private
  137. */
  138. var _tabUpdatedCallback = function (evt, content) {
  139. return function (newTab) {
  140. if (content) {
  141. setTimeout(function () {
  142. chrome.tabs.sendMessage(newTab.id, {
  143. type: MSG_TYPE.TAB_CREATED_OR_UPDATED,
  144. content: content,
  145. event: evt
  146. });
  147. }, 300)
  148. }
  149. };
  150. };
  151. /**
  152. * 打开对应文件,运行该Helper
  153. * @param tab
  154. * @param file
  155. * @param txt
  156. * @private
  157. */
  158. var _openFileAndRun = function (tab, file, txt) {
  159. chrome.tabs.query({windowId: chrome.windows.WINDOW_ID_CURRENT}, function (tabs) {
  160. var isOpened = false;
  161. var tabId;
  162. var reg = new RegExp("^chrome.*" + file + ".html$", "i");
  163. for (var i = 0, len = tabs.length; i < len; i++) {
  164. if (reg.test(tabs[i].url)) {
  165. isOpened = true;
  166. tabId = tabs[i].id;
  167. break;
  168. }
  169. }
  170. if (!isOpened) {
  171. chrome.tabs.create({
  172. url: 'template/fehelper_' + file + '.html',
  173. active: true
  174. }, _tabUpdatedCallback(file, txt));
  175. } else {
  176. chrome.tabs.update(tabId, {highlighted: true}, _tabUpdatedCallback(file, txt));
  177. }
  178. });
  179. };
  180. /**
  181. * ajax debugger 开关切换
  182. * @private
  183. */
  184. var _debuggerSwitchOn = function () {
  185. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  186. var tab = tabs[0];
  187. ajaxDbgCache[tab.id] = !ajaxDbgCache[tab.id];
  188. chrome.tabs.executeScript(tab.id, {
  189. code: 'console.info("FeHelper提醒:Ajax Debugger开关已' + (ajaxDbgCache[tab.id] ? '开启' : '关闭') + '!");',
  190. allFrames: false
  191. });
  192. });
  193. };
  194. /**
  195. * 告诉DevTools页面,当前的debug开关是否打开
  196. * @param callback
  197. * @private
  198. */
  199. var _tellDevToolsDbgSwitchOn = function (callback) {
  200. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  201. var tab = tabs[0];
  202. callback && callback(ajaxDbgCache[tab.id]);
  203. });
  204. };
  205. /**
  206. * 根据给定参数,运行对应的Helper
  207. */
  208. var _runHelper = function (config) {
  209. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  210. var tab = tabs[0];
  211. // 如果是采用独立文件方式访问,直接打开该页面即可
  212. if (config.useFile == '1') {
  213. var content = config.msgType == MSG_TYPE.QR_CODE ? tab.url : '';
  214. _openFileAndRun(tab, config.msgType, content);
  215. } else {
  216. switch (config.msgType) {
  217. //fcphelper检测
  218. case MSG_TYPE.FCP_HELPER_DETECT:
  219. _doFcpDetect(tab);
  220. break;
  221. //查看网页加载时间
  222. case MSG_TYPE.SHOW_PAGE_LOAD_TIME:
  223. _getPageWpoInfo();
  224. break;
  225. //代码压缩
  226. case MSG_TYPE.CODE_COMPRESS:
  227. _goCompressTool();
  228. break;
  229. //Ajax调试
  230. case MSG_TYPE.AJAX_DEBUGGER:
  231. _debuggerSwitchOn();
  232. break;
  233. default :
  234. break;
  235. }
  236. }
  237. });
  238. };
  239. /**
  240. * 创建扩展专属的右键菜单
  241. */
  242. var _createContextMenu = function () {
  243. _removeContextMenu();
  244. baidu.contextMenuId = chrome.contextMenus.create({
  245. title: "FeHelper",
  246. contexts: ['page', 'selection', 'editable', 'link'],
  247. documentUrlPatterns: ['http://*/*', 'https://*/*']
  248. });
  249. chrome.contextMenus.create({
  250. title: "生成二维码",
  251. contexts: ['page', 'selection', 'editable', 'link'],
  252. parentId: baidu.contextMenuId,
  253. onclick: function (info, tab) {
  254. chrome.tabs.executeScript(tab.id, {
  255. code: '(' + (function () {
  256. return window.getSelection().toString() || location.href;
  257. }).toString() + ')()',
  258. allFrames: false
  259. }, function (txt) {
  260. _openFileAndRun(tab, 'qrcode', txt);
  261. });
  262. }
  263. });
  264. chrome.contextMenus.create({
  265. type: 'separator',
  266. contexts: ['all'],
  267. parentId: baidu.contextMenuId
  268. });
  269. chrome.contextMenus.create({
  270. title: "页面取色器",
  271. contexts: ['page', 'selection', 'editable'],
  272. parentId: baidu.contextMenuId,
  273. onclick: function (info, tab) {
  274. _showColorPicker();
  275. }
  276. });
  277. chrome.contextMenus.create({
  278. type: 'separator',
  279. contexts: ['all'],
  280. parentId: baidu.contextMenuId
  281. });
  282. chrome.contextMenus.create({
  283. title: "字符串编解码",
  284. contexts: ['page', 'selection', 'editable'],
  285. parentId: baidu.contextMenuId,
  286. onclick: function (info, tab) {
  287. chrome.tabs.executeScript(tab.id, {
  288. code: '(' + (function () {
  289. return window.getSelection().toString();
  290. }).toString() + ')()',
  291. allFrames: false
  292. }, function (txt) {
  293. _openFileAndRun(tab, 'endecode', txt);
  294. });
  295. }
  296. });
  297. chrome.contextMenus.create({
  298. type: 'separator',
  299. contexts: ['all'],
  300. parentId: baidu.contextMenuId
  301. });
  302. chrome.contextMenus.create({
  303. title: "JSON格式化",
  304. contexts: ['page', 'selection', 'editable'],
  305. parentId: baidu.contextMenuId,
  306. onclick: function (info, tab) {
  307. chrome.tabs.executeScript(tab.id, {
  308. code: '(' + (function () {
  309. return window.getSelection().toString();
  310. }).toString() + ')()',
  311. allFrames: false
  312. }, function (txt) {
  313. _openFileAndRun(tab, 'jsonformat', txt);
  314. });
  315. }
  316. });
  317. chrome.contextMenus.create({
  318. type: 'separator',
  319. contexts: ['all'],
  320. parentId: baidu.contextMenuId
  321. });
  322. chrome.contextMenus.create({
  323. title: "代码格式化",
  324. contexts: ['page', 'selection', 'editable'],
  325. parentId: baidu.contextMenuId,
  326. onclick: function (info, tab) {
  327. chrome.tabs.executeScript(tab.id, {
  328. code: '(' + (function () {
  329. return window.getSelection().toString();
  330. }).toString() + ')()',
  331. allFrames: false
  332. }, function (txt) {
  333. _openFileAndRun(tab, 'codebeautify', txt);
  334. });
  335. }
  336. });
  337. };
  338. /**
  339. * 移除扩展专属的右键菜单
  340. */
  341. var _removeContextMenu = function () {
  342. if (!baidu.contextMenuId) return;
  343. chrome.contextMenus.remove(baidu.contextMenuId);
  344. baidu.contextMenuId = null;
  345. };
  346. /**
  347. * 创建或移除扩展专属的右键菜单
  348. */
  349. var _createOrRemoveContextMenu = function () {
  350. //管理右键菜单
  351. if (baidu.feOption.getOptionItem('opt_item_contextMenus') !== 'false') {
  352. _createContextMenu();
  353. } else {
  354. _removeContextMenu();
  355. }
  356. };
  357. /**
  358. * 显示color picker
  359. * @private
  360. */
  361. var _showColorPicker = function () {
  362. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  363. var tab = tabs[0];
  364. var tabid = tab.id;
  365. var port = chrome.tabs.connect(tabid, {name: "popupshown"});
  366. chrome.tabs.sendMessage(tabid, {enableColorPicker: true}, function (response) {
  367. chrome.tabs.sendMessage(tabid, {doPick: true}, function (r) {
  368. });
  369. });
  370. });
  371. };
  372. /**
  373. * 将网页截成一张图,实现取色
  374. * @param callback
  375. * @private
  376. */
  377. var _drawColorPicker = function (callback) {
  378. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  379. var tab = tabs[0];
  380. var tabid = tab.id;
  381. chrome.tabs.captureVisibleTab(null, {format: 'png'}, function (dataUrl) {
  382. chrome.tabs.sendMessage(tabid, {
  383. setPickerImage: true,
  384. pickerImage: dataUrl
  385. }, function (response) {
  386. callback && callback();
  387. });
  388. });
  389. });
  390. };
  391. /**
  392. * 在当前页面的控制台输出console
  393. * @param request
  394. * @private
  395. */
  396. var _ajaxDebugger = function (request) {
  397. chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
  398. var tab = tabs[0];
  399. chrome.tabs.executeScript(tab.id, {
  400. code: "(" + (function (jsonStr) {
  401. var args = JSON.parse(unescape(jsonStr));
  402. console[args[0]].apply(console, Array.prototype.slice.call(args, 1));
  403. }).toString() + ")('" + request.content + "');"
  404. });
  405. });
  406. };
  407. /**
  408. * 接收来自content_scripts发来的消息
  409. */
  410. var _addExtensionListener = function () {
  411. chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  412. //处理CSS的请求
  413. if (request.type == MSG_TYPE.GET_CSS) {
  414. //直接AJAX获取CSS文件内容
  415. baidu.network.readFileContent(request.link, callback);
  416. }
  417. //处理JS的请求
  418. else if (request.type == MSG_TYPE.GET_JS) {
  419. //直接AJAX获取JS文件内容
  420. baidu.network.readFileContent(request.link, callback);
  421. }
  422. //处理HTML的请求
  423. else if (request.type == MSG_TYPE.GET_HTML) {
  424. //直接AJAX获取JS文件内容
  425. baidu.network.readFileContent(request.link, callback);
  426. }
  427. //处理cookie
  428. else if (request.type == MSG_TYPE.GET_COOKIE) {
  429. baidu.network.getCookies(request, callback);
  430. }
  431. //移除cookie
  432. else if (request.type == MSG_TYPE.REMOVE_COOKIE) {
  433. baidu.network.removeCookie(request, callback);
  434. }
  435. //设置cookie
  436. else if (request.type == MSG_TYPE.SET_COOKIE) {
  437. baidu.network.setCookie(request, callback);
  438. }
  439. //CSS准备就绪
  440. else if (request.type == MSG_TYPE.CSS_READY) {
  441. _readyState.css = true;
  442. _detectReadyState(callback);
  443. }
  444. //JS准备就绪
  445. else if (request.type == MSG_TYPE.JS_READY) {
  446. _readyState.js = true;
  447. _detectReadyState(callback);
  448. }
  449. //HTML准备就绪
  450. else if (request.type == MSG_TYPE.HTML_READY) {
  451. _readyState.html = true;
  452. _detectReadyState(callback);
  453. }
  454. //提取配置项
  455. else if (request.type == MSG_TYPE.GET_OPTIONS) {
  456. baidu.feOption.doGetOptions(request.items, callback);
  457. }
  458. //保存配置项
  459. else if (request.type == MSG_TYPE.SET_OPTIONS) {
  460. baidu.feOption.doSetOptions(request.items, callback);
  461. //管理右键菜单
  462. _createOrRemoveContextMenu();
  463. }
  464. //保存当前网页加载时间
  465. else if (request.type == MSG_TYPE.CALC_PAGE_LOAD_TIME) {
  466. _showPageWpoInfo(request.wpo);
  467. }
  468. // 从popup中点过来的
  469. else if (request.type == MSG_TYPE.FROM_POPUP) {
  470. _runHelper(request.config);
  471. }
  472. // color picker
  473. else if (request.type == MSG_TYPE.COLOR_PICKER) {
  474. _drawColorPicker(callback);
  475. }
  476. // console switch
  477. else if (request.type == MSG_TYPE.AJAX_DEBUGGER_SWITCH) {
  478. _tellDevToolsDbgSwitchOn(callback);
  479. }
  480. // console show
  481. else if (request.type == MSG_TYPE.AJAX_DEBUGGER_CONSOLE) {
  482. _ajaxDebugger(request);
  483. }
  484. return true;
  485. });
  486. };
  487. /**
  488. * 初始化
  489. */
  490. var _init = function () {
  491. _addExtensionListener();
  492. _createOrRemoveContextMenu();
  493. };
  494. return {
  495. init: _init,
  496. runHelper: _runHelper,
  497. showColorPicker: _showColorPicker,
  498. tellMeAjaxDbgSwitch: _tellDevToolsDbgSwitchOn
  499. };
  500. })();
  501. //初始化
  502. BgPageInstance.init();