| {% extends "announce.html" %} |
| |
| {% block head %} |
| {{ super() }} |
| <script type='text/javascript'> |
| // <![CDATA[ |
| // |
| |
| // |
| // Functions used to display the build status bubble on box click. |
| // |
| |
| // show the build status box. This is called when the user clicks on a block. |
| function showBuildBox(url, event) { |
| // Find the current curson position. |
| var cursorPosTop = (window.event ? window.event.clientY : event.pageY) |
| var cursorPosLeft = (window.event ? window.event.clientX : event.pageX) |
| |
| // Offset the position by 5, to make the window appears under the cursor. |
| cursorPosTop = cursorPosTop + document.body.scrollTop -5 ; |
| cursorPosLeft = cursorPosLeft + document.body.scrollLeft - 5; |
| |
| // Move the div (hidden) under the cursor. |
| var divBox = document.getElementById('divBox'); |
| divBox.style.top = parseInt(cursorPosTop) + 'px'; |
| divBox.style.left = parseInt(cursorPosLeft) + 'px'; |
| |
| // Reload the hidden frame with the build page we want to show. |
| // The onload even on this frame will update the div and make it visible. |
| document.getElementById("frameBox").src = url |
| |
| // We don't want to reload the page. |
| return false; |
| } |
| |
| // OnLoad handler for the iframe containing the build to show. |
| function updateDiv(event) { |
| // Get the frame innerHTML. |
| var iframeContent = document.getElementById("frameBox").contentWindow.document.body.innerHTML; |
| |
| // If there is any content, update the div, and make it visible. |
| if (iframeContent) { |
| var divBox = document.getElementById('divBox'); |
| divBox.innerHTML = iframeContent ; |
| divBox.style.display = "block"; |
| } |
| } |
| |
| // Util functions to know if an element is contained inside another element. |
| // We use this to know when we mouse out our build status div. |
| function containsDOM (container, containee) { |
| var isParent = false; |
| do { |
| if ((isParent = container == containee)) |
| break; |
| containee = containee.parentNode; |
| } while (containee != null); |
| |
| return isParent; |
| } |
| |
| // OnMouseOut handler. Returns true if the mouse moved out of the element. |
| // It is false if the mouse is still in the element, but in a blank part of it, |
| // like in an empty table cell. |
| function checkMouseLeave(element, event) { |
| if (element.contains && event.toElement) { |
| return !element.contains(event.toElement); |
| } |
| else if (event.relatedTarget) { |
| return !containsDOM(element, event.relatedTarget); |
| } |
| } |
| |
| // Returns the value of a GET parameter, or null if it does not exist. |
| function readGetParameter(name) { |
| var begin = name + '='; |
| var data = location.search; |
| if (data === '') { |
| return null; |
| } |
| // Location starts with "?". |
| data = data.substr(1); |
| var parameters = data.split("&"); |
| for (var index = 0; index < parameters.length; index++) { |
| var parameter = parameters[index]; |
| if (parameter.indexOf(begin) == 0) |
| return decodeURIComponent( |
| parameter.substring(begin.length)); |
| } |
| return null; |
| } |
| |
| // Creates a new cookie. |
| function createCookie(name, value, day) { |
| var date = new Date(); |
| date.setTime(date.getTime() + (day * 24 * 60 * 60 * 1000)); |
| var expires = "; expires=" + date.toGMTString(); |
| document.cookie = name + "=" + value+expires + "; path=/"; |
| } |
| |
| // Returns the value of a cookie, or null if it does not exist. |
| function readCookie(name) { |
| var begin = name + "="; |
| var data = document.cookie.split(';'); |
| for(var i = 0; i < data.length; i++) { |
| var cookie = data[i]; |
| while (cookie.charAt(0) == ' ') |
| cookie = cookie.substring(1, cookie.length); |
| if (cookie.indexOf(begin) == 0) |
| return cookie.substring(begin.length, cookie.length); |
| } |
| |
| return null; |
| } |
| |
| // Deletes a cookie. |
| function eraseCookie(name) { |
| createCookie(name, "", -1); |
| } |
| |
| // Hides all "details" and "comments" section. |
| function collapse() { |
| // Hide all Comments sections. |
| var comments = document.querySelectorAll('.DevComment'); |
| for(var i = 0; i < comments.length; i++) { |
| comments[i].style.display = "none"; |
| } |
| |
| // Hide all details sections. |
| var details = document.querySelectorAll('.DevDetails'); |
| for(var i = 0; i < details.length; i++) { |
| details[i].style.display = "none"; |
| } |
| |
| // Fix the rounding on the Revision box. (Lower right corner must be round) |
| var revisions = document.querySelectorAll('.DevRev'); |
| for(var i = 0; i < revisions.length; i++) { |
| revisions[i].className = revisions[i].className + ' DevRevCollapse'; |
| } |
| |
| // Fix the rounding on the last category box. (Lower left corner must be round) |
| var status = document.querySelectorAll('.last'); |
| for(var i = 0; i < status.length; i++) { |
| status[i].className = status[i].className + ' DevStatusCollapse'; |
| } |
| |
| // Create a cookie to remember that we want the view to be collapsed. |
| createCookie('collapsed', 'true', 30) |
| |
| // Hide the collapse and the unmerge buttons. |
| document.querySelectorAll('.collapse')[0].style.display = 'none' |
| document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| |
| // Activate the merge and expand buttons. |
| document.querySelectorAll('.uncollapse')[0].style.display = 'inline' |
| document.querySelectorAll('.merge')[0].style.display = 'inline' |
| } |
| |
| // Expands the view. This is the opposite of "Collapse" |
| function uncollapse() { |
| unmerge(); |
| |
| // Make the comments visible. |
| var comments = document.querySelectorAll('.DevComment'); |
| for(var i = 0; i < comments.length; i++) { |
| comments[i].style.display = ""; |
| } |
| |
| // Make the details visible. |
| var details = document.querySelectorAll('.DevDetails'); |
| for(var i = 0; i < details.length; i++) { |
| details[i].style.display = ""; |
| } |
| |
| // Remove the round corner (lower right) for the Revision box. |
| var revisions = document.querySelectorAll('.DevRev'); |
| for(var i = 0; i < revisions.length; i++) { |
| revisions[i].className = revisions[i].className.replace('DevRevCollapse', ''); |
| } |
| |
| // Remoe the round corner (lower left) for the last category box. |
| var status = document.querySelectorAll('.DevStatus'); |
| for(var i = 0; i < status.length; i++) { |
| status[i].className = status[i].className.replace('DevStatusCollapse', ''); |
| } |
| |
| // Delete the cookies that say that we want to be collapsed or merged. |
| eraseCookie('collapsed') |
| eraseCookie('merged') |
| |
| // Display the "collapse" and "merge" buttons. |
| document.querySelectorAll('.collapse')[0].style.display = 'inline' |
| document.querySelectorAll('.merge')[0].style.display = 'inline' |
| |
| // Remove the "uncollapse" and "unmerge" buttons. |
| document.querySelectorAll('.uncollapse')[0].style.display = 'none' |
| document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| } |
| |
| // Merge all the status boxes together. |
| function merge() { |
| collapse(); |
| |
| // Hide all the spacing. |
| var spacing = document.querySelectorAll('.DevStatusSpacing'); |
| for(var i = 0; i < spacing.length; i++) { |
| spacing[i].style.display = "none"; |
| } |
| |
| // Each boxes have, in the className, a tag that uniquely represents the |
| // build where this data comes from. |
| // Since we want to merge all the boxes coming from the same build, we |
| // parse the document to find all the builds, and then, for each build, we |
| // concatenate the boxes. |
| |
| var allTags = []; |
| all = document.getElementsByTagName('*') |
| for(var i = 0; i < all.length; i++) { |
| var element = all[i]; |
| start = element.className.indexOf('Tag') |
| if (start != -1) { |
| var className = "" |
| end = element.className.indexOf(' ', start) |
| if (end != -1) { |
| className = element.className.substring(start, end); |
| } else { |
| className = element.className.substring(start); |
| } |
| allTags[className] = 1; |
| } |
| } |
| |
| // Mergeall tags that we found |
| for (i in allTags) { |
| var current = document.querySelectorAll('.' + i); |
| |
| // We do the work only if there is more than 1 box with the same |
| // build. |
| if (current.length > 1) { |
| // Add the noround class to all the boxes. |
| for(var i = 0; i < current.length; i++) { |
| current[i].className = current[i].className + ' noround'; |
| } |
| |
| // Add the begin class to the first box. |
| current[0].className = current[0].className + ' begin'; |
| |
| // Add the end class to the last box. |
| last = current.length - 1; |
| current[last].className = current[last].className + ' end'; |
| } |
| } |
| |
| // Display the "unmerge" button. |
| document.querySelectorAll('.unmerge')[0].style.display = 'inline' |
| document.querySelectorAll('.uncollapse')[0].style.display = 'inline' |
| |
| // Remove the "merge" button. |
| document.querySelectorAll('.collapse')[0].style.display = 'none' |
| document.querySelectorAll('.merge')[0].style.display = 'none' |
| |
| // Create a cookie to remember that we want to be merged. |
| createCookie('merged', 'true', 30) |
| } |
| |
| // Un-merge the view. This is the opposite of "merge". |
| function unmerge() { |
| // We put back all the spacing. |
| var spacing = document.querySelectorAll('.DevStatusSpacing'); |
| for(var i = 0; i < spacing.length; i++) { |
| spacing[i].style.display = ""; |
| } |
| |
| // We remove the class added to all the boxes we modified. |
| var noround = document.querySelectorAll('.noround'); |
| for(var i = 0; i < noround.length; i++) { |
| noround[i].className = noround[i].className.replace("begin", ''); |
| noround[i].className = noround[i].className.replace("end", ''); |
| noround[i].className = noround[i].className.replace("noround", ''); |
| } |
| |
| // Delete the cookie, we don't want to be merged anymore. |
| eraseCookie('merged') |
| |
| // Display the "merge" button. |
| document.querySelectorAll('.merge')[0].style.display = 'inline' |
| |
| // Hide the "unmerge" button. |
| document.querySelectorAll('.unmerge')[0].style.display = 'none' |
| } |
| |
| function SetupView() { |
| // Allow override cookies with Get parameters. |
| var getMerged = readGetParameter('merged'); |
| if (getMerged === 'true') { |
| createCookie('merged', 'true', 30); |
| } |
| if (getMerged === 'false') { |
| eraseCookie('merged'); |
| } |
| var getCollapsed = readGetParameter('collapsed'); |
| if (getCollapsed === 'true') { |
| createCookie('collapsed', 'true', 30); |
| } |
| if (getCollapsed === 'false') { |
| eraseCookie('collapsed'); |
| } |
| |
| if (readCookie('merged')) { |
| merge(); |
| } else if (readCookie('collapsed')) { |
| collapse(); |
| } |
| } |
| |
| document.addEventListener("DOMContentLoaded", SetupView, false); |
| |
| // ]]> |
| </script> |
| {% endblock %} |
| |
| {% block content %} |
| |
| <div align="center"> |
| <table width="95%" class="Grid" border="0" cellspacing="0"> |
| <tr> |
| <td width="33%" align="left" class="left_align"> |
| {% if repository %} |
| <br><b>Repository:</b> {{ repository|e }} |
| {% endif %} |
| {% if branch != ANYBRANCH %} |
| <br><b>Branch:</b> {{ branch|e }} |
| {% endif %} |
| </td> |
| <td width="33%" align="center" class="center_align"> |
| <div align="center"> |
| <table class="info"> |
| <tr> |
| <td>Legend: </td> |
| <td class='legend success' title='All tests passed'>Passed</td> |
| <td class='legend failure' title='There is a new failure. Take a look!'>Failed</td> |
| <td class='legend warnings' title='It was failing before, and it is still failing. Make sure you did not introduce new regressions'>Failed Again</td> |
| <td class='legend running' title='The tests are still running'>Running</td> |
| <td class='legend exception' title='Something went wrong with the test, there is no result'>Exception</td> |
| <td class='legend offline' title='The builder is offline, as there are no slaves connected to it'>Offline</td> |
| <td class='legend notstarted' title='No result yet.'>No data</td> |
| </tr> |
| </table> |
| </div> |
| </td> |
| <td width="33%" align="right" class="right_align"> |
| <script type="text/javascript"> |
| // <![CDATA[ |
| function reload_page() { |
| name_value = document.getElementById('namebox').value |
| if (document.location.href.lastIndexOf('?') == -1) |
| document.location.href = document.location.href+ '?name=' + name_value; |
| else |
| document.location.href = document.location.href+ '&name=' + name_value; |
| } |
| // ]]> |
| </script> |
| <input id='namebox' name='name' type='text' style='color:#999;' |
| onblur='this.value = this.value || this.defaultValue; this.style.color = "#999";' |
| onfocus='this.value=""; this.style.color = "#000";' |
| value='Personalized for...'/> |
| <input type='submit' value='Go' onclick='reload_page()'/> |
| </td> |
| </tr> |
| </table> |
| </div> |
| |
| <br/> |
| |
| {% set alt_class = cycler('', 'Alt') %} |
| |
| <div align="center"> |
| <table width="96%"> |
| |
| {% if categories|length > 1 %} |
| <tr> |
| <td width="1%"> |
| </td> |
| <td width="1%"> |
| </td> |
| {% for c in categories %} |
| <td class='DevStatus Alt {{ "first" if loop.first else '' }} {{ "last" if loop.last else '' }}' width='{{ c.size }}%'> |
| {{ c.name|numstrip }} |
| </td> |
| {% endfor %} |
| </tr> |
| <tr class='DevStatusSpacing'> |
| </tr> |
| {% endif %} |
| |
| {% if slaves %} |
| <tr> |
| <td width="1%"> |
| </td> |
| <td width="1%"> |
| </td> |
| {% for c in categories %} |
| <td class='DevSlave Alt {{ "last" if loop.last else '' }}'> |
| <table width="100%"> |
| <tr> |
| {% for s in slaves[c.name] %} |
| <td class='DevSlaveBox'> |
| <a href='{{ s.url }}' title='{{ s.pageTitle }}' class='DevSlaveBox {{ s.color }}' target="_blank"> |
| </a> |
| </td> |
| {% endfor %} |
| </tr> |
| </table> |
| </td> |
| {% endfor %} |
| </tr> |
| {% endif %} |
| |
| {% for r in revisions %} |
| {% set alt = alt_class.next() %} |
| {% set last = "last" if loop.last else "" %} |
| |
| <tr> |
| <td class='DevRev {{ alt }} DevRevCollapse' width="1%"> |
| <a href="{{ r.link }}" target="_blank">{{ r.id|shortrev(r.repository) }}</a> |
| </td> |
| <td class='DevName {{ alt }}' width="1%"> |
| {{ r.who|user }} |
| </td> |
| |
| {% for c in categories %} |
| <td class='DevStatus {{ alt }} {% if loop.last %}DevStatusCollapse{% endif %}'> |
| <table width="100%"> |
| <tr> |
| {% for b in r.builds[c.name] %} |
| <td class='DevStatusBox'> |
| <a href='#' onclick='showBuildBox("{{ b.url }}", event); return false;' |
| title='{{ b.pageTitle|e }}' class='DevStatusBox {{ b.color }} {{ b.tag }}' |
| target="_blank"></a> |
| </td> |
| {% endfor %} |
| </tr> |
| </table> |
| </td> |
| {% endfor %} |
| </tr> |
| |
| <tr> |
| <td colspan="{{ r.span }}" class='DevComment {{ alt }}'> |
| {{ r.comments|changecomment(r.project or None)|replace('\n', '<br/>')|replace(' ',' ') }} |
| </td> |
| </tr> |
| |
| {% if r.details %} |
| <tr> |
| <td colspan="{{ r.span }}" class='DevDetails {{ alt }}'> |
| <ul style='margin: 0px; padding: 0 0 0 1.5em;'> |
| {% for d in r.details %} |
| <li>{{ d.buildername }}: {{ d.status }} - |
| {%- for l in d.logs -%} |
| <a href="{{ l.url }}"> {{ l.name }} </a>{% if not loop.last %} - {% endif %} |
| {%- endfor -%} |
| </li> |
| {% endfor %} |
| </ul> |
| </td> |
| </tr> |
| {% endif %} |
| |
| <tr class='DevStatusSpacing'> |
| <td> |
| </td> |
| </tr> |
| {% else %} |
| <tr><td>No revisions available</td></tr> |
| {% endfor %} |
| |
| </table> |
| </div> |
| |
| |
| <div id="divBox" onmouseout="if (checkMouseLeave(this, event)) this.style.display = 'None'" class="BuildWaterfall"> |
| </div> |
| |
| |
| <iframe id="frameBox" style="display: none;"></iframe> |
| |
| <script type="text/javascript"> |
| // replace 'onload="updateDiv(event);" with this, as iframe doesn't have onload event in xhtml |
| window.addEventListener("load", function() { |
| document.getElementById('frameBox').onload = function(event) { |
| updateDiv(event); |
| }; |
| }, false); |
| </script> |
| |
| {% endblock %} |
| |
| |
| {% block footer %} |
| <div class="footer" style="clear:both"> |
| <hr/> |
| [ <a class='collapse' href='#' OnClick='collapse(); return false;'>collapse</a> |
| <a class='uncollapse' href='#' OnClick='uncollapse(); return false;'>un-collapse</a> |
| <a class='merge' href="#" OnClick="merge(); return false;">merge</a> |
| <a class='unmerge' style='display: none' href="#" OnClick="unmerge(); return false;">un-merge</a> ] |
| </div> |
| {% endblock %} |