Skip to content

Commit fef01e7

Browse files
committed
initial commit
0 parents  commit fef01e7

29 files changed

+11054
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
files/

LICENSE

+674
Large diffs are not rendered by default.

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
HTML5 file browser
2+
---
3+
4+
This HTML5 file browser allows to browse and share files in a public server directory. Unlike some other solutions out there, this file browser does not depend on any server-side code. Instead, directory listings are used to parse the list of available files.
5+
6+
### Configuration
7+
#### Apache
8+
This program comes with a `.htaccess` file that enables directory listings for the `files/` directory. Simply upload this file browser to any directory on your server and you are done.
9+
10+
#### Nginx
11+
For `nginx`, auto-indexing has to be turned on for the `/files/` directory:
12+
```
13+
location /somedir/files/ {
14+
autoindex on;
15+
}
16+
```
17+
18+
#### Python
19+
For testing purposes or to share files in a LAN, Python can be used. Run `python -m http.server 8080` (or `python2 -m SimpleHTTPServer 8080` if your system is horribly outdated) from within this directory (the directory where `README.md` can be found) and you are done.
20+
21+
### License
22+
This program is free software: you can redistribute it and/or modify
23+
it under the terms of the GNU General Public License as published by
24+
the Free Software Foundation, either version 3 of the License, or
25+
(at your option) any later version.

app.css

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
body {
2+
background: #22222f;
3+
padding-top: 1em;
4+
color: #eee;
5+
}
6+
7+
a, a:hover {
8+
cursor: pointer;
9+
color: #eee;
10+
}
11+
12+
.base-dir-icon {
13+
cursor: pointer;
14+
vertical-align: middle;
15+
margin-right: .125em;
16+
}
17+
18+
.browser-view {
19+
margin-top: 3em;
20+
}
21+
22+
.browser-view a {
23+
cursor: pointer;
24+
background-color: #333344;
25+
color: white;
26+
padding: 1.5em 3em 1.5em 1.5em;
27+
margin: .5em;
28+
min-width: 15em;
29+
display: inline-block;
30+
border-radius: .25em;
31+
}
32+
33+
.browser-view a span {
34+
margin-right: .66em;
35+
}
36+
37+
.browser-view a:hover {
38+
text-decoration: none;
39+
transition: background-color .25s;
40+
background: #434354;
41+
}
42+
43+
.bg-translucent {
44+
display: none;
45+
position: absolute;
46+
top: 0;
47+
right: 0;
48+
bottom: 0;
49+
left: 0;
50+
background: rgba(0, 0, 0, 0.5);;
51+
cursor: pointer;
52+
}
53+
54+
.file-view-wrapper {
55+
display: none;
56+
position: absolute;
57+
top: 10%;
58+
right: 10%;
59+
bottom: 10%;
60+
left: 10%;
61+
text-align: center;
62+
}
63+
64+
.file-view-img {
65+
max-width: 100%;
66+
max-height: 100%;
67+
box-shadow: 0 0 3em black;
68+
}
69+
70+
.file-view-prev, .file-view-next {
71+
display: none;
72+
position: absolute;
73+
top: 43%;
74+
cursor: pointer;
75+
opacity: .8;
76+
}
77+
78+
.file-view-prev {
79+
left: .75em;
80+
}
81+
82+
.file-view-next {
83+
right: .75em;
84+
}
85+
86+
.file-view-prev:hover, .file-view-next:hover {
87+
opacity: 1;
88+
}

app.js

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
var app = function(){
2+
var base_dir = (location.pathname.replace('/index.html', '/') +
3+
"/files/").replace(/\/\//g, '/');
4+
var current_dir = (base_dir + location.hash.substring(1) +
5+
'/').replace(/\/\//g, '/');
6+
var IMG_EXTENSIONS = ['bmp', 'gif', 'jpg', 'jpeg', 'jpe', 'png'];
7+
var IGNORED_ELEMENTS = ['../', 'Name', 'Last modified', 'Size', 'Description',
8+
'Parent Directory'];
9+
var imgCache = [];
10+
var prev_img = "";
11+
var next_img = "";
12+
13+
14+
// create a tile
15+
function createTile(href, name) {
16+
return '<a href="'+href+name+'"><span class="glyphicon glyphicon-file" aria-hidden="true"></span>'+name+'</a>';
17+
}
18+
19+
// cache an image for future usage
20+
function cacheImage(file) {
21+
for (var i=0; i<imgCache.length; i++) {
22+
if (imgCache[i].src == file) return;
23+
}
24+
imgCache.push(file);
25+
}
26+
27+
// check if the given path points to an image
28+
function isImage(path) {
29+
return $.inArray(path.split('.').pop().toLowerCase(), IMG_EXTENSIONS) != -1;
30+
}
31+
32+
function isValidTile(name) {
33+
return $.inArray(name, IGNORED_ELEMENTS) == -1;
34+
}
35+
36+
// load the contents of the given directory
37+
function cd(dir) {
38+
current_dir = dir;
39+
40+
console.log(current_dir, base_dir);
41+
location.hash = current_dir.replace(base_dir, '');
42+
43+
// show the location bar
44+
$(".current-dir").text('');
45+
var path = current_dir.replace(base_dir, '/').split('/');
46+
47+
var temp_path = "";
48+
for (var i=0; i<path.length-1; i++) {
49+
var a = document.createElement('a');
50+
temp_path += path[i] + '/';
51+
$(a).text(path[i] + '/');
52+
a.title = base_dir + temp_path.substring(1);
53+
$(a).click(function(){
54+
cd(this.title);
55+
});
56+
$(".current-dir").append(a);
57+
}
58+
59+
// retrieve the contents of the directory
60+
$.get(current_dir, function(data) {
61+
html = $.parseHTML(data);
62+
$(".browser-view").html("");
63+
64+
// create tiles
65+
$(html).find("a").each(function(i, element){
66+
if (isValidTile(element.text)) {
67+
$(".browser-view").append(
68+
createTile(current_dir, element.text));
69+
}
70+
});
71+
72+
// add events to tiles
73+
$(".browser-view a").each(function(i, element){
74+
if (element.pathname.slice(-1) == "/" ) {
75+
// open directories
76+
$(element).click(function(e) {
77+
e.preventDefault();
78+
cd(element.pathname);
79+
});
80+
} else if (isImage(element.pathname)) {
81+
// show image previews
82+
$(element).click(function(e) {
83+
e.preventDefault();
84+
showPreview(element.pathname);
85+
});
86+
}
87+
});
88+
});
89+
}
90+
91+
// show an image preview of the given file
92+
function showPreview(filepath){
93+
$(".bg-translucent").css('display', 'block');
94+
$(".file-view-img").attr('src', 'loader.gif');
95+
$(".file-view-wrapper").css('display', 'block');
96+
var img = new Image();
97+
img.src = filepath;
98+
img.onload = function() {
99+
$(".file-view-img").attr('src', filepath);
100+
var imgWidth = $('.file-view-img').width();
101+
$(".file-view-wrapper").css('left', ($(document).width()-imgWidth)/2);
102+
$(".file-view-wrapper").css('width', imgWidth);
103+
$(".file-view-prev").css('display', 'block');
104+
$(".file-view-next").css('display', 'block');
105+
};
106+
cacheImage(filepath);
107+
108+
// search for the previous and next image to be displayed
109+
var first_img = "";
110+
var last_img = "";
111+
prev_img = "";
112+
next_img = "";
113+
var img_found = false;
114+
$(".browser-view a").each(function(i, element){
115+
if (isImage(element.pathname)) {
116+
if (first_img === "") first_img = element.pathname;
117+
if (img_found && next_img === "") { next_img = element.pathname; }
118+
if (element.pathname == filepath) img_found = true;
119+
if (!img_found) prev_img = element.pathname;
120+
last_img = element.pathname;
121+
}
122+
});
123+
if (next_img === "") next_img = first_img;
124+
if (prev_img === "") prev_img = last_img;
125+
}
126+
127+
// close the image preview
128+
function closePreview() {
129+
$(".bg-translucent").css('display', 'none');
130+
$(".file-view-wrapper").css('display', 'none');
131+
}
132+
133+
// add various event handlers
134+
$('.file-view-prev').click(function(){
135+
showPreview(prev_img);
136+
});
137+
$('.file-view-next').click(function(){
138+
showPreview(next_img);
139+
});
140+
$("body").keydown(function(event) {
141+
switch (event.which) {
142+
case 27: // ESC
143+
closePreview();
144+
break;
145+
case 37: // left arrow key
146+
showPreview(prev_img);
147+
break;
148+
case 39: // right arrow key
149+
showPreview(next_img);
150+
break;
151+
}
152+
});
153+
$(".bg-translucent").click(closePreview);
154+
$('.base-dir-icon').click(function(){
155+
cd(base_dir);
156+
});
157+
158+
cd(current_dir);
159+
}();

files/.htaccess

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Options +Indexes
2+
IndexOptions -FancyIndexing

files/screenshot.png

782 KB
Loading

index.html

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>Directory listing</title>
8+
<link href="vendor/bootstrap-3.3.6/css/bootstrap.min.css" rel="stylesheet">
9+
<link rel="stylesheet" href="app.css" />
10+
</head>
11+
<body>
12+
<div class="container">
13+
<h1>
14+
<span class="glyphicon glyphicon-tasks base-dir-icon" aria-hidden="true"></span>
15+
<span class="current-dir"></span>
16+
</h1>
17+
<div class="browser-view">
18+
No files to show. :(
19+
</div>
20+
<div class="bg-translucent"></div>
21+
<div class="file-view-wrapper">
22+
<img class="file-view-img">
23+
<img class="file-view-prev" src="prev.png">
24+
<img class="file-view-next" src="next.png">
25+
</div>
26+
</div>
27+
28+
<script src="vendor/jquery-2.2.0.min.js"></script>
29+
<script src="vendor/bootstrap-3.3.6/js/bootstrap.min.js"></script>
30+
<script src="app.js"></script>
31+
</body>
32+
</html>

loader.gif

404 Bytes
Loading

next.png

631 Bytes
Loading

prev.png

574 Bytes
Loading

prev.svg

+35
Loading

0 commit comments

Comments
 (0)