<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type"> <script language="javascript"> // Split a string in 2 parts. The first is the leading number, if any, // the second is the string following the numbers. function splitNum(s) { var results = new Array(); results[0] = 'None'; for (var i = 0; i < s.length; i++) { var substr = s.substr(0, i+1) if (isNaN(substr)) { // Not a number anymore. results[1] = s.substr(i) break; } else { // This is a number. update the results. results[0] = parseFloat(substr); } } return results; } // Compare 2 strings using a custom alphanumerical algorithm. // This is similar to a normal string sort, except that we sort // first by leading digits, if any. // For example: // 100hello > 2goodbye // Numbers anywhere else in the string are compared using the normal // sort algorithm. function alphanumCompare(a, b) { var parsedA = splitNum(a); var parsedB = splitNum(b); var numA = parsedA[0]; var numB = parsedB[0]; var strA = parsedA[1]; var strB = parsedB[1]; if (isNaN(numA) == false && isNaN(numB) == false) { // They both start with numbers. if (numA < numB) return -1; if (numA > numB) return 1; // Identical. Fallback to string. return (strA < strB) ? -1 : (strA > strB ? 1 : 0) } // If only one starts with a number, we start with that one as // the lowest. if (isNaN(numA) == false) return -1 if (isNaN(numB) == false) return 1 // They are both strings. return (a < b) ? -1 : (a > b ? 1 : 0) } </script> </head> <body> <script type="application/javascript"> String.prototype.startsWith = function(str) { return (this.match('^' + str) == str) } // Helper function to retrieve the value of a GET query parameter. // Greatly inspired from http://alturl.com/8rj7a function getParameter(parameterName) { // Add '=' to the parameter name (i.e. parameterName=value) var parameterName = parameterName + '='; var queryString = window.location.search.substring(1); if (queryString.length <= 0) { return ''; } // Find the beginning of the string begin = queryString.indexOf(parameterName); // If the parameter name is not found, skip it, otherwise return the // value. if (begin == -1) { return ''; } // Add the length (integer) to the beginning. begin += parameterName.length; // Multiple parameters are separated by the '&' sign. end = queryString.indexOf ('&', begin); if (end == -1) { end = queryString.length; } // Return the string. return unescape(queryString.substring(begin, end)); } // Given a tag and a node, returns the value for this tag on this node. function getNodeValue(node, tag) { return node.getElementsByTagName(tag)[0].firstChild.nodeValue; } // Displays the directory listing given the XML and path. function displayList(xmlstring, root, path, pathRoot) { // Display the header document.write('<h1>Index of /' + path + '</h1>'); // Start the table for the results. document.write('<table style="border-spacing:15px 0px;">'); var sortOrder = getParameter('sort'); var sortLink = location.pathname + '?path=' + path; if (sortOrder != 'desc') { sortLink += '&sort=desc'; } // Display the table header. document.write('<tr><th><img src="' + root + pathRoot + 'icons/blank.gif" alt="[ICO]"></th>'); document.write('<th><a href="' + sortLink + '">Name</a></th>'); document.write('<th>Last modified</th>'); document.write('<th>Size</th>'); document.write('<th>Storage Class</th>'); document.write('<th>ETag</th></tr>'); document.write('<tr><th colspan="6"><hr></th></tr>'); // Display the 'go back' button. if (path != '') { var backpath = location.pathname; // If there is more than one section delimited by '/' in the current // path we truncate the last section and append the rest to backpath. var delimiter = path.lastIndexOf('/'); if (delimiter >= 0) { delimiter = path.substr(0, delimiter).lastIndexOf('/'); if (delimiter >= 0) { backpath += '?path='; backpath += path.substr(0, delimiter+1); } } document.write('<tr><td valign="top"><img src="' + root + pathRoot + 'icons/back.gif" alt="[DIR]"></td>'); document.write('<td><a href="'); document.write(backpath); document.write('">Parent Directory</a></td>'); document.write('<td> </td>'); document.write('<td align="right"> - </td></tr>'); } // Set up the variables. var directories = new Array(); var files = new Array(); for (var iter = 0; iter < xmlstrings.length; iter++) { var xmlstring = xmlstrings[iter]; // Parse the XML output. var parser = new DOMParser(); var xmlDoc = parser.parseFromString(xmlstring, 'text/xml'); // Get the main element. var results = xmlDoc.getElementsByTagName('ListBucketResult'); // Get all the directories. var prefixes = results[0].getElementsByTagName('CommonPrefixes'); for (var i = 0; i < prefixes.length; i++) { var prefix = getNodeValue(prefixes[i], 'Prefix'); directories.push(prefix.substr(path.length)); } // Get all the files. var contents = results[0].getElementsByTagName('Contents'); for (var i = 0; i < contents.length; i++) { var obj = new Object(); obj.keyName = getNodeValue(contents[i], 'Key'); obj.lastModified = getNodeValue(contents[i], 'LastModified'); obj.eTag = getNodeValue(contents[i], 'ETag'); obj.size = getNodeValue(contents[i], 'Size'); files.push(obj); } } files.sort(alphanumCompare); directories.sort(alphanumCompare); // Reverse the list for a descending sort. if (sortOrder == 'desc') { files.reverse(); directories.reverse(); } // Display the directories. for (var i = 0; i < directories.length; i++) { var lnk = location.pathname.substr(0, location.pathname.indexOf('?')); lnk += '?path=' + path + directories[i]; document.write('<tr>'); document.write('<td valign="top"><img src="' + root + pathRoot + 'icons/folder.gif" alt="[DIR]"></td>'); document.write('<td><a href="' + lnk + '">' + directories[i].split('/')[0] + '</a></td>'); document.write('<td align="right">-</td>'); document.write('<td align="right">-</td>'); document.write('<td align="right">-</td>'); document.write('<td align="right">-</td>'); document.write('</tr>'); } // Display the files. for (var i = 0; i < files.length; i++) { var link = root + files[i].keyName; var filename = files[i].keyName.substr(path.length); var size = files[i].size / 1024 / 1024; var lastModified = files[i].lastModified.replace('T', ' '); lastModified = lastModified.substr(0, lastModified.indexOf('.')); // Remove the entries we don't want to show. if (filename == '') { continue; } if (filename.indexOf('$folder$') >= 0) { continue; } // Display the row. document.write('<tr>'); document.write('<td valign="top"><img src="' + root + pathRoot + 'icons/binary.gif" alt="[DIR]"></td>'); document.write('<td><a href="' + link + '">' + filename + '</a></td>'); document.write('<td align="right">' + lastModified + '</td>'); document.write('<td align="right">' + size.toFixed(2) + 'MB</td>'); document.write('<td align="right"><pre>' + files[i].eTag.split('"')[1] + '</pre></td>'); document.write('</tr>'); } // Close the table. document.write('<tr><th colspan="6"><hr></th></tr>'); document.write('</table>'); } var xmlstrings = new Array(); function fetchAndDisplay(marker) { var path = getParameter('path'); var lastSlash = location.pathname.lastIndexOf("/"); var filename = location.pathname.substring(lastSlash + 1); var firstSlash = location.pathname.indexOf("/", 1); var root = location.pathname.substring(0, firstSlash + 1); var pathRoot = location.pathname.substring(firstSlash + 1, lastSlash + 1); if (!path) { path = location.pathname.substring(firstSlash + 1, lastSlash + 1); } var markerParam = ''; if (marker != '') { markerParam = '&marker=' + marker; } var http = new XMLHttpRequest(); http.open('GET', root + '?delimiter=/&prefix=' + path + markerParam, true); http.onreadystatechange = useHttpResponse; http.send(null); function useHttpResponse() { if (http.readyState == 4) { var xmlstring = http.responseText; xmlstrings.push(xmlstring); // Check if the data is truncated. if so, we need to request the // rest. var parser = new DOMParser(); var xmlDoc = parser.parseFromString(xmlstring, 'text/xml'); // Get the main element. var results = xmlDoc.getElementsByTagName('ListBucketResult'); // Get IsTruncated. var truncated = getNodeValue(results[0], 'IsTruncated'); var nextMarker = ''; if (truncated == 'true') { nextMarker = getNodeValue(results[0], 'NextMarker'); fetchAndDisplay(nextMarker); } else { displayList(xmlstrings, root, path, pathRoot); } } } } fetchAndDisplay(''); </script> </body> </html>