<html> | |
<head> | |
<!-- | |
Amazon S3 Bucket listing. | |
Copyright (C) 2008 Francesco Pasqualini | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
--> | |
<!-- | |
Modified by Nolan Lawson! (http://nolanlawson.com). I'm keeping the spirit of the | |
GPL alive by issuing this with the same license! | |
--> | |
<title>Bucket loading...</title> | |
<link href="//netdna.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet"/> | |
<style> | |
.hide-while-loading { | |
display:none; | |
} | |
.i-expand-collapse { | |
opacity: 0.3; | |
} | |
.i-file-or-folder { | |
margin-right: 4px; | |
} | |
</style> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.1.2/handlebars.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.4.0/moment.min.js"></script> | |
</head> | |
<body> | |
<div class="container"> | |
<h1 id="h1-title">Bucket loading...</h1> | |
<table class="hide-while-loading table table-striped"> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Date Modified</th> | |
<th>Size</th> | |
<th>Type</th> | |
</tr> | |
</thead> | |
<tbody id="tbody-content"> | |
</tbody> | |
</table> | |
</div> | |
<script id="file-or-folder" type="text/x-handlebars-template"> | |
<tr> | |
{{#if isFolder}} | |
<td><i class="icon-chevron-down i-expand-collapse" style="margin-left:calc(({{numLevels}} - 1) * 16px)");></i><i class="icon-folder-open i-file-or-folder" style="margin-left:4px;"></i> | |
{{simpleFilename}}</td> | |
{{else}} | |
<td><i class="icon-file i-file-or-folder" style="margin-left:calc(({{numLevels}} * 16px) + 4px);"></i> | |
<a href="{{url}}">{{simpleFilename}}</a></td> | |
{{/if}} | |
<td>{{friendlyLastModified}}</td> | |
<td>{{friendlySizeName}}</td> | |
<td>{{type}}</td> | |
</tr> | |
</script> | |
<script> | |
(function($){ | |
"use strict"; | |
var FOLDER_PATTERN = new RegExp('_\\$folder\\$$'); | |
var TYPE_PATTERN = new RegExp('\\.([^\\.\\s]{1,10})$'); | |
var KB = 1024; | |
var MB = 1000000; | |
var GB = 1000000000; | |
// replace last /index.html to get bucket root | |
var bucketUrl = document.location.href.replace(/\/[^\/]+$/, ''); | |
var compiledTemplate; | |
// return e.g. 1.2KB, 1.3MB, 2GB, etc. | |
function toFriendlySizeName(size){ | |
if (size === 0) { | |
return ''; | |
} else if (size < KB) { | |
return size + ' B'; | |
} else if (size < MB) { | |
return (size / KB).toFixed(0) + ' KB'; | |
} else if (size < GB) { | |
return (size / MB).toFixed(2) + ' MB'; | |
} | |
return (size / GB).toFixed(2) + ' GB'; | |
} | |
// POJO describing a file or a folder | |
function FileOrFolder(lastModified, etag, size, key){ | |
var self = this; | |
self.lastModified = lastModified; | |
self.etag = etag; | |
self.size = size; | |
self.key = key; | |
// init logic | |
self.isFolder = FOLDER_PATTERN.test(self.key); | |
self.filename = self.isFolder ? self.key.replace(FOLDER_PATTERN,'') : self.key; | |
self.url = bucketUrl + '/' + self.key; | |
self.levels = self.filename.split('/'); | |
self.numLevels = self.levels.length; | |
self.simpleFilename = self.levels[self.numLevels - 1]; | |
self.friendlySizeName = toFriendlySizeName(parseInt(self.size,10)); | |
var foundTypes = TYPE_PATTERN.exec(self.simpleFilename); | |
self.type = self.isFolder ? 'Folder ' : (foundTypes ? (foundTypes[1].toUpperCase() + ' file') : 'Unknown'); | |
self.friendlyLastModified = moment(lastModified).format('MMM Do YYYY, hh:mm:ss a'); | |
} | |
function onAjaxSuccess(xml) { | |
var listBucketResult = $(xml).find('ListBucketResult'); | |
// set a reasonable title instead of "Bucket loading" | |
var title = 'Index of bucket "' + listBucketResult.find('Name').text() + '"'; | |
document.title = title; | |
$('#h1-title').text(title); | |
var $tbodyContent = $('#tbody-content'); | |
// create the file or folder objects | |
var filesOrFolders = []; | |
listBucketResult.find('Contents').each(function(idx, element){ | |
var $element = $(element); | |
var fileOrFolder = new FileOrFolder( | |
$element.find('LastModified').text(), | |
$element.find('ETag').text(), | |
$element.find('Size').text(), | |
$element.find('Key').text() | |
); | |
filesOrFolders.push(fileOrFolder); | |
}); | |
// sort | |
filesOrFolders.sort(function(left, right){ | |
if (left.levels === right.levels) { | |
return 0; | |
} else if (left.levels < right.levels) { | |
return -1; | |
} | |
return 1; | |
}); | |
// fill in the rows | |
var str = ''; | |
for (var i = 0; i < filesOrFolders.length; i ++) { | |
str += compiledTemplate(filesOrFolders[i]); | |
} | |
$tbodyContent.append(str); | |
$('.hide-while-loading').show(); | |
} | |
$.ajax({ | |
url: bucketUrl, | |
success: onAjaxSuccess | |
}); | |
// compile while ajax is in progress | |
compiledTemplate = Handlebars.compile($('#file-or-folder').html()); | |
})(jQuery); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment