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