main.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. void function () {
  2. var currentCodeId, codes, pageComments, host;
  3. var restorePageEnvironments = function () {
  4. var i, lastTimerId, tempIframe, fixList, tempArray, sourceArray,
  5. tempDocument;
  6. lastTimerId = setTimeout("1", 0);
  7. for (i = lastTimerId, down = Math.max(0, lastTimerId - 200);
  8. i >= down; i--)
  9. clearTimeout(i),
  10. clearInterval(i);
  11. // NOTE: 恢复可能被目标页面破坏掉的几个主要的 Array 方法
  12. tempIframe = host.createElement("iframe");
  13. tempIframe.style.cssText = "width: 1px; height: 1px; top: -1000px; position: absolute;";
  14. host.body.appendChild(tempIframe);
  15. fixList = ( "push, pop, slice, splice, shift, unshift, concat, join, reverse" ).split(", ");
  16. tempArray = tempIframe.contentWindow.Array.prototype;
  17. sourceArray = Array.prototype;
  18. for (i = 0, l = fixList.length; i < l; i++)
  19. sourceArray[fixList[i]] = tempArray[fixList[i]];
  20. fixList = ["open", "write", "close"];
  21. tempDocument = tempIframe.contentDocument;
  22. for (i = 0, l = fixList.length; i < l; i++)
  23. host[fixList[i]] = function (fn, host) {
  24. return function () {
  25. return fn.apply(host, arguments);
  26. }
  27. }(tempDocument[fixList[i]], host);
  28. host.body.removeChild(tempIframe);
  29. tempIframe = null;
  30. tempDocument = null;
  31. };
  32. var AsynStringReplacer = function () {
  33. var restoreRegx = /\({3}AsynStringReplacer:(\d+)\){3}/g;
  34. return {
  35. replace: function (origContent, regx, pmReplaceFn) {
  36. var cache, tasks = [], content = origContent, index = 0,
  37. pm = new Tracker.Promise();
  38. content = content.replace(regx, function () {
  39. tasks.push(pmReplaceFn.apply(null, arguments));
  40. return "(((AsynStringReplacer:" + ( index++ ) + ")))";
  41. });
  42. Tracker.Promise.when(tasks).then(function () {
  43. cache = [].slice.call(arguments, 0);
  44. content = content.replace(restoreRegx, function (s, index) {
  45. return cache[index - 0];
  46. });
  47. pm.resolve(content);
  48. });
  49. return pm;
  50. }
  51. };
  52. }();
  53. var initControllerOnLoad = function () {
  54. Tracker.controllerOnLoad = Tracker.Promise.fuze();
  55. Tracker.controllerOnLoad(function (window, document) {
  56. var waitTime, loadingEl;
  57. window.onbeforeunload = function () {
  58. var startTime = Tracker.Util.time();
  59. return function () {
  60. if (Tracker.Util.time() - startTime < 3e3)
  61. setTimeout(function () {
  62. var h = window.location.hash;
  63. window.location.href = ~h.indexOf("#") ? h : "#" + h;
  64. }, 0);
  65. }
  66. }();
  67. waitTime = document.getElementById("waitTime");
  68. loadingEl = document.getElementById("loading");
  69. loadingEl.style.display = "block";
  70. Tracker.Util.onCpuFree(function () {
  71. waitTime.innerHTML = "(100.000000 %)";
  72. loadingEl.style.height = "0";
  73. Tracker.View.ControlPanel.activeTab("code-list");
  74. setTimeout(function () {
  75. loadingEl.parentNode.removeChild(loadingEl);
  76. }, 5e2);
  77. }, function (t) {
  78. waitTime.innerHTML = "(" + ( 1e2 - 1e2 / Math.max(t, 1e2) ).toFixed(6) + "%)";
  79. });
  80. Tracker.TrackerGlobalEvent.on("bootstrap: dropdown.open", function () {
  81. if (Tracker.View.ControlPanel.activeTab() == 0)
  82. Tracker.View.ControlPanel.setControlPower(true);
  83. });
  84. Tracker.TrackerGlobalEvent.on("bootstrap: dropdown.close", function () {
  85. if (Tracker.View.ControlPanel.activeTab() == 0)
  86. Tracker.View.ControlPanel.setControlPower(false);
  87. });
  88. Tracker.TrackerGlobalEvent.on("bootstrap: dialog.open", function () {
  89. setTimeout(function () { // trigger by dropdown
  90. if (Tracker.View.ControlPanel.activeTab() == 0)
  91. Tracker.View.ControlPanel.setControlPower(true);
  92. }, 1);
  93. });
  94. Tracker.TrackerGlobalEvent.on("bootstrap: dialog.close", function () {
  95. if (Tracker.View.ControlPanel.activeTab() == 0)
  96. Tracker.View.ControlPanel.setControlPower(false);
  97. });
  98. setTimeout(function () {
  99. Tracker.Plugins.prepare({
  100. name: "general",
  101. type: "TopPanel",
  102. label: "综合结果",
  103. bodyId: "plugin-general-page"
  104. });
  105. Tracker.setupGeneralPlugin();
  106. Tracker.Plugins.prepare({
  107. name: "watch",
  108. type: "TopPanel",
  109. label: "活动监视器",
  110. bodyId: "plugin-watch-page"
  111. });
  112. Tracker.setupWatchPlugin();
  113. }, 5e2);
  114. });
  115. Tracker.controllerOnLoad(Tracker.Util.bind(Tracker.View.ControlFrame.show, Tracker.View.ControlFrame));
  116. };
  117. var initPageBuilder = function () {
  118. Tracker.View.ControlFrame.pageBuilder(function (html) {
  119. var pm = new Tracker.Promise(),
  120. charset = document.characterSet,
  121. allScriptTagRegx = /(<script\b[^>]*>)([\s\S]*?)(<\/script>)/gi,
  122. srcPropertyRegx = / src=["']([^"']+)["']/,
  123. typePropertyRegx = / type=["']([^"']+)["']/,
  124. scriptRegx = /(<script\b [^>]*src=["']([^"']+)["'][^>]*>)\s*(<\/script>)/gi,
  125. firstTagRegx = /(<[^>]+>)/,
  126. lineBreakRegx = /\r\n|[\r\n]/g,
  127. a, b, i, l, r;
  128. var proxyScript = '<script type="text/javascript" src="' + chrome.runtime.getURL('/static/js/tracker/inject.js') + '"></script>';
  129. Tracker.Util.request(location.href, charset).then(function (html) {
  130. html = html.response;
  131. for (i = 0, l = pageComments.length; i < l; i++) {
  132. r = "<!--" + pageComments[i] + "-->";
  133. a = r.replace(lineBreakRegx, "\r\n");
  134. b = r.replace(lineBreakRegx, "\n");
  135. html = html.replace(a, "").replace(b, "");
  136. }
  137. AsynStringReplacer.replace(html, allScriptTagRegx,
  138. function (raw, openTag, content, closeTag) {
  139. var pm, code;
  140. pm = new Tracker.Promise();
  141. if (srcPropertyRegx.test(openTag)) { // is outer script
  142. Tracker.View.Loading.addCount();
  143. pm.resolve(raw);
  144. return pm;
  145. }
  146. if (typePropertyRegx.test(openTag) &&
  147. RegExp.$1.toLowerCase() != "text/javascript") { // is not javascript
  148. // TODO: 对于非 text/javascript,将来也放到 code list 中,以便于查询
  149. pm.resolve(raw);
  150. return pm;
  151. }
  152. // embed script
  153. Tracker.View.Loading.addCount();
  154. code = new Tracker.Code(null, content);
  155. code.loadConsum = 0;
  156. code.setType("embed");
  157. Tracker.CodeList.add(code);
  158. code.onReady(function () {
  159. pm.resolve(openTag + code.executiveCode + closeTag);
  160. Tracker.View.Loading.addProgress();
  161. });
  162. return pm;
  163. }
  164. ).then(function (html) {
  165. AsynStringReplacer.replace(html, scriptRegx,
  166. function (raw, openTag, url, closeTag) {
  167. var pm, content;
  168. pm = new Tracker.Promise();
  169. openTag = openTag.replace(srcPropertyRegx, " tracker-src='$1'");
  170. Tracker.Util.intelligentGet(url).then(function (data) {
  171. var code;
  172. content = data.response;
  173. code = new Tracker.Code(url, content);
  174. code.loadConsum = data.consum;
  175. code.setType("link");
  176. Tracker.CodeList.add(code);
  177. code.onReady(function () {
  178. Tracker.View.Loading.addProgress();
  179. pm.resolve(openTag + code.executiveCode + closeTag);
  180. });
  181. }, function () {
  182. var code;
  183. code = new Tracker.Code(url);
  184. code.setState("timeout");
  185. Tracker.CodeList.add(code);
  186. Tracker.View.Loading.addProgress();
  187. pm.resolve(raw);
  188. });
  189. return pm;
  190. }
  191. ).then(function (html) {
  192. Tracker.View.Loading.hide();
  193. Tracker.Util.delay(function () {
  194. Tracker.CodeList.sort();
  195. if (!~html.indexOf("<html"))
  196. html = "<html>" + html;
  197. pm.resolve(html.replace(firstTagRegx, "$1" + proxyScript));
  198. });
  199. });
  200. });
  201. }, function () {
  202. var message, refresh;
  203. message = "处理超时"; // 处理超时
  204. refresh = function () {
  205. location.assign(location.href);
  206. };
  207. Tracker.View.Loading.text(message).then(refresh);
  208. });
  209. return pm;
  210. });
  211. };
  212. var initControlFrame = function () {
  213. Tracker.View.ControlFrame.controllerBuilder(Tracker.View.ControlPanel.htmlBuilder);
  214. Tracker.View.ControlFrame.on({
  215. "controllerLoad": function (window, document) {
  216. Tracker.View.ControlPanel.bindWindow(window);
  217. Tracker.View.ControlPanel.addCode(codes = Tracker.CodeList.list());
  218. Tracker.View.ControlPanel.eventBuilder();
  219. Tracker.controllerOnLoad.fire(window, document);
  220. if (currentCodeId)
  221. Tracker.View.ControlPanel.showCodeDetail(currentCodeId);
  222. document.getElementById("top-nav").tabEvent.on("active", function (index, name) {
  223. var b;
  224. Tracker.View.ControlPanel.setControlPower(b = index > 0, b);
  225. if (name == "code-list")
  226. Tracker.View.ControlPanel.showCodeDetail(false);
  227. });
  228. },
  229. "hide": function () {
  230. Tracker.View.ControlPanel.autoUpdateCodeStop();
  231. },
  232. "show": function () {
  233. Tracker.View.ControlPanel.autoUpdateCodeStart();
  234. },
  235. pageLoad: function (topWin, pageWin) {
  236. Tracker.Decorate(topWin, pageWin);
  237. topWin.document.getElementById('btnTrackerProxy').addEventListener('click', function (e) {
  238. var type = this.getAttribute('data-type');
  239. switch (type) {
  240. case '__tracker__':
  241. var groupId = this.getAttribute('data-groupId');
  242. topWin[type](groupId);
  243. break;
  244. case '__trackerError__':
  245. var codeId = this.getAttribute('data-codeId');
  246. var msg = this.getAttribute('data-msg');
  247. topWin[type](codeId, msg);
  248. break;
  249. case '__trackerMockTop__':
  250. topWin[type]();
  251. break;
  252. case '__trackerScriptStart__':
  253. var codeId = this.getAttribute('data-codeId');
  254. var scriptTagIndex = this.getAttribute('data-scriptTagIndex');
  255. topWin[type](codeId, scriptTagIndex);
  256. break;
  257. case '__trackerScriptEnd__':
  258. var codeId = this.getAttribute('data-codeId');
  259. topWin[type](codeId);
  260. break;
  261. case 'onbeforeunload':
  262. topWin[type]();
  263. break;
  264. }
  265. }, false);
  266. }
  267. });
  268. Tracker.View.ControlPanel.actions(function (be) {
  269. be = function (action) {
  270. return function () {
  271. if (Tracker.View.ControlFrame.getMode() == "embed" &&
  272. Tracker.View.ControlPanel.activeTab() > 0)
  273. Tracker.View.ControlPanel.activeTab(0);
  274. Tracker.View.ControlFrame[action]();
  275. };
  276. };
  277. return {
  278. "frame#close": be("hide"),
  279. "frame#toggle": be("toggleMode")
  280. }
  281. }());
  282. };
  283. /**
  284. * 启动js tracker
  285. */
  286. var startTrack = function () {
  287. initControllerOnLoad();
  288. host = window.document;
  289. pageComments = Tracker.Util.getHtmlComments(host.documentElement);
  290. Tracker.TrackerGlobalEvent = Tracker.Event.bind();
  291. initPageBuilder();
  292. initControlFrame();
  293. restorePageEnvironments();
  294. Tracker.View.Loading.show();
  295. Tracker.View.ControlFrame.createEmbed();
  296. };
  297. // 在tab创建或者更新时候,监听事件,看看是否有参数传递过来
  298. chrome.runtime.onMessage.addListener(function (request, sender, callback) {
  299. if (request.type == MSG_TYPE.JS_TRACKER) {
  300. startTrack();
  301. }
  302. });
  303. }();