Commit b8f070f0d17f20240376e48aa8dcad23c1d23ece

Authored by Sato Hiroyuki
1 parent a29c883b

Rename to coffee.

app/assets/javascripts/branch-graph.js
@@ -1,398 +0,0 @@ @@ -1,398 +0,0 @@
1 -!function(){  
2 -  
3 - var BranchGraph = function(element, options){  
4 - this.element = element;  
5 - this.options = options;  
6 -  
7 - this.preparedCommits = {};  
8 - this.mtime = 0;  
9 - this.mspace = 0;  
10 - this.parents = {};  
11 - this.colors = ["#000"];  
12 -  
13 - this.load();  
14 - };  
15 -  
16 - BranchGraph.prototype.load = function(){  
17 - $.ajax({  
18 - url: this.options.url,  
19 - method: 'get',  
20 - dataType: 'json',  
21 - success: $.proxy(function(data){  
22 - $('.loading', this.element).hide();  
23 - this.prepareData(data.days, data.commits);  
24 - this.buildGraph();  
25 - }, this)  
26 - });  
27 - };  
28 -  
29 - BranchGraph.prototype.prepareData = function(days, commits){  
30 - this.days = days;  
31 - this.dayCount = days.length;  
32 - this.commits = commits;  
33 - this.commitCount = commits.length;  
34 -  
35 - this.collectParents();  
36 -  
37 - this.mtime += 4;  
38 - this.mspace += 10;  
39 - for (var i = 0; i < this.commitCount; i++) {  
40 - if (this.commits[i].id in this.parents) {  
41 - this.commits[i].isParent = true;  
42 - }  
43 - this.preparedCommits[this.commits[i].id] = this.commits[i];  
44 - }  
45 - this.collectColors();  
46 - };  
47 -  
48 - BranchGraph.prototype.collectParents = function(){  
49 - for (var i = 0; i < this.commitCount; i++) {  
50 - for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {  
51 - this.parents[this.commits[i].parents[j][0]] = true;  
52 - }  
53 - this.mtime = Math.max(this.mtime, this.commits[i].time);  
54 - this.mspace = Math.max(this.mspace, this.commits[i].space);  
55 - }  
56 - };  
57 -  
58 - BranchGraph.prototype.collectColors = function(){  
59 - for (var k = 0; k < this.mspace; k++) {  
60 - this.colors.push(Raphael.getColor(.8));  
61 - // Skipping a few colors in the spectrum to get more contrast between colors  
62 - Raphael.getColor();Raphael.getColor();  
63 - }  
64 - };  
65 -  
66 - BranchGraph.prototype.buildGraph = function(){  
67 - var graphWidth = $(this.element).width()  
68 - , ch = this.mspace * 20 + 100  
69 - , cw = Math.max(graphWidth, this.mtime * 20 + 260)  
70 - , r = Raphael(this.element.get(0), cw, ch)  
71 - , top = r.set()  
72 - , cuday = 0  
73 - , cumonth = ""  
74 - , offsetX = 20  
75 - , offsetY = 60  
76 - , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320)  
77 - , scrollLeft = cw;  
78 -  
79 - this.raphael = r;  
80 -  
81 - r.rect(0, 0, barWidth, 20).attr({fill: "#222"});  
82 - r.rect(0, 20, barWidth, 20).attr({fill: "#444"});  
83 -  
84 - for (mm = 0; mm < this.dayCount; mm++) {  
85 - if(this.days[mm] != null){  
86 - if(cuday != this.days[mm][0]){  
87 - // Dates  
88 - r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({  
89 - font: "12px Monaco, monospace",  
90 - fill: "#DDD"  
91 - });  
92 - cuday = this.days[mm][0];  
93 - }  
94 - if(cumonth != this.days[mm][1]){  
95 - // Months  
96 - r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({  
97 - font: "12px Monaco, monospace",  
98 - fill: "#EEE"  
99 - });  
100 - cumonth = this.days[mm][1];  
101 - }  
102 - }  
103 - }  
104 -  
105 - for (i = 0; i < this.commitCount; i++) {  
106 - var x = offsetX + 20 * this.commits[i].time  
107 - , y = offsetY + 10 * this.commits[i].space  
108 - , c  
109 - , ps;  
110 -  
111 - // Draw dot  
112 - r.circle(x, y, 3).attr({  
113 - fill: this.colors[this.commits[i].space],  
114 - stroke: "none"  
115 - });  
116 -  
117 - // Draw lines  
118 - for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {  
119 - c = this.preparedCommits[this.commits[i].parents[j][0]];  
120 - ps = this.commits[i].parents[j][1];  
121 - var cx = offsetX + 20 * c.time  
122 - , cy = offsetY + 10 * c.space  
123 - , psy = offsetY + 10 * ps;  
124 - if (c.space == this.commits[i].space && c.space == ps) {  
125 - r.path([  
126 - "M", x, y,  
127 - "L", cx, cy  
128 - ]).attr({  
129 - stroke: this.colors[c.space],  
130 - "stroke-width": 2  
131 - });  
132 -  
133 - } else if (c.space < this.commits[i].space) {  
134 - if (y == psy) {  
135 - r.path([  
136 - "M", x - 5, y,  
137 - "l-5,-2,0,4,5,-2",  
138 - "L", x - 10, y,  
139 - "L", x - 15, psy,  
140 - "L", cx + 5, psy,  
141 - "L", cx, cy])  
142 - .attr({  
143 - stroke: this.colors[this.commits[i].space],  
144 - "stroke-width": 2  
145 - });  
146 - } else {  
147 - r.path([  
148 - "M", x - 3, y - 6,  
149 - "l-4,-3,4,-2,0,5",  
150 - "L", x - 5, y - 10,  
151 - "L", x - 10, psy,  
152 - "L", cx + 5, psy,  
153 - "L", cx, cy])  
154 - .attr({  
155 - stroke: this.colors[this.commits[i].space],  
156 - "stroke-width": 2  
157 - });  
158 - }  
159 - } else {  
160 - r.path([  
161 - "M", x - 3, y + 6,  
162 - "l-4,3,4,2,0,-5",  
163 - "L", x - 5, y + 10,  
164 - "L", x - 10, psy,  
165 - "L", cx + 5, psy,  
166 - "L", cx, cy])  
167 - .attr({  
168 - stroke: this.colors[c.space],  
169 - "stroke-width": 2  
170 - });  
171 - }  
172 - }  
173 -  
174 - if (this.commits[i].refs) {  
175 - this.appendLabel(x, y, this.commits[i].refs);  
176 - }  
177 -  
178 - // mark commit and displayed in the center  
179 - if (this.commits[i].id == this.options.commit_id) {  
180 - r.path([  
181 - 'M', x, y - 5,  
182 - 'L', x + 4, y - 15,  
183 - 'L', x - 4, y - 15,  
184 - 'Z'  
185 - ]).attr({  
186 - "fill": "#000",  
187 - "fill-opacity": .7,  
188 - "stroke": "none"  
189 - });  
190 - scrollLeft = x - graphWidth / 2;  
191 - }  
192 -  
193 - this.appendAnchor(top, this.commits[i], x, y);  
194 - }  
195 - top.toFront();  
196 - this.element.scrollLeft(scrollLeft);  
197 - this.bindEvents();  
198 - };  
199 -  
200 - BranchGraph.prototype.bindEvents = function(){  
201 - var drag = {}  
202 - , element = this.element;  
203 -  
204 - var dragger = function(event){  
205 - element.scrollLeft(drag.sl - (event.clientX - drag.x));  
206 - element.scrollTop(drag.st - (event.clientY - drag.y));  
207 - };  
208 -  
209 - element.on({  
210 - mousedown: function (event) {  
211 - drag = {  
212 - x: event.clientX,  
213 - y: event.clientY,  
214 - st: element.scrollTop(),  
215 - sl: element.scrollLeft()  
216 - };  
217 - $(window).on('mousemove', dragger);  
218 - }  
219 - });  
220 - $(window).on({  
221 - mouseup: function(){  
222 - //bars.animate({opacity: 0}, 300);  
223 - $(window).off('mousemove', dragger);  
224 - },  
225 - keydown: function(event){  
226 - if(event.keyCode == 37){  
227 - // left  
228 - element.scrollLeft( element.scrollLeft() - 50);  
229 - }  
230 - if(event.keyCode == 38){  
231 - // top  
232 - element.scrollTop( element.scrollTop() - 50);  
233 - }  
234 - if(event.keyCode == 39){  
235 - // right  
236 - element.scrollLeft( element.scrollLeft() + 50);  
237 - }  
238 - if(event.keyCode == 40){  
239 - // bottom  
240 - element.scrollTop( element.scrollTop() + 50);  
241 - }  
242 - }  
243 - });  
244 - };  
245 -  
246 - BranchGraph.prototype.appendLabel = function(x, y, refs){  
247 - var r = this.raphael  
248 - , shortrefs = refs  
249 - , text, textbox, rect;  
250 -  
251 - if (shortrefs.length > 17){  
252 - // Truncate if longer than 15 chars  
253 - shortrefs = shortrefs.substr(0,15) + "…";  
254 - }  
255 -  
256 - text = r.text(x+5, y+8 + 10, shortrefs).attr({  
257 - font: "10px Monaco, monospace",  
258 - fill: "#FFF",  
259 - title: refs  
260 - });  
261 -  
262 - textbox = text.getBBox();  
263 - text.transform([  
264 - 't', textbox.height/-4, textbox.width/2 + 5,  
265 - 'r90'  
266 - ]);  
267 -  
268 - // Create rectangle based on the size of the textbox  
269 - rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr({  
270 - "fill": "#000",  
271 - "fill-opacity": .7,  
272 - "stroke": "none"  
273 - });  
274 -  
275 - triangle = r.path([  
276 - 'M', x, y + 5,  
277 - 'L', x + 4, y + 15,  
278 - 'L', x - 4, y + 15,  
279 - 'Z'  
280 - ]).attr({  
281 - "fill": "#000",  
282 - "fill-opacity": .7,  
283 - "stroke": "none"  
284 - });  
285 -  
286 - // Rotate and reposition rectangle over text  
287 - rect.transform([  
288 - 'r', 90, x, y,  
289 - 't', 15, -9  
290 - ]);  
291 -  
292 - // Set text to front  
293 - text.toFront();  
294 - };  
295 -  
296 - BranchGraph.prototype.appendAnchor = function(top, commit, x, y) {  
297 - var r = this.raphael  
298 - , options = this.options  
299 - , anchor;  
300 - anchor = r.circle(x, y, 10).attr({  
301 - fill: "#000",  
302 - opacity: 0,  
303 - cursor: "pointer"  
304 - })  
305 - .click(function(){  
306 - window.open(options.commit_url.replace('%s', commit.id), '_blank');  
307 - })  
308 - .hover(function(){  
309 - this.tooltip = r.commitTooltip(x, y + 5, commit);  
310 - top.push(this.tooltip.insertBefore(this));  
311 - }, function(){  
312 - this.tooltip && this.tooltip.remove() && delete this.tooltip;  
313 - });  
314 - top.push(anchor);  
315 - };  
316 -  
317 - this.BranchGraph = BranchGraph;  
318 -  
319 -}(this);  
320 -Raphael.fn.commitTooltip = function(x, y, commit){  
321 - var icon, nameText, idText, messageText  
322 - , boxWidth = 300  
323 - , boxHeight = 200;  
324 -  
325 - icon = this.image(commit.author.icon, x, y, 20, 20);  
326 - nameText = this.text(x + 25, y + 10, commit.author.name);  
327 - idText = this.text(x, y + 35, commit.id);  
328 - messageText = this.text(x, y + 50, commit.message);  
329 -  
330 - textSet = this.set(icon, nameText, idText, messageText).attr({  
331 - "text-anchor": "start",  
332 - "font": "12px Monaco, monospace"  
333 - });  
334 -  
335 - nameText.attr({  
336 - "font": "14px Arial",  
337 - "font-weight": "bold"  
338 - });  
339 -  
340 - idText.attr({  
341 - "fill": "#AAA"  
342 - });  
343 -  
344 - textWrap(messageText, boxWidth - 50);  
345 -  
346 - var rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({  
347 - "fill": "#FFF",  
348 - "stroke": "#000",  
349 - "stroke-linecap": "round",  
350 - "stroke-width": 2  
351 - });  
352 - var tooltip = this.set(rect, textSet);  
353 -  
354 - rect.attr({  
355 - "height" : tooltip.getBBox().height + 10,  
356 - "width" : tooltip.getBBox().width + 10  
357 - });  
358 -  
359 - tooltip.transform([  
360 - 't', 20, 20  
361 - ]);  
362 -  
363 - return tooltip;  
364 -};  
365 -  
366 -function textWrap(t, width) {  
367 - var content = t.attr("text");  
368 - var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";  
369 - t.attr({  
370 - "text" : abc  
371 - });  
372 - var letterWidth = t.getBBox().width / abc.length;  
373 -  
374 - t.attr({  
375 - "text" : content  
376 - });  
377 -  
378 - var words = content.split(" ");  
379 - var x = 0, s = [];  
380 - for ( var i = 0; i < words.length; i++) {  
381 -  
382 - var l = words[i].length;  
383 - if (x + (l * letterWidth) > width) {  
384 - s.push("\n");  
385 - x = 0;  
386 - }  
387 - x += l * letterWidth;  
388 - s.push(words[i] + " ");  
389 - }  
390 - t.attr({  
391 - "text" : s.join("")  
392 - });  
393 - var b = t.getBBox()  
394 - , h = Math.abs(b.y2) - Math.abs(b.y) + 1;  
395 - t.attr({  
396 - "y": b.y + h  
397 - });  
398 -}  
app/assets/javascripts/branch-graph.js.coffee 0 → 100644
@@ -0,0 +1,398 @@ @@ -0,0 +1,398 @@
  1 +!function(){
  2 +
  3 + var BranchGraph = function(element, options){
  4 + this.element = element;
  5 + this.options = options;
  6 +
  7 + this.preparedCommits = {};
  8 + this.mtime = 0;
  9 + this.mspace = 0;
  10 + this.parents = {};
  11 + this.colors = ["#000"];
  12 +
  13 + this.load();
  14 + };
  15 +
  16 + BranchGraph.prototype.load = function(){
  17 + $.ajax({
  18 + url: this.options.url,
  19 + method: 'get',
  20 + dataType: 'json',
  21 + success: $.proxy(function(data){
  22 + $('.loading', this.element).hide();
  23 + this.prepareData(data.days, data.commits);
  24 + this.buildGraph();
  25 + }, this)
  26 + });
  27 + };
  28 +
  29 + BranchGraph.prototype.prepareData = function(days, commits){
  30 + this.days = days;
  31 + this.dayCount = days.length;
  32 + this.commits = commits;
  33 + this.commitCount = commits.length;
  34 +
  35 + this.collectParents();
  36 +
  37 + this.mtime += 4;
  38 + this.mspace += 10;
  39 + for (var i = 0; i < this.commitCount; i++) {
  40 + if (this.commits[i].id in this.parents) {
  41 + this.commits[i].isParent = true;
  42 + }
  43 + this.preparedCommits[this.commits[i].id] = this.commits[i];
  44 + }
  45 + this.collectColors();
  46 + };
  47 +
  48 + BranchGraph.prototype.collectParents = function(){
  49 + for (var i = 0; i < this.commitCount; i++) {
  50 + for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
  51 + this.parents[this.commits[i].parents[j][0]] = true;
  52 + }
  53 + this.mtime = Math.max(this.mtime, this.commits[i].time);
  54 + this.mspace = Math.max(this.mspace, this.commits[i].space);
  55 + }
  56 + };
  57 +
  58 + BranchGraph.prototype.collectColors = function(){
  59 + for (var k = 0; k < this.mspace; k++) {
  60 + this.colors.push(Raphael.getColor(.8));
  61 + // Skipping a few colors in the spectrum to get more contrast between colors
  62 + Raphael.getColor();Raphael.getColor();
  63 + }
  64 + };
  65 +
  66 + BranchGraph.prototype.buildGraph = function(){
  67 + var graphWidth = $(this.element).width()
  68 + , ch = this.mspace * 20 + 100
  69 + , cw = Math.max(graphWidth, this.mtime * 20 + 260)
  70 + , r = Raphael(this.element.get(0), cw, ch)
  71 + , top = r.set()
  72 + , cuday = 0
  73 + , cumonth = ""
  74 + , offsetX = 20
  75 + , offsetY = 60
  76 + , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320)
  77 + , scrollLeft = cw;
  78 +
  79 + this.raphael = r;
  80 +
  81 + r.rect(0, 0, barWidth, 20).attr({fill: "#222"});
  82 + r.rect(0, 20, barWidth, 20).attr({fill: "#444"});
  83 +
  84 + for (mm = 0; mm < this.dayCount; mm++) {
  85 + if(this.days[mm] != null){
  86 + if(cuday != this.days[mm][0]){
  87 + // Dates
  88 + r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({
  89 + font: "12px Monaco, monospace",
  90 + fill: "#DDD"
  91 + });
  92 + cuday = this.days[mm][0];
  93 + }
  94 + if(cumonth != this.days[mm][1]){
  95 + // Months
  96 + r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({
  97 + font: "12px Monaco, monospace",
  98 + fill: "#EEE"
  99 + });
  100 + cumonth = this.days[mm][1];
  101 + }
  102 + }
  103 + }
  104 +
  105 + for (i = 0; i < this.commitCount; i++) {
  106 + var x = offsetX + 20 * this.commits[i].time
  107 + , y = offsetY + 10 * this.commits[i].space
  108 + , c
  109 + , ps;
  110 +
  111 + // Draw dot
  112 + r.circle(x, y, 3).attr({
  113 + fill: this.colors[this.commits[i].space],
  114 + stroke: "none"
  115 + });
  116 +
  117 + // Draw lines
  118 + for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
  119 + c = this.preparedCommits[this.commits[i].parents[j][0]];
  120 + ps = this.commits[i].parents[j][1];
  121 + var cx = offsetX + 20 * c.time
  122 + , cy = offsetY + 10 * c.space
  123 + , psy = offsetY + 10 * ps;
  124 + if (c.space == this.commits[i].space && c.space == ps) {
  125 + r.path([
  126 + "M", x, y,
  127 + "L", cx, cy
  128 + ]).attr({
  129 + stroke: this.colors[c.space],
  130 + "stroke-width": 2
  131 + });
  132 +
  133 + } else if (c.space < this.commits[i].space) {
  134 + if (y == psy) {
  135 + r.path([
  136 + "M", x - 5, y,
  137 + "l-5,-2,0,4,5,-2",
  138 + "L", x - 10, y,
  139 + "L", x - 15, psy,
  140 + "L", cx + 5, psy,
  141 + "L", cx, cy])
  142 + .attr({
  143 + stroke: this.colors[this.commits[i].space],
  144 + "stroke-width": 2
  145 + });
  146 + } else {
  147 + r.path([
  148 + "M", x - 3, y - 6,
  149 + "l-4,-3,4,-2,0,5",
  150 + "L", x - 5, y - 10,
  151 + "L", x - 10, psy,
  152 + "L", cx + 5, psy,
  153 + "L", cx, cy])
  154 + .attr({
  155 + stroke: this.colors[this.commits[i].space],
  156 + "stroke-width": 2
  157 + });
  158 + }
  159 + } else {
  160 + r.path([
  161 + "M", x - 3, y + 6,
  162 + "l-4,3,4,2,0,-5",
  163 + "L", x - 5, y + 10,
  164 + "L", x - 10, psy,
  165 + "L", cx + 5, psy,
  166 + "L", cx, cy])
  167 + .attr({
  168 + stroke: this.colors[c.space],
  169 + "stroke-width": 2
  170 + });
  171 + }
  172 + }
  173 +
  174 + if (this.commits[i].refs) {
  175 + this.appendLabel(x, y, this.commits[i].refs);
  176 + }
  177 +
  178 + // mark commit and displayed in the center
  179 + if (this.commits[i].id == this.options.commit_id) {
  180 + r.path([
  181 + 'M', x, y - 5,
  182 + 'L', x + 4, y - 15,
  183 + 'L', x - 4, y - 15,
  184 + 'Z'
  185 + ]).attr({
  186 + "fill": "#000",
  187 + "fill-opacity": .7,
  188 + "stroke": "none"
  189 + });
  190 + scrollLeft = x - graphWidth / 2;
  191 + }
  192 +
  193 + this.appendAnchor(top, this.commits[i], x, y);
  194 + }
  195 + top.toFront();
  196 + this.element.scrollLeft(scrollLeft);
  197 + this.bindEvents();
  198 + };
  199 +
  200 + BranchGraph.prototype.bindEvents = function(){
  201 + var drag = {}
  202 + , element = this.element;
  203 +
  204 + var dragger = function(event){
  205 + element.scrollLeft(drag.sl - (event.clientX - drag.x));
  206 + element.scrollTop(drag.st - (event.clientY - drag.y));
  207 + };
  208 +
  209 + element.on({
  210 + mousedown: function (event) {
  211 + drag = {
  212 + x: event.clientX,
  213 + y: event.clientY,
  214 + st: element.scrollTop(),
  215 + sl: element.scrollLeft()
  216 + };
  217 + $(window).on('mousemove', dragger);
  218 + }
  219 + });
  220 + $(window).on({
  221 + mouseup: function(){
  222 + //bars.animate({opacity: 0}, 300);
  223 + $(window).off('mousemove', dragger);
  224 + },
  225 + keydown: function(event){
  226 + if(event.keyCode == 37){
  227 + // left
  228 + element.scrollLeft( element.scrollLeft() - 50);
  229 + }
  230 + if(event.keyCode == 38){
  231 + // top
  232 + element.scrollTop( element.scrollTop() - 50);
  233 + }
  234 + if(event.keyCode == 39){
  235 + // right
  236 + element.scrollLeft( element.scrollLeft() + 50);
  237 + }
  238 + if(event.keyCode == 40){
  239 + // bottom
  240 + element.scrollTop( element.scrollTop() + 50);
  241 + }
  242 + }
  243 + });
  244 + };
  245 +
  246 + BranchGraph.prototype.appendLabel = function(x, y, refs){
  247 + var r = this.raphael
  248 + , shortrefs = refs
  249 + , text, textbox, rect;
  250 +
  251 + if (shortrefs.length > 17){
  252 + // Truncate if longer than 15 chars
  253 + shortrefs = shortrefs.substr(0,15) + "…";
  254 + }
  255 +
  256 + text = r.text(x+5, y+8 + 10, shortrefs).attr({
  257 + font: "10px Monaco, monospace",
  258 + fill: "#FFF",
  259 + title: refs
  260 + });
  261 +
  262 + textbox = text.getBBox();
  263 + text.transform([
  264 + 't', textbox.height/-4, textbox.width/2 + 5,
  265 + 'r90'
  266 + ]);
  267 +
  268 + // Create rectangle based on the size of the textbox
  269 + rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr({
  270 + "fill": "#000",
  271 + "fill-opacity": .7,
  272 + "stroke": "none"
  273 + });
  274 +
  275 + triangle = r.path([
  276 + 'M', x, y + 5,
  277 + 'L', x + 4, y + 15,
  278 + 'L', x - 4, y + 15,
  279 + 'Z'
  280 + ]).attr({
  281 + "fill": "#000",
  282 + "fill-opacity": .7,
  283 + "stroke": "none"
  284 + });
  285 +
  286 + // Rotate and reposition rectangle over text
  287 + rect.transform([
  288 + 'r', 90, x, y,
  289 + 't', 15, -9
  290 + ]);
  291 +
  292 + // Set text to front
  293 + text.toFront();
  294 + };
  295 +
  296 + BranchGraph.prototype.appendAnchor = function(top, commit, x, y) {
  297 + var r = this.raphael
  298 + , options = this.options
  299 + , anchor;
  300 + anchor = r.circle(x, y, 10).attr({
  301 + fill: "#000",
  302 + opacity: 0,
  303 + cursor: "pointer"
  304 + })
  305 + .click(function(){
  306 + window.open(options.commit_url.replace('%s', commit.id), '_blank');
  307 + })
  308 + .hover(function(){
  309 + this.tooltip = r.commitTooltip(x, y + 5, commit);
  310 + top.push(this.tooltip.insertBefore(this));
  311 + }, function(){
  312 + this.tooltip && this.tooltip.remove() && delete this.tooltip;
  313 + });
  314 + top.push(anchor);
  315 + };
  316 +
  317 + this.BranchGraph = BranchGraph;
  318 +
  319 +}(this);
  320 +Raphael.fn.commitTooltip = function(x, y, commit){
  321 + var icon, nameText, idText, messageText
  322 + , boxWidth = 300
  323 + , boxHeight = 200;
  324 +
  325 + icon = this.image(commit.author.icon, x, y, 20, 20);
  326 + nameText = this.text(x + 25, y + 10, commit.author.name);
  327 + idText = this.text(x, y + 35, commit.id);
  328 + messageText = this.text(x, y + 50, commit.message);
  329 +
  330 + textSet = this.set(icon, nameText, idText, messageText).attr({
  331 + "text-anchor": "start",
  332 + "font": "12px Monaco, monospace"
  333 + });
  334 +
  335 + nameText.attr({
  336 + "font": "14px Arial",
  337 + "font-weight": "bold"
  338 + });
  339 +
  340 + idText.attr({
  341 + "fill": "#AAA"
  342 + });
  343 +
  344 + textWrap(messageText, boxWidth - 50);
  345 +
  346 + var rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({
  347 + "fill": "#FFF",
  348 + "stroke": "#000",
  349 + "stroke-linecap": "round",
  350 + "stroke-width": 2
  351 + });
  352 + var tooltip = this.set(rect, textSet);
  353 +
  354 + rect.attr({
  355 + "height" : tooltip.getBBox().height + 10,
  356 + "width" : tooltip.getBBox().width + 10
  357 + });
  358 +
  359 + tooltip.transform([
  360 + 't', 20, 20
  361 + ]);
  362 +
  363 + return tooltip;
  364 +};
  365 +
  366 +function textWrap(t, width) {
  367 + var content = t.attr("text");
  368 + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  369 + t.attr({
  370 + "text" : abc
  371 + });
  372 + var letterWidth = t.getBBox().width / abc.length;
  373 +
  374 + t.attr({
  375 + "text" : content
  376 + });
  377 +
  378 + var words = content.split(" ");
  379 + var x = 0, s = [];
  380 + for ( var i = 0; i < words.length; i++) {
  381 +
  382 + var l = words[i].length;
  383 + if (x + (l * letterWidth) > width) {
  384 + s.push("\n");
  385 + x = 0;
  386 + }
  387 + x += l * letterWidth;
  388 + s.push(words[i] + " ");
  389 + }
  390 + t.attr({
  391 + "text" : s.join("")
  392 + });
  393 + var b = t.getBBox()
  394 + , h = Math.abs(b.y2) - Math.abs(b.y) + 1;
  395 + t.attr({
  396 + "y": b.y + h
  397 + });
  398 +}