index.js 16 KB

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