/deps/webmachine/trace/wmtrace.js

https://code.google.com/p/zotonic/ · JavaScript · 713 lines · 581 code · 131 blank · 1 comment · 75 complexity · 75bd52062dc90411416d95147e956758 MD5 · raw file

  1. var HIGHLIGHT = '#cc00cc';
  2. var REGULAR = '#666666';
  3. var cols = {
  4. 'a':173,
  5. 'b':325,
  6. 'c':589,
  7. 'd':797,
  8. 'e':1005,
  9. 'f':1195,
  10. 'g':1402,
  11. 'gg':1515,
  12. 'h':1572,
  13. 'i':1799,
  14. 'j':1893,
  15. 'k':1988,
  16. 'l':2157,
  17. 'll':2346,
  18. 'm':2403,
  19. 'mm':2535,
  20. 'n':2554,
  21. 'o':2649,
  22. 'oo':2781,
  23. 'ooo':2801,
  24. 'p':2894,
  25. 'q':3007
  26. };
  27. var rows = {
  28. '1':221,
  29. '2':298,
  30. '3':373,
  31. '4':448,
  32. '5':524,
  33. '6':599,
  34. '7':675,
  35. '8':751,
  36. '9':826,
  37. '10':902,
  38. '11':977,
  39. '12':1053,
  40. '13':1129,
  41. '14':1204,
  42. '15':1280,
  43. '16':1355,
  44. '17':1431,
  45. '18':1506,
  46. '19':1583,
  47. '20':1658,
  48. '21':1734,
  49. '22':1809,
  50. '23':1885,
  51. '24':1961,
  52. '25':2036,
  53. '26':2112
  54. };
  55. var edges = {
  56. 'b14b13':['b14','b13'],
  57. 'b13b12':['b13','b12'],
  58. 'b13503':['b13','503'],
  59. 'b12b11':['b12','b11'],
  60. 'b12501':['b12','501'],
  61. 'b11b10':['b11','b10'],
  62. 'b11414':['b11','414'],
  63. 'b10b9':['b10','b9'],
  64. 'b10405':['b10','405'],
  65. 'b9b8':['b9','b8'],
  66. 'b9400':['b9','400'],
  67. 'b8b7':['b8','b7'],
  68. 'b8401':['b8','401'],
  69. 'b7b6':['b7','b6'],
  70. 'b7403':['b7','403'],
  71. 'b6b5':['b6','b5'],
  72. 'b6501':['b6','501a'],
  73. 'b5b4':['b5','b4'],
  74. 'b5415':['b5','415'],
  75. 'b4b3':['b4','b3'],
  76. 'b4413':['b4','b4'],
  77. 'b3c3':['b3','c3'],
  78. 'b3200':['b3','200'],
  79. 'c3c4':['c3','c4'],
  80. 'c3d4':['c3','d3','d4'],
  81. 'c4d4':['c4','d4'],
  82. 'c4406':['c4','406'],
  83. 'd4d5':['d4','d5'],
  84. 'd4e5':['d4','e4','e5'],
  85. 'd5e5':['d5','e5'],
  86. 'd5406':['d5','d7','406'],
  87. 'e5e6':['e5','e6'],
  88. 'e5f6':['e5','f5','f6'],
  89. 'e6f6':['e6','f6'],
  90. 'e6406':['e6','e7','406'],
  91. 'f6f7':['f6','f7'],
  92. 'f6g7':['f6','g6','g7'],
  93. 'f7g7':['f7','g7'],
  94. 'f7406':['f7','406'],
  95. 'g7g8':['g7','g8'],
  96. 'g7h7':['g7','h7'],
  97. 'g8g9':['g8','g9'],
  98. 'g8h10':['g8','h8','h10'],
  99. 'g9g11':['g9','g11'],
  100. 'g9h10':['g9','gg9','gg10','h10'],
  101. 'g11h10':['g11','gg11','gg10','h10'],
  102. 'g11412':['g11','g18','412a'],
  103. 'h7i7':['h7','i7'],
  104. 'h7412':['h7','412'],
  105. 'h10h11':['h10','h11'],
  106. 'h10i12':['h10','i10','i12'],
  107. 'h11h12':['h11','h12'],
  108. 'h11i12':['h11','i11','i12'],
  109. 'h12i12':['h12','i12'],
  110. 'h12412':['h12','412a'],
  111. 'i4p3':['i4','i3','p3'],
  112. 'i4301':['i4','301'],
  113. 'i7i4':['i7','i4'],
  114. 'i7k7':['i7','k7'],
  115. 'i12l13':['i12','l12','l13'],
  116. 'i12i13':['i12','i13'],
  117. 'i13k13':['i13','k13'],
  118. 'i13j18':['i13','i17','j17','j18'],
  119. 'j18412':['j18','412a'],
  120. 'j18304':['j18','304'],
  121. 'k5l5':['k5','l5'],
  122. 'k5301':['k5','301'],
  123. 'k7k5':['k7','k5'],
  124. 'k7l7':['k7','l7'],
  125. 'k13j18':['k13','k17','j17','j18'],
  126. 'k13l13':['k13','l13'],
  127. 'l5m5':['l5','m5'],
  128. 'l5307':['l5','307'],
  129. 'l7m7':['l7','m7'],
  130. 'l7404':['l7','l8','404'],
  131. 'l13l14':['l13','l14'],
  132. 'l13m16':['l13','m13','m16'],
  133. 'l14l15':['l14','l15'],
  134. 'l14m16':['l14','m14','m16'],
  135. 'l15l17':['l15','l17'],
  136. 'l15m16':['l15','ll15','ll16','m16'],
  137. 'l17m16':['l17','ll17','ll16','m16'],
  138. 'l17304':['l17','304'],
  139. 'm5n5':['m5','n5'],
  140. 'm5410':['m5','m4','410'],
  141. 'm7n11':['m7','n7','n11'],
  142. 'm7404':['m7','404'],
  143. 'm16m20':['m16','m20'],
  144. 'm16n16':['m16','n16'],
  145. 'm20o20':['m20','o20'],
  146. 'm20202':['m20','202'],
  147. 'n5n11':['n5','n11'],
  148. 'n5410':['n5','410'],
  149. 'n11p11':['n11','p11'],
  150. 'n11303':['n11','303'],
  151. 'n16n11':['n16','n11'],
  152. 'n16o16':['n16','o16'],
  153. 'o14p11':['o14','o11','p11'],
  154. 'o14409':['o14','409a'],
  155. 'o16o14':['o16','o14'],
  156. 'o16o18':['o16','o18'],
  157. 'o18200':['o18','200a'],
  158. 'o18300':['o18','oo18','300'],
  159. 'o20o18':['o20','o18'],
  160. 'o20204':['o20','204'],
  161. 'p3p11':['p3','p11'],
  162. 'p3409':['p3','409'],
  163. 'p11o20':['p11','p20','o20'],
  164. 'p11201':['p11','q11','201']
  165. };
  166. var ends = {
  167. '200': {col:'a', row:'3', width:190},
  168. '200a': {col:'mm', row:'18', width:116},
  169. '201': {col:'q', row:'12', width:154},
  170. '202': {col:'m', row:'21', width:116},
  171. '204': {col:'o', row:'21', width:152},
  172. '300': {col:'oo', row:'19', width:152},
  173. '301': {col:'k', row:'4', width:154},
  174. '303': {col:'m', row:'11', width:116},
  175. '304': {col:'l', row:'18', width:116},
  176. '307': {col:'l', row:'4', width:154},
  177. '400': {col:'a', row:'9', width:190},
  178. '401': {col:'a', row:'8', width:190},
  179. '403': {col:'a', row:'7', width:190},
  180. '404': {col:'m', row:'8', width:116},
  181. '405': {col:'a', row:'10', width:190},
  182. '406': {col:'c', row:'7', width:152},
  183. '409': {col:'p', row:'2', width:116},
  184. '409a': {col:'oo', row:'14', width:116},
  185. '410': {col:'n', row:'4', width:116},
  186. '412': {col:'h', row:'6', width:152},
  187. '412a': {col:'h', row:'18', width:152},
  188. '413': {col:'a', row:'4', width:190},
  189. '414': {col:'a', row:'11', width:190},
  190. '415': {col:'a', row:'5', width:190},
  191. '501a': {col:'a', row:'6', width:190},
  192. '501': {col:'a', row:'12', width:190},
  193. '503': {col:'a', row:'13', width:190}
  194. };
  195. var canvas;
  196. function decorateTrace() {
  197. trace[0].x = cols[trace[0].d[0]];
  198. trace[0].y = rows[trace[0].d.slice(1)];
  199. trace[0].previewCalls = previewCalls(trace[0]);
  200. for (var i = 1; i < trace.length; i++) {
  201. trace[i].x = cols[trace[i].d[0]];
  202. trace[i].y = rows[trace[i].d.slice(1)];
  203. trace[i].previewCalls = previewCalls(trace[i]);
  204. var path = edges[trace[i-1].d+trace[i].d];
  205. if (path) {
  206. trace[i].path = [path.length-1];
  207. for (var p = 1; p < path.length; p++) {
  208. trace[i].path[p-1] = getSeg(path[p-1], path[p], p == path.length-1);
  209. }
  210. } else {
  211. trace[i].path = [];
  212. }
  213. }
  214. var path = edges[trace[i-1].d+response.code];
  215. if (path) {
  216. var end = ends[path[path.length-1]];
  217. response.x = cols[end.col];
  218. response.y = rows[end.row];
  219. response.width = end.width;
  220. response.type = 'normal';
  221. response.path = [path.length-1];
  222. for (var p = 1; p < path.length; p++) {
  223. response.path[p-1] = getSeg(path[p-1], path[p], p == path.length-1);
  224. }
  225. } else {
  226. var ld = trace[trace.length-1];
  227. response.x = ld.x+50;
  228. response.y = ld.y-50;
  229. response.width = 38;
  230. response.type = 'other';
  231. response.path = [
  232. {x1: ld.x+10, y1: ld.y-10,
  233. x2: ld.x+36, y2: ld.y-36}
  234. ];
  235. }
  236. };
  237. function previewCalls(dec) {
  238. var prev = '';
  239. for (var i = 0; i < dec.calls.length; i++) {
  240. if (dec.calls[i].output != "wmtrace_not_exported")
  241. prev += '<li>'+dec.calls[i].module+':'+dec.calls[i]['function']+'</li>';
  242. }
  243. return prev;
  244. };
  245. function drawTrace() {
  246. drawDecision(trace[0]);
  247. for (var i = 1; i < trace.length; i++) {
  248. drawPath(trace[i].path);
  249. drawDecision(trace[i]);
  250. }
  251. drawPath(response.path);
  252. drawResponse();
  253. };
  254. function drawResponse() {
  255. if (response.type == 'normal') {
  256. var context = canvas.getContext('2d');
  257. context.strokeStyle=HIGHLIGHT;
  258. context.lineWidth=4;
  259. context.beginPath();
  260. context.rect(response.x-(response.width/2),
  261. response.y-19,
  262. response.width,
  263. 38);
  264. context.stroke();
  265. } else {
  266. var context = canvas.getContext('2d');
  267. context.strokeStyle='#ff0000';
  268. context.lineWidth=4;
  269. context.beginPath();
  270. context.arc(response.x, response.y, 19,
  271. 0, 2*3.14159, false);
  272. context.stroke();
  273. }
  274. };
  275. function drawDecision(dec) {
  276. var context = canvas.getContext('2d');
  277. if (dec.previewCalls == '')
  278. context.strokeStyle=REGULAR;
  279. else
  280. context.strokeStyle=HIGHLIGHT;
  281. context.lineWidth=4;
  282. context.beginPath();
  283. context.moveTo(dec.x, dec.y-19);
  284. context.lineTo(dec.x+19, dec.y);
  285. context.lineTo(dec.x, dec.y+19);
  286. context.lineTo(dec.x-19, dec.y);
  287. context.closePath();
  288. context.stroke();
  289. };
  290. function drawPath(path) {
  291. var context = canvas.getContext('2d');
  292. context.strokeStyle=REGULAR;
  293. context.lineWidth=4;
  294. context.beginPath();
  295. context.moveTo(path[0].x1, path[0].y1);
  296. for (var p = 0; p < path.length; p++) {
  297. context.lineTo(path[p].x2, path[p].y2);
  298. }
  299. context.stroke();
  300. };
  301. function getSeg(p1, p2, last) {
  302. var seg = {
  303. x1:cols[p1[0]],
  304. y1:rows[p1.slice(1)]
  305. };
  306. if (ends[p2]) {
  307. seg.x2 = cols[ends[p2].col];
  308. seg.y2 = rows[ends[p2].row];
  309. } else {
  310. seg.x2 = cols[p2[0]];
  311. seg.y2 = rows[p2.slice(1)];
  312. }
  313. if (seg.x1 == seg.x2) {
  314. if (seg.y1 < seg.y2) {
  315. seg.y1 = seg.y1+19;
  316. if (last) seg.y2 = seg.y2-19;
  317. } else {
  318. seg.y1 = seg.y1-19;
  319. if (last) seg.y2 = seg.y2+19;
  320. }
  321. } else {
  322. //assume seg.y1 == seg.y2
  323. if (seg.x1 < seg.x2) {
  324. seg.x1 = seg.x1+19;
  325. if (last) seg.x2 = seg.x2-(ends[p2] ? (ends[p2].width/2) : 19);
  326. } else {
  327. seg.x1 = seg.x1-19;
  328. if (last) seg.x2 = seg.x2+(ends[p2] ? (ends[p2].width/2) : 19);
  329. }
  330. }
  331. return seg;
  332. };
  333. function traceDecision(name) {
  334. for (var i = trace.length-1; i >= 0; i--)
  335. if (trace[i].d == name) return trace[i];
  336. };
  337. var detailPanels = {};
  338. function initDetailPanels() {
  339. var windowWidth = document.getElementById('sizetest').clientWidth;
  340. var infoPanel = document.getElementById('infopanel');
  341. var panelWidth = windowWidth-infoPanel.offsetLeft;
  342. var panels = {
  343. 'request': document.getElementById('requestdetail'),
  344. 'response': document.getElementById('responsedetail'),
  345. 'decision': document.getElementById('decisiondetail')
  346. };
  347. var tabs = {
  348. 'request': document.getElementById('requesttab'),
  349. 'response': document.getElementById('responsetab'),
  350. 'decision': document.getElementById('decisiontab')
  351. };
  352. var decisionId = document.getElementById('decisionid');
  353. var decisionCalls = document.getElementById('decisioncalls');
  354. var callInput = document.getElementById('callinput');
  355. var callOutput = document.getElementById('calloutput');
  356. var lastUsedPanelWidth = windowWidth-infoPanel.offsetLeft;
  357. var setPanelWidth = function(width) {
  358. infoPanel.style.left = (windowWidth-width)+'px';
  359. canvas.style.marginRight = (width+20)+'px';
  360. panelWidth = width;
  361. };
  362. setPanelWidth(panelWidth);
  363. var ensureVisible = function() {
  364. if (windowWidth-infoPanel.offsetLeft < 10)
  365. setPanelWidth(lastUsedPanelWidth);
  366. };
  367. var decChoices = '';
  368. for (var i = 0; i < trace.length; i++) {
  369. decChoices += '<option value="'+trace[i].d+'">'+trace[i].d+'</option>';
  370. }
  371. decisionId.innerHTML = decChoices;
  372. decisionId.selectedIndex = -1;
  373. decisionId.onchange = function() {
  374. detailPanels.setDecision(traceDecision(decisionId.value));
  375. }
  376. detailPanels.setDecision = function(dec) {
  377. decisionId.value = dec.d;
  378. var calls = [];
  379. for (var i = 0; i < dec.calls.length; i++) {
  380. calls.push('<option value="'+dec.d+'-'+i+'">');
  381. calls.push(dec.calls[i].module+':'+dec.calls[i]['function']);
  382. calls.push('</option>');
  383. }
  384. decisionCalls.innerHTML = calls.join('');
  385. decisionCalls.selectedIndex = 0;
  386. decisionCalls.onchange();
  387. };
  388. detailPanels.show = function(name) {
  389. for (p in panels) {
  390. if (p == name) {
  391. panels[p].style.display = 'block';
  392. tabs[p].className = 'selectedtab';
  393. }
  394. else {
  395. panels[p].style.display = 'none';
  396. tabs[p].className = '';
  397. }
  398. }
  399. ensureVisible();
  400. };
  401. detailPanels.hide = function() {
  402. setPanelWidth(0);
  403. }
  404. decisionCalls.onchange = function() {
  405. var val = decisionCalls.value;
  406. if (val) {
  407. var dec = traceDecision(val.substring(0, val.indexOf('-')));
  408. var call = dec.calls[parseInt(val.substring(val.indexOf('-')+1, val.length))];
  409. if (call.output != "wmtrace_not_exported") {
  410. callInput.style.color='#000000';
  411. callInput.innerHTML = call.input;
  412. if (call.output != null) {
  413. callOutput.style.color = '#000000';
  414. callOutput.innerHTML = call.output;
  415. } else {
  416. callOutput.style.color = '#ff0000';
  417. callOutput.textContent = 'Error: '+call.module+':'+call['function']+' never returned';
  418. }
  419. } else {
  420. callInput.style.color='#999999';
  421. callInput.textContent = call.module+':'+call['function']+' was not exported';
  422. callOutput.textContent = '';
  423. }
  424. } else {
  425. callInput.textContent = '';
  426. callOutput.textContent = '';
  427. }
  428. };
  429. var headersList = function(headers) {
  430. var h = '';
  431. for (n in headers) h += '<li>'+n+': '+headers[n];
  432. return h;
  433. };
  434. document.getElementById('requestmethod').innerHTML = request.method;
  435. document.getElementById('requestpath').innerHTML = request.path;
  436. document.getElementById('requestheaders').innerHTML = headersList(request.headers);
  437. document.getElementById('requestbody').innerHTML = request.body;
  438. document.getElementById('responsecode').innerHTML = response.code;
  439. document.getElementById('responseheaders').innerHTML = headersList(response.headers);
  440. document.getElementById('responsebody').innerHTML = response.body;
  441. var infoControls = document.getElementById('infocontrols');
  442. var md = false;
  443. var dragged = false;
  444. var msoff = 0;
  445. infoControls.onmousedown = function(ev) {
  446. md = true;
  447. dragged = false;
  448. msoff = ev.clientX-infoPanel.offsetLeft;
  449. };
  450. infoControls.onclick = function(ev) {
  451. if (dragged) {
  452. lastUsedPanelWidth = panelWidth;
  453. }
  454. else if (panelWidth < 10) {
  455. switch(ev.target.id) {
  456. case 'requesttab': detailPanels.show('request'); break;
  457. case 'responsetab': detailPanels.show('response'); break;
  458. case 'decisiontab': detailPanels.show('decision'); break;
  459. default: ensureVisible();
  460. }
  461. } else {
  462. var name = 'none';
  463. switch(ev.target.id) {
  464. case 'requesttab': name = 'request'; break;
  465. case 'responsetab': name = 'response'; break;
  466. case 'decisiontab': name = 'decision'; break;
  467. }
  468. if (panels[name] && panels[name].style.display != 'block')
  469. detailPanels.show(name);
  470. else
  471. detailPanels.hide();
  472. }
  473. return false;
  474. };
  475. document.onmousemove = function(ev) {
  476. if (md) {
  477. dragged = true;
  478. panelWidth = windowWidth-(ev.clientX-msoff);
  479. if (panelWidth < 0) {
  480. panelWidth = 0;
  481. infoPanel.style.left = windowWidth+"px";
  482. }
  483. else if (panelWidth > windowWidth-21) {
  484. panelWidth = windowWidth-21;
  485. infoPanel.style.left = '21px';
  486. }
  487. else
  488. infoPanel.style.left = (ev.clientX-msoff)+"px";
  489. canvas.style.marginRight = panelWidth+20+"px";
  490. return false;
  491. }
  492. };
  493. document.onmouseup = function() { md = false; };
  494. window.onresize = function() {
  495. windowWidth = document.getElementById('sizetest').clientWidth;
  496. infoPanel.style.left = windowWidth-panelWidth+'px';
  497. };
  498. };
  499. window.onload = function() {
  500. canvas = document.getElementById('v3map');
  501. initDetailPanels();
  502. var scale = 0.25;
  503. var coy = canvas.offsetTop;
  504. function findDecision(ev) {
  505. var x = (ev.clientX+window.pageXOffset)/scale;
  506. var y = (ev.clientY+window.pageYOffset-coy)/scale;
  507. for (var i = trace.length-1; i >= 0; i--) {
  508. if (x >= trace[i].x-19 && x <= trace[i].x+19 &&
  509. y >= trace[i].y-19 && y <= trace[i].y+19)
  510. return trace[i];
  511. }
  512. };
  513. var preview = document.getElementById('preview');
  514. var previewId = document.getElementById('previewid');
  515. var previewCalls = document.getElementById('previewcalls');
  516. function previewDecision(dec) {
  517. preview.style.left = (dec.x*scale)+'px';
  518. preview.style.top = (dec.y*scale+coy+15)+'px';
  519. preview.style.display = 'block';
  520. previewId.textContent = dec.d;
  521. previewCalls.innerHTML = dec.previewCalls;
  522. };
  523. function overResponse(ev) {
  524. var x = (ev.clientX+window.pageXOffset)/scale;
  525. var y = (ev.clientY+window.pageYOffset-coy)/scale;
  526. return (x >= response.x-(response.width/2)
  527. && x <= response.x+(response.width/2)
  528. && y >= response.y-19 && y <= response.y+19);
  529. };
  530. decorateTrace();
  531. var bg = new Image(3138, 2184);
  532. function drawMap() {
  533. var ctx = canvas.getContext("2d");
  534. ctx.save();
  535. ctx.scale(1/scale, 1/scale);
  536. ctx.fillStyle = '#ffffff';
  537. ctx.fillRect(0, 0, 3138, 2184);
  538. ctx.restore();
  539. ctx.drawImage(bg, 0, 0);
  540. drawTrace();
  541. };
  542. bg.onload = function() {
  543. canvas.getContext("2d").scale(scale, scale);
  544. drawMap(scale);
  545. canvas.onmousemove = function(ev) {
  546. if (findDecision(ev)) {
  547. canvas.style.cursor = 'pointer';
  548. previewDecision(findDecision(ev));
  549. }
  550. else {
  551. preview.style.display = 'none';
  552. if (overResponse(ev))
  553. canvas.style.cursor = 'pointer';
  554. else
  555. canvas.style.cursor = 'default';
  556. }
  557. };
  558. canvas.onclick = function(ev) {
  559. var dec = findDecision(ev);
  560. if (dec) {
  561. detailPanels.setDecision(dec);
  562. detailPanels.show('decision');
  563. } else if (overResponse(ev)) {
  564. detailPanels.show('response');
  565. }
  566. };
  567. document.getElementById('zoomin').onclick = function() {
  568. scale = scale*2;
  569. canvas.getContext("2d").scale(2, 2);
  570. drawMap();
  571. };
  572. document.getElementById('zoomout').onclick = function() {
  573. scale = scale/2;
  574. canvas.getContext("2d").scale(0.5, 0.5);
  575. drawMap();
  576. };
  577. };
  578. bg.onerror = function() {
  579. alert('Failed to load background image.');
  580. };
  581. bg.src = 'static/map.png';
  582. };