PageRenderTime 65ms CodeModel.GetById 18ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

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