| <!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> |