1/* 2 * Copyright 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/** 18 * @author: Brett Slatkin (bslatkin@google.com) 19 */ 20 21// Format a number with a minimum number of digits and a padding character. 22function leftPadNumber(number, minSize, paddingChar) { 23 var stringified = '' + number; 24 if (stringified.length < minSize) { 25 for (var i = 0; i < (minSize - stringified.length); ++i) { 26 stringified = paddingChar + stringified; 27 } 28 } 29 return stringified; 30} 31 32 33// Convert milliseconds since the epoch to an ISO8601 datestring. 34function getIso8601String(timeMs) { 35 var time = new Date(); 36 time.setTime(timeMs); 37 return '' + 38 time.getUTCFullYear() + '-' + 39 leftPadNumber(time.getUTCMonth() + 1, 2, '0') + '-' + 40 leftPadNumber(time.getUTCDate(), 2, '0') + 'T' + 41 leftPadNumber(time.getUTCHours(), 2, '0') + ':' + 42 leftPadNumber(time.getUTCMinutes(), 2, '0') + ':' + 43 leftPadNumber(time.getUTCSeconds(), 2, '0') + 'Z'; 44} 45 46 47// Get time string for job runtime. Specially handle number of days running as 48// a prefix and milliseconds as a suffix. If the runtime is less than one 49// minute, use the format "38.123 seconds" instead. 50function getElapsedTimeString(startTimestampMs, updatedTimestampMs) { 51 var updatedDiff = Math.max(0, updatedTimestampMs - startTimestampMs); 52 var updatedDays = Math.floor(updatedDiff / 86400000.0); 53 updatedDiff -= (updatedDays * 86400000.0); 54 var updatedHours = Math.floor(updatedDiff / 3600000.0); 55 updatedDiff -= (updatedHours * 3600000.0); 56 var updatedMinutes = Math.floor(updatedDiff / 60000.0); 57 updatedDiff -= (updatedMinutes * 60000.0); 58 var updatedSeconds = Math.floor(updatedDiff / 1000.0); 59 updatedDiff -= (updatedSeconds * 1000.0); 60 var updatedMs = Math.floor(updatedDiff / 1.0); 61 62 var updatedString = ''; 63 64 if (updatedMinutes > 0) { 65 if (updatedDays == 1) { 66 updatedString = '1 day, '; 67 } else if (updatedDays > 1) { 68 updatedString = '' + updatedDays + ' days, '; 69 } 70 updatedString += 71 leftPadNumber(updatedHours, 2, '0') + ':' + 72 leftPadNumber(updatedMinutes, 2, '0') + ':' + 73 leftPadNumber(updatedSeconds, 2, '0'); 74 if (updatedMs > 0) { 75 updatedString += '.' + leftPadNumber(updatedMs, 3, '0'); 76 } 77 } else { 78 updatedString += updatedSeconds; 79 updatedString += '.' + leftPadNumber(updatedMs, 3, '0'); 80 updatedString += ' seconds'; 81 } 82 83 return updatedString; 84} 85 86 87// Clears the status butter. 88function clearButter() { 89 $('#butter').css('display', 'none'); 90} 91 92 93// Sets the status butter, optionally indicating if it's an error message. 94function setButter(message, error, traceback, asHtml) { 95 var butter = $('#butter'); 96 // Prevent flicker on butter update by hiding it first. 97 butter.css('display', 'none'); 98 if (error) { 99 butter.removeClass('info').addClass('error'); 100 } else { 101 butter.removeClass('error').addClass('info'); 102 } 103 butter.children().remove(); 104 if (asHtml) { 105 butter.append($('<div>').html(message)); 106 } else { 107 butter.append($('<div>').text(message)); 108 } 109 110 function centerButter() { 111 butter.css('left', ($(window).width() - $(butter).outerWidth()) / 2); 112 } 113 114 if (traceback) { 115 var showDetail = $('<a href="">').text('Detail'); 116 showDetail.click(function(event) { 117 $('#butter-detail').toggle(); 118 centerButter(); 119 event.preventDefault(); 120 }); 121 var butterDetail = $('<pre id="butter-detail">').text(traceback); 122 butterDetail.css('display', 'none'); 123 124 butter.append(showDetail); 125 butter.append(butterDetail); 126 } 127 centerButter(); 128 butter.css('display', null); 129} 130 131 132// Given an AJAX error message (which is empty or null on success) and a 133// data payload containing JSON, parses the data payload and returns the object. 134// Server-side errors and AJAX errors will be brought to the user's attention 135// if present in the response object 136function getResponseDataJson(error, data) { 137 var response = null; 138 try { 139 response = $.parseJSON(data); 140 } catch (e) { 141 error = '' + e; 142 } 143 if (response && response.error_class) { 144 error = response.error_class + ': ' + response.error_message; 145 setButter('Error -- ' + error, true, response.error_traceback); 146 } else if (!response) { 147 setButter('Error -- Could not parse response JSON data.', true); 148 } else { 149 return response; 150 } 151 return null; 152} 153