OLD | NEW |
(Empty) | |
| 1 {% extends "announce.html" %} |
| 2 |
| 3 {% block head %} |
| 4 {{ super() }} |
| 5 <script type='text/javascript'> |
| 6 // <![CDATA[ |
| 7 // |
| 8 |
| 9 // |
| 10 // Functions used to display the build status bubble on box click. |
| 11 // |
| 12 |
| 13 // show the build status box. This is called when the user clicks on a block. |
| 14 function showBuildBox(url, event) { |
| 15 // Find the current curson position. |
| 16 var cursorPosTop = (window.event ? window.event.clientY : event.pageY) |
| 17 var cursorPosLeft = (window.event ? window.event.clientX : event.pageX) |
| 18 |
| 19 // Offset the position by 5, to make the window appears under the cursor. |
| 20 cursorPosTop = cursorPosTop + document.body.scrollTop -5 ; |
| 21 cursorPosLeft = cursorPosLeft + document.body.scrollLeft - 5; |
| 22 |
| 23 // Move the div (hidden) under the cursor. |
| 24 var divBox = document.getElementById('divBox'); |
| 25 divBox.style.top = parseInt(cursorPosTop) + 'px'; |
| 26 divBox.style.left = parseInt(cursorPosLeft) + 'px'; |
| 27 |
| 28 // Reload the hidden frame with the build page we want to show. |
| 29 // The onload even on this frame will update the div and make it visible. |
| 30 document.getElementById("frameBox").src = url |
| 31 |
| 32 // We don't want to reload the page. |
| 33 return false; |
| 34 } |
| 35 |
| 36 // OnLoad handler for the iframe containing the build to show. |
| 37 function updateDiv(event) { |
| 38 // Get the frame innerHTML. |
| 39 var iframeContent = document.getElementById("frameBox").contentWindow.docume
nt.body.innerHTML; |
| 40 |
| 41 // If there is any content, update the div, and make it visible. |
| 42 if (iframeContent) { |
| 43 var divBox = document.getElementById('divBox'); |
| 44 divBox.innerHTML = iframeContent ; |
| 45 divBox.style.display = "block"; |
| 46 } |
| 47 } |
| 48 |
| 49 // Util functions to know if an element is contained inside another element. |
| 50 // We use this to know when we mouse out our build status div. |
| 51 function containsDOM (container, containee) { |
| 52 var isParent = false; |
| 53 do { |
| 54 if ((isParent = container == containee)) |
| 55 break; |
| 56 containee = containee.parentNode; |
| 57 } while (containee != null); |
| 58 |
| 59 return isParent; |
| 60 } |
| 61 |
| 62 // OnMouseOut handler. Returns true if the mouse moved out of the element. |
| 63 // It is false if the mouse is still in the element, but in a blank part of it, |
| 64 // like in an empty table cell. |
| 65 function checkMouseLeave(element, event) { |
| 66 if (element.contains && event.toElement) { |
| 67 return !element.contains(event.toElement); |
| 68 } |
| 69 else if (event.relatedTarget) { |
| 70 return !containsDOM(element, event.relatedTarget); |
| 71 } |
| 72 } |
| 73 |
| 74 // Creates a new cookie. |
| 75 function createCookie(name, value, day) { |
| 76 var date = new Date(); |
| 77 date.setTime(date.getTime() + (day * 24 * 60 * 60 * 1000)); |
| 78 var expires = "; expires=" + date.toGMTString(); |
| 79 document.cookie = name + "=" + value+expires + "; path=/"; |
| 80 } |
| 81 |
| 82 // Returns the vaue of a cookie, or null if it does not exist. |
| 83 function readCookie(name) { |
| 84 var begin = name + "="; |
| 85 var data = document.cookie.split(';'); |
| 86 for(var i = 0; i < data.length; i++) { |
| 87 var cookie = data[i]; |
| 88 while (cookie.charAt(0) == ' ') |
| 89 cookie = cookie.substring(1, cookie.length); |
| 90 if (cookie.indexOf(begin) == 0) |
| 91 return cookie.substring(begin.length, cookie.length); |
| 92 } |
| 93 |
| 94 return null; |
| 95 } |
| 96 |
| 97 // Deletes a cookie. |
| 98 function eraseCookie(name) { |
| 99 createCookie(name, "", -1); |
| 100 } |
| 101 |
| 102 // Hides all "details" and "comments" section. |
| 103 function collapse() { |
| 104 // Hide all Comments sections. |
| 105 var comments = document.querySelectorAll('.DevComment'); |
| 106 for(var i = 0; i < comments.length; i++) { |
| 107 comments[i].style.display = "none"; |
| 108 } |
| 109 |
| 110 // Hide all details sections. |
| 111 var details = document.querySelectorAll('.DevDetails'); |
| 112 for(var i = 0; i < details.length; i++) { |
| 113 details[i].style.display = "none"; |
| 114 } |
| 115 |
| 116 // Fix the rounding on the Revision box. (Lower right corner must be round) |
| 117 var revisions = document.querySelectorAll('.DevRev'); |
| 118 for(var i = 0; i < revisions.length; i++) { |
| 119 revisions[i].className = revisions[i].className + ' DevRevCollapse'; |
| 120 } |
| 121 |
| 122 // Fix the rounding on the last category box. (Lower left corner must be rou
nd) |
| 123 var status = document.querySelectorAll('.last'); |
| 124 for(var i = 0; i < status.length; i++) { |
| 125 status[i].className = status[i].className + ' DevStatusCollapse'; |
| 126 } |
| 127 |
| 128 // Create a cookie to remember that we want the view to be collapsed. |
| 129 createCookie('collapsed', 'true', 30) |
| 130 |
| 131 // Hide the collapse and the unmerge buttons. |
| 132 document.querySelectorAll('.collapse')[0].style.display = 'none' |
| 133 document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| 134 |
| 135 // Activate the merge and expand buttons. |
| 136 document.querySelectorAll('.uncollapse')[0].style.display = 'inline' |
| 137 document.querySelectorAll('.merge')[0].style.display = 'inline' |
| 138 } |
| 139 |
| 140 // Expands the view. This is the opposite of "Collapse" |
| 141 function uncollapse() { |
| 142 unmerge(); |
| 143 |
| 144 // Make the comments visible. |
| 145 var comments = document.querySelectorAll('.DevComment'); |
| 146 for(var i = 0; i < comments.length; i++) { |
| 147 comments[i].style.display = ""; |
| 148 } |
| 149 |
| 150 // Make the details visible. |
| 151 var details = document.querySelectorAll('.DevDetails'); |
| 152 for(var i = 0; i < details.length; i++) { |
| 153 details[i].style.display = ""; |
| 154 } |
| 155 |
| 156 // Remove the round corner (lower right) for the Revision box. |
| 157 var revisions = document.querySelectorAll('.DevRev'); |
| 158 for(var i = 0; i < revisions.length; i++) { |
| 159 revisions[i].className = revisions[i].className.replace('DevRevCollapse'
, ''); |
| 160 } |
| 161 |
| 162 // Remoe the round corner (lower left) for the last category box. |
| 163 var status = document.querySelectorAll('.DevStatus'); |
| 164 for(var i = 0; i < status.length; i++) { |
| 165 status[i].className = status[i].className.replace('DevStatusCollapse', '
'); |
| 166 } |
| 167 |
| 168 // Delete the cookies that say that we want to be collapsed or merged. |
| 169 eraseCookie('collapsed') |
| 170 eraseCookie('merged') |
| 171 |
| 172 // Display the "collapse" and "merge" buttons. |
| 173 document.querySelectorAll('.collapse')[0].style.display = 'inline' |
| 174 document.querySelectorAll('.merge')[0].style.display = 'inline' |
| 175 |
| 176 // Remove the "uncollapse" and "unmerge" buttons. |
| 177 document.querySelectorAll('.uncollapse')[0].style.display = 'none' |
| 178 document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| 179 } |
| 180 |
| 181 // Merge all the status boxes together. |
| 182 function merge() { |
| 183 collapse(); |
| 184 |
| 185 // Hide all the spacing. |
| 186 var spacing = document.querySelectorAll('.DevStatusSpacing'); |
| 187 for(var i = 0; i < spacing.length; i++) { |
| 188 spacing[i].style.display = "none"; |
| 189 } |
| 190 |
| 191 // Each boxes have, in the className, a tag that uniquely represents the |
| 192 // build where this data comes from. |
| 193 // Since we want to merge all the boxes coming from the same build, we |
| 194 // parse the document to find all the builds, and then, for each build, we |
| 195 // concatenate the boxes. |
| 196 |
| 197 var allTags = []; |
| 198 all = document.getElementsByTagName('*') |
| 199 for(var i = 0; i < all.length; i++) { |
| 200 var element = all[i]; |
| 201 start = element.className.indexOf('Tag') |
| 202 if (start != -1) { |
| 203 var className = "" |
| 204 end = element.className.indexOf(' ', start) |
| 205 if (end != -1) { |
| 206 className = element.className.substring(start, end); |
| 207 } else { |
| 208 className = element.className.substring(start); |
| 209 } |
| 210 allTags[className] = 1; |
| 211 } |
| 212 } |
| 213 |
| 214 // Mergeall tags that we found |
| 215 for (i in allTags) { |
| 216 var current = document.querySelectorAll('.' + i); |
| 217 |
| 218 // We do the work only if there is more than 1 box with the same |
| 219 // build. |
| 220 if (current.length > 1) { |
| 221 // Add the noround class to all the boxes. |
| 222 for(var i = 0; i < current.length; i++) { |
| 223 current[i].className = current[i].className + ' noround'; |
| 224 } |
| 225 |
| 226 // Add the begin class to the first box. |
| 227 current[0].className = current[0].className + ' begin'; |
| 228 |
| 229 // Add the end class to the last box. |
| 230 last = current.length - 1; |
| 231 current[last].className = current[last].className + ' end'; |
| 232 } |
| 233 } |
| 234 |
| 235 // Display the "unmerge" button. |
| 236 document.querySelectorAll('.unmerge')[0].style.display = 'inline' |
| 237 document.querySelectorAll('.uncollapse')[0].style.display = 'inline' |
| 238 |
| 239 // Remove the "merge" button. |
| 240 document.querySelectorAll('.collapse')[0].style.display = 'none' |
| 241 document.querySelectorAll('.merge')[0].style.display = 'none' |
| 242 |
| 243 // Create a cookie to remember that we want to be merged. |
| 244 createCookie('merged', 'true', 30) |
| 245 } |
| 246 |
| 247 // Un-merge the view. This is the opposite of "merge". |
| 248 function unmerge() { |
| 249 // We put back all the spacing. |
| 250 var spacing = document.querySelectorAll('.DevStatusSpacing'); |
| 251 for(var i = 0; i < spacing.length; i++) { |
| 252 spacing[i].style.display = ""; |
| 253 } |
| 254 |
| 255 // We remove the class added to all the boxes we modified. |
| 256 var noround = document.querySelectorAll('.noround'); |
| 257 for(var i = 0; i < noround.length; i++) { |
| 258 noround[i].className = noround[i].className.replace("begin", ''); |
| 259 noround[i].className = noround[i].className.replace("end", ''); |
| 260 noround[i].className = noround[i].className.replace("noround", ''); |
| 261 } |
| 262 |
| 263 // Delete the cookie, we don't want to be merged anymore. |
| 264 eraseCookie('merged') |
| 265 |
| 266 // Display the "merge" button. |
| 267 document.querySelectorAll('.merge')[0].style.display = 'inline' |
| 268 |
| 269 // Hide the "unmerge" button. |
| 270 document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| 271 } |
| 272 |
| 273 function SetupView() { |
| 274 if (readCookie('merged')) { |
| 275 merge(); |
| 276 } else if (readCookie('collapsed')) { |
| 277 collapse(); |
| 278 } |
| 279 } |
| 280 |
| 281 document.addEventListener("DOMContentLoaded", SetupView, false); |
| 282 |
| 283 // ]]> |
| 284 </script> |
| 285 {% endblock %} |
| 286 |
| 287 {% block content %} |
| 288 |
| 289 <div align="center"> |
| 290 <table width="95%" class="Grid" border="0" cellspacing="0"> |
| 291 <tr> |
| 292 <td width="33%" align="left" class="left_align"> |
| 293 {% if repository %} |
| 294 <br><b>Repository:</b> {{ repository|e }} |
| 295 {% endif %} |
| 296 {% if branch != ANYBRANCH %} |
| 297 <br><b>Branch:</b> {{ branch|e }} |
| 298 {% endif %} |
| 299 </td> |
| 300 <td width="33%" align="center" class="center_align"> |
| 301 <div align="center"> |
| 302 <table class="info"> |
| 303 <tr> |
| 304 <td>Legend: </td> |
| 305 <td class='legend success' title='All tests passed'>Passed</td> |
| 306 <td class='legend failure' title='There is a new failure. Take a l
ook!'>Failed</td> |
| 307 <td class='legend warnings' title='It was failing before, and it i
s still failing. Make sure you did not introduce new regressions'>Failed Ag
ain</td> |
| 308 <td class='legend running' title='The tests are still running'>Run
ning</td> |
| 309 <td class='legend exception' title='Something went wrong with the
test, there is no result'>Exception</td> |
| 310 <td class='legend offline' title='The builder is offline, as there
are no slaves connected to it'>Offline</td> |
| 311 <td class='legend notstarted' title='No result yet.'>No data<
/td> |
| 312 </tr> |
| 313 </table> |
| 314 </div> |
| 315 </td> |
| 316 <td width="33%" align="right" class="right_align"> |
| 317 <script type="text/javascript"> |
| 318 // <![CDATA[ |
| 319 function reload_page() { |
| 320 name_value = document.getElementById('namebox').value |
| 321 if (document.location.href.lastIndexOf('?') == -1) |
| 322 document.location.href = document.location.href+ '?name=' + name_v
alue; |
| 323 else |
| 324 document.location.href = document.location.href+ '&name=' + name_v
alue; |
| 325 } |
| 326 // ]]> |
| 327 </script> |
| 328 <input id='namebox' name='name' type='text' style='color:#999;' |
| 329 onblur='this.value = this.value || this.defaultValue; this.style.col
or = "#999";' |
| 330 onfocus='this.value=""; this.style.color = "#000";' |
| 331 value='Personalized for...'/> |
| 332 <input type='submit' value='Go' onclick='reload_page()'/> |
| 333 </td> |
| 334 </tr> |
| 335 </table> |
| 336 </div> |
| 337 |
| 338 <br/> |
| 339 |
| 340 {% set alt_class = cycler('', 'Alt') %} |
| 341 |
| 342 <div align="center"> |
| 343 <table width="96%"> |
| 344 |
| 345 {% if categories|length > 1 %} |
| 346 <tr> |
| 347 <td width="1%"> |
| 348 </td> |
| 349 <td width="1%"> |
| 350 </td> |
| 351 {% for c in categories %} |
| 352 <td class='DevStatus Alt {{ "first" if loop.first else '' }} {{ "last" if
loop.last else '' }}' width='{{ c.size }}%'> |
| 353 {{ c.name|numstrip }} |
| 354 </td> |
| 355 {% endfor %} |
| 356 </tr> |
| 357 <tr class='DevStatusSpacing'> |
| 358 </tr> |
| 359 {% endif %} |
| 360 |
| 361 {% if slaves %} |
| 362 <tr> |
| 363 <td width="1%"> |
| 364 </td> |
| 365 <td width="1%"> |
| 366 </td> |
| 367 {% for c in categories %} |
| 368 <td class='DevSlave Alt {{ "last" if loop.last else '' }}'> |
| 369 <table width="100%"> |
| 370 <tr> |
| 371 {% for s in slaves[c.name] %} |
| 372 <td class='DevSlaveBox'> |
| 373 <a href='{{ s.url }}' title='{{ s.pageTitle }}' class='DevSlaveBox {
{ s.color }}' target="_blank"> |
| 374 </a> |
| 375 </td> |
| 376 {% endfor %} |
| 377 </tr> |
| 378 </table> |
| 379 </td> |
| 380 {% endfor %} |
| 381 </tr> |
| 382 {% endif %} |
| 383 |
| 384 {% for r in revisions %} |
| 385 {% set alt = alt_class.next() %} |
| 386 {% set last = "last" if loop.last else "" %} |
| 387 |
| 388 <tr> |
| 389 <td class='DevRev {{ alt }} DevRevCollapse' width="1%"> |
| 390 <a href="{{ r.link }}" target="_blank">{{ r.id|shortrev(r.repository) }}</
a> |
| 391 </td> |
| 392 <td class='DevName {{ alt }}' width="1%"> |
| 393 {{ r.who|user }} |
| 394 </td> |
| 395 |
| 396 {% for c in categories %} |
| 397 <td class='DevStatus {{ alt }} {% if loop.last %}DevStatusCollapse{% endif %
}'> |
| 398 <table width="100%"> |
| 399 <tr> |
| 400 {% for b in r.builds[c.name] %} |
| 401 <td class='DevStatusBox'> |
| 402 <a href='#' onclick='showBuildBox("{{ b.url }}", event); return fals
e;' |
| 403 title='{{ b.pageTitle|e }}' class='DevStatusBox {{ b.color }} {{
b.tag }}' |
| 404 target="_blank"></a> |
| 405 </td> |
| 406 {% endfor %} |
| 407 </tr> |
| 408 </table> |
| 409 </td> |
| 410 {% endfor %} |
| 411 </tr> |
| 412 |
| 413 <tr> |
| 414 <td colspan="{{ r.span }}" class='DevComment {{ alt }}'> |
| 415 {{ r.comments|changecomment(r.project or None)|replace('\n', '<br/>')|repl
ace(' ',' ') }} |
| 416 </td> |
| 417 </tr> |
| 418 |
| 419 {% if r.details %} |
| 420 <tr> |
| 421 <td colspan="{{ r.span }}" class='DevDetails {{ alt }}'> |
| 422 <ul style='margin: 0px; padding: 0 0 0 1.5em;'> |
| 423 {% for d in r.details %} |
| 424 <li>{{ d.buildername }}: {{ d.status }} - |
| 425 {%- for l in d.logs -%} |
| 426 <a href="{{ l.url }}"> {{ l.name }} </a>{% if not loop.last %} - {%
endif %} |
| 427 {%- endfor -%} |
| 428 </li> |
| 429 {% endfor %} |
| 430 </ul> |
| 431 </td> |
| 432 </tr> |
| 433 {% endif %} |
| 434 |
| 435 <tr class='DevStatusSpacing'> |
| 436 <td> |
| 437 </td> |
| 438 </tr> |
| 439 {% else %} |
| 440 <tr><td>No revisions available</td></tr> |
| 441 {% endfor %} |
| 442 |
| 443 </table> |
| 444 </div> |
| 445 |
| 446 |
| 447 <div id="divBox" onmouseout="if (checkMouseLeave(this, event)) this.style.displa
y = 'None'" class="BuildWaterfall"> |
| 448 </div> |
| 449 |
| 450 |
| 451 <iframe id="frameBox" style="display: none;"></iframe> |
| 452 |
| 453 <script type="text/javascript"> |
| 454 // replace 'onload="updateDiv(event);" with this, as iframe doesn't have onload
event in xhtml |
| 455 window.onload = function() { |
| 456 document.getElementById('frameBox').onload = function(event) { |
| 457 updateDiv(event); |
| 458 }; |
| 459 }; |
| 460 </script> |
| 461 |
| 462 {% endblock %} |
| 463 |
| 464 |
| 465 {% block footer %} |
| 466 <div class="footer" style="clear:both"> |
| 467 <hr/> |
| 468 [ <a class='collapse' href='#' OnClick='collapse(); return false;'>collapse</a
> |
| 469 <a class='uncollapse' href='#' OnClick='uncollapse(); return false;'>un-collap
se</a> |
| 470 <a class='merge' href="#" OnClick="merge(); return false;">merge</a> |
| 471 <a class='unmerge' style='display: none' href="#" OnClick="unmerge(); return f
alse;">un-merge</a> ] |
| 472 </div> |
| 473 {% endblock %} |
OLD | NEW |