Refactored and lots of modification. See README.md.

This commit is contained in:
Lars Jung 2012-04-16 12:53:54 +02:00
parent 859a680e19
commit 71ed41fa69
85 changed files with 3191 additions and 2969 deletions

View file

@ -1,6 +1,6 @@
# h5ai
Don't use files from this repository (`src` folder) for installation.
Please don't use files from this repository (`src` folder) for installation.
They need to be preprocessed/compiled to work correctly. You'll find a
precompiled package on the [project page](http://larsjung.de/h5ai).
@ -20,6 +20,7 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h
* [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228) (GPL)
* [HTML5 ★ Boilerplate](http://html5boilerplate.com)
* [jQuery](http://jquery.com) (MIT/GPL)
* [jQuery.fracs](http://larsjung.de/fracs) (MIT)
* [jQuery.mousewheel](http://github.com/brandonaaron/jquery-mousewheel) (MIT)
* [modernizr](http://www.modernizr.com) (MIT/BSD)
* [Moment.js](http://momentjs.com) (MIT)
@ -30,20 +31,29 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h
## Changelog
### v0.19 - *2012-??-??*
### v0.19 - *2012-04-??*
* adds lots of config options
* changes in `config.js` and `h5ai.htaccess`
* fixes js problems in IE 7+8
* hides broken tree view in IE < 9 and adds a message to the footer
* disables hash changes since they break logical browser history
* hides broken tree view in IE < 9, adds a message to the footer
* removes hash changes since they break logical browser history
* fixes thumbnail size for portrait images in icon view
* adds an info page at `/_h5ai`
* sort order is preserved while browsing
* removes PHP error messages on thumbnail generation
* fixes PHP problems with zipped download
* changes crumb image for folders with an index file
* adds `index.php` to use h5ai in non-Apache environments
* switches from [Datejs](http://www.datejs.com) to [Moment.js](http://momentjs.com)
* adds [underscore.js](http://underscorejs.org)
* adds a info page to `/_ha5i`
* fixes mousewheel problems, updates [jQuery.mousewheel](http://github.com/brandonaaron/jquery-mousewheel) to 3.0.6
* updates lv translation
* adds ro translation by [Jakob Cosoroabă](http://github.com/midday)
* adds ja translation by [metasta](http://github.com/metasta)
* adds nb translation by [Sindre Sorhus](http://github.com/sindresorhus)
* adds sr translation by [Goran](http://github.com/vBm)
* adds gr translation by [xhmikosr](http://github.com/xhmikosr)
### v0.18 - *2012-02-24*

View file

@ -3,7 +3,7 @@ custom = true
# project
project.name = h5ai
project.version = pre0.19
project.version = 0.19-pre
# src
@ -18,4 +18,5 @@ release.dir = release
# tools
tool.wepp = wepp
tool.jslint = jslint
tool.jshint = jshint

View file

@ -54,6 +54,11 @@
<jslint files="${build.dir}/_h5ai/js/inc/main.js" />
</target>
<target name="hint" depends="build-prepare">
<wepp file="${build.dir}/_h5ai/js/inc/main.js" tofile="${build.dir}/_h5ai/js/inc/main.js" />
<jshint files="${build.dir}/_h5ai/js/inc/main.js" />
</target>
<macrodef name="wepp-args">
<attribute name="args" default="" />
@ -112,4 +117,14 @@
</sequential>
</macrodef>
<macrodef name="jshint">
<attribute name="files" />
<sequential>
<echo>JSHint @{files}</echo>
<exec executable="${tool.jshint}" failonerror="false">
<arg line="@{files}" />
</exec>
</sequential>
</macrodef>
</project>

View file

@ -17,16 +17,17 @@ var H5AI_CONFIG = {
"h5aiAbsHref": "/_h5ai/",
/*
* Filenames of customized header and footer files to look for
* in each folder. For Example:
*
* "customHeader": "_h5ai.header.html",
* "customFooter": "_h5ai.footer.html",
*
* This is disabled by default.
* Spacing of the main content.
* Left and right will be added to a minimum of 30px. Top and bottom
* are calculated relative to the top and bottom bar heights.
*/
"customHeader": null,
"customFooter": null,
"spacing": {
"maxWidth": 960,
"top": 50,
"right": "auto",
"bottom": 50,
"left": "auto"
},
/*
* An array of view modes the user may choose from. Currently there
@ -35,8 +36,102 @@ var H5AI_CONFIG = {
* view mode is fixed and the selector buttons are hidden.
* The user selected view mode is also stored local in modern browsers
* so that it will be persistent.
*
* Set parent folder labels to real folder names.
*/
"viewmodes": ["details", "icons"],
"view": {
"modes": ["details", "icons"],
"setParentFolderLabels": true
},
/*
* Extensions in alphabetical order.
*/
/*
* Show a clickable breadcrumb.
*/
"crumb": {
"enabled": true
},
/*
* Filenames of customized header and footer files to look for
* in each folder.
*/
"custom": {
"enabled": true,
"header": "_h5ai.header.html",
"footer": "_h5ai.footer.html"
},
/*
* Allow filtering the displayed files and folders.
* Note: filters will be treated as JavaScript regular expressions
* if you prefix them with "re:".
*/
"filter": {
"enabled": true
},
/*
* Associative array of folders and their HTTP status codes to
* avoid HEAD requests to that folders. The key (folder) must start
* and end with a slash (/).
* For example
* "/some/folder/": 200
* will always return HTTP status 200 (OK), which will be interpreted
* as a non auto indexed folder, that means a folder containing an
* appropriate default index file.
*/
"folderstatus": {
"enabled": true,
"folders": {}
},
/*
* Localization, for example "en", "de" etc. - see "langs" below for
* possible values. Adjust it to your needs. If lang is not found in
* "langs" it defaults to "en".
*
* Optionally try to use browser language, falls back to previous
* specified language.
*
* Date format in detailed view, for example: "YYYY-MM-DD HH:mm:ss"
* Syntax as specified by Moment.js (http://momentjs.com)
* This might be overidden by "dateFormat" in a lang specification.
*/
"l10n": {
"enabled": true,
"lang": "en",
"useBrowserLang": true,
"defaultDateFormat": "YYYY-MM-DD HH:mm"
},
/*
* Link the hover effects between crumb, main view and tree.
*/
"link-hover-states": {
"enabled": true
},
/*
* Show QRCodes on hovering files.
*/
"qrcode": {
"enabled": true,
"size": 150
},
/*
* Make entries selectable. At the moment only needed for zipped download.
*/
"select": {
"enabled": true
},
/*
* Default sort order is a two letter code. The first letter specifies
@ -44,96 +139,66 @@ var H5AI_CONFIG = {
* second letter specifies the sort order: "a" for "ascending" or "d"
* for "descending".
*/
"sortorder": "na",
"sort": {
"enabled": true,
"order": "na"
},
/*
* Show a folder tree, boolean.
* Note that this tree might have side effects as it sends HEAD requests
* to the folders, and therefore will invoke index.php scripts. Use
* folderStatus below to avoid such requests.
* It might also affect performance significantly.
* Show additional info in a statusbar.
*/
"showTree": true,
/*
* Slide tree bar into viewport if there is enough space, boolean.
*/
"slideTree": true,
/*
* Associative array of folders and their HTTP status codes to
* avoid HEAD requests to that folders. The key (folder) must start
* and end with a slash (/).
* For example:
* "/some/folder/": 200
* will always return HTTP status 200 (OK), which will be interpreted
* as a non auto indexed folder, that means a folder containing an
* appropriate default index file.
*/
"folderStatus": {},
/*
* Localization, for example "en", "de" etc. - see h5aiLangs below for
* possible values. Adjust it to your needs. If lang is not found in
* h5aiLangs it defaults to "en".
*/
"lang": "en",
/*
* Try to use browser language, falls back to previous specified lang.
*/
"useBrowserLang": true,
/*
* Set parent folder labels to real folder names.
*/
"setParentFolderLabels": true,
/*
* Link the hover effects between crumb, extended view and tree.
*/
"linkHoverStates": true,
/*
* Date format in detailed view, for example: "YYYY-MM-DD HH:mm:ss"
* Syntax as specified by Moment.js (http://momentjs.com)
*/
"dateFormat": "YYYY-MM-DD HH:mm",
"statusbar": {
"enabled": true
},
/*
* Requires PHP on the server.
* Show thumbnails for image files.
* Show thumbnails for image files. Needs the "/_h5ai/cache" folder to be
* writable for the Apache Server.
*/
"showThumbs": true,
"thumbTypes": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
"thumbnails": {
"enabled": true,
"types": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
"delay": 1000
},
/*
* Replace window title with current breadcrumb.
*/
"title": {
"enabled": true
},
/*
* Show a folder tree.
* Note that this tree might have side effects as it sends HEAD requests
* to the folders, and therefore will invoke index.php scripts. Use
* "folderstatus" above to avoid such requests.
* It might also affect performance significantly.
*
* Slide tree bar into viewport if there is enough space.
*/
"tree": {
"enabled": true,
"slide": true
},
/*
* Requires PHP on the server.
* Enable zipped download of selected entries.
*/
"zippedDownload": true,
/*
* Show QRCodes on hovering files.
* Set this to the desired size in pixel or null to not display QRCodes.
* A good size to start with might be 150.
*/
"qrCodesSize": 150,
/*
* Allow filtering the displayed files and folders.
* Filters are ment to be JavaScript regular expressions.
*/
"showFilter": true
"zipped-download": {
"enabled": true
}
},
/*
* File types mapped to file extensions.
* File types mapped to file extensions. In alphabetical order.
*/
"types": {
"archive": [".tar.bz2", ".tar.gz", ".tgz"],
"audio": [".aif", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"],
"audio": [".aif", ".flac", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"],
"authors": ["authors"],
"bin": [".class", ".o", ".so"],
"blank": [],
@ -149,7 +214,7 @@ var H5AI_CONFIG = {
"doc": [".doc", ".docx", ".odm", ".odt", ".ott"],
"draw": [".drw"],
"eps": [".eps"],
"exe": [".exe"],
"exe": [".bat", ".cmd", ".exe"],
"folder": [],
"folder-home": [],
"folder-open": [],
@ -171,7 +236,7 @@ var H5AI_CONFIG = {
"package": [],
"pdf": [".pdf"],
"php": [".php"],
"playlist": [".m3u"],
"playlist": [".m3u", ".m3u8", ".pls"],
"png": [".png"],
"pres": [".odp", ".otp", ".pps", ".ppt", ".pptx"],
"psd": [".psd"],
@ -187,18 +252,18 @@ var H5AI_CONFIG = {
"sql": [],
"tar": [".tar"],
"tex": [".tex"],
"text": [".markdown", ".md", ".text", ".txt"],
"text": [".diff", ".markdown", ".md", ".patch", ".text", ".txt"],
"tiff": [".tiff"],
"unknown": [],
"vcal": [".vcal"],
"video": [".avi", ".flv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"],
"video": [".avi", ".flv", ".mkv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"],
"xml": [".xml"],
"zip": [".bz2", ".jar", ".war", ".z", ".Z", ".zip"]
"zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"]
},
/*
* Available translations.
* Available translations. "en" in first place as a reference, otherwise in alphabetical order.
*/
"langs": {
@ -259,7 +324,8 @@ var H5AI_CONFIG = {
"folders": "Ordner",
"files": "Dateien",
"download": "Download",
"noMatch": "keine Treffer"
"noMatch": "keine Treffer",
"dateFormat": "DD.MM.YYYY HH:mm"
},
"es": {
@ -292,6 +358,21 @@ var H5AI_CONFIG = {
"noMatch": "no match"
},
"gr": {
"lang": "ελληνικά",
"details": "Λεπτομέρειες",
"icons": "Εικονίδια",
"name": "Όνομα",
"lastModified": "Τελευταία Τροποποίηση",
"size": "Μέγεθος",
"parentDirectory": "Προηγούμενος Κατάλογος",
"empty": "κενό",
"folders": "Φάκελοι",
"files": "Αρχεία",
"download": "Μεταμόρφωση",
"noMatch": "Κανένα Ταίριασμα"
},
"it": {
"lang": "italiano",
"details": "dettagli",

View file

@ -14,7 +14,7 @@ $H5AI_CONFIG = array(
* This configuration assumes that h5ai is installed
* in the webroot directory of the Apache server.
*/
"ROOT_ABS_PATH" => safe_dirname(safe_dirname(__FILE__)),
"ROOT_ABS_PATH" => dirname(dirname(__FILE__)),
/*
* Files/folders that should not be listed. Specified

View file

@ -1,33 +1,32 @@
#table {
#data-apache-autoindex {
max-width: 960px;
margin: 0 auto;
table {
display: block;
width: 100%;
border-collapse: collapse;
th, td {
padding: 3px 6px;
padding: 6px;
text-align: left;
border: none;
}
th {
padding-bottom: 18px;
opacity: 0.4;
.transition(all 0.2s ease-in-out);
&:hover, &:hover a {
color: #555;
cursor: pointer;
opacity: 0.9;
}
a, a:visited {
color: #555;
font-weight: normal;
text-decoration: none;
cursor: pointer;
opacity: 0.4;
.transition(all 0.2s ease-in-out);
img {
width: 12px;
height: 12px;
padding: 0 8px;
&:hover {
color: #555;
opacity: 0.9;
}
}
}
@ -35,6 +34,19 @@
border: 1px solid #ddd;
border-left: none;
border-right: none;
overflow: hidden;
white-space: nowrap;
a, a:active, a:visited {
display: block;
color: #555;
text-decoration: none;
cursor: pointer;
&:hover {
color: #e80;
}
}
}
td:nth-child(1), th:nth-child(1) {
text-align: center;
@ -43,26 +55,23 @@
img {
width: 16px;
height: 16px;
padding-top: 2px;
position: relative;
top: -2px;
}
}
td:nth-child(2), th:nth-child(2) {
width: 682px;
max-width: 682px;
overflow: hidden;
white-space: nowrap;
}
td:nth-child(3), th:nth-child(3) {
text-align: right;
width: 160px;
min-width: 160px;
white-space: nowrap;
}
td:nth-child(4), th:nth-child(4) {
text-align: right;
width: 70px;
min-width: 70px;
white-space: nowrap;
}
}
}

View file

@ -0,0 +1,68 @@
#bottombar {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
bottom: 0;
padding: 6px 0 8px 0;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-top: 1px solid rgb(210,210,210);
color: #999;
font-size: @smaller-font;
text-align: center;
a, a:active, a:visited {
color: #555;
text-decoration: none;
.transition(all 0.2s ease-in-out);
opacity: 0.7;
&:hover {
color: #e80;
opacity: 1;
}
}
.left {
display: block;
padding: 0 8px;
float: left
}
.center {
display: block;
margin: 0 100px;
}
.right {
display: block;
padding: 0 8px;
float: right
}
.noJsMsg {
color: #c33;
margin-left: 16px;
}
.oldBrowser {
display: none;
color: #c33;
margin-left: 16px;
a, a:active, a:visited {
color: #c33;
text-decoration: underline;
&:hover {
color: #e80;
}
}
}
.status {
.sep {
display: inline-block;
padding: 0 6px;
}
&.default {
}
&.dynamic {
display: none;
}
}
}

View file

@ -1,18 +1,30 @@
#content {
max-width: 960px;
margin: 0 auto;
margin: 50px auto;
}
> header {
display: none;
padding-bottom: 10px;
margin-bottom: 80px;
border-bottom: 2px dashed #ddd;
}
> footer {
display: none;
padding-top: 10px;
margin-top: 80px;
border-top: 2px dashed #ddd;
#content-header, #content-footer {
a, a:active, a:visited {
color: #2080FF;
text-decoration: none;
cursor: pointer;
&:hover {
color: #68A9FF;
}
}
}
#content-header {
padding-bottom: 12px;
margin-bottom: 32px;
}
#content-footer {
padding-top: 12px;
margin-top: 32px;
}

View file

@ -54,10 +54,10 @@
background-color: #f6f6f6;
color: #e80;
}
&.selected:not(.selecting), &.selecting:not(.selected) {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
}
&.selected:not(.selecting) a, &.selecting:not(.selected) a {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
&.error {
a, a:active, a:visited {
@ -102,7 +102,7 @@
width: 16px;
height: 16px;
&.thumb {
border: 1px solid #eee;
// border: 1px solid #ddd;
}
}
}
@ -132,18 +132,6 @@
width: 80px;
white-space: nowrap;
}
&.entry.thumb .icon.small {
overflow: hidden;
padding: 5px;
img {
background-color: #eee;
width: 16px;
height: 16px;
border: 1px solid #ddd;
overflow: hidden;
}
}
}
}
.empty, .no-match {
@ -206,10 +194,6 @@
border-color: #eee;
background-color: #f6f6f6;
}
&.selected:not(.selecting), &.selecting:not(.selected) {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
.icon {
display: block;
@ -218,7 +202,7 @@
height: 48px;
margin-bottom: 8px;
&.thumb {
border: 1px solid #eee;
// border: 1px solid #ddd;
}
}
}
@ -233,6 +217,10 @@
display: none;
}
}
&.selected:not(.selecting) a, &.selecting:not(.selected) a {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
&.error {
a, a:active, a:visited {
color: #aaa;
@ -253,21 +241,6 @@
}
}
}
&.entry.thumb .icon.big {
width: 100px;
height: 58px;
overflow: hidden;
img {
background-color: #eee;
min-width: 46px;
min-height: 46px;
min-width: 12px;
min-height: 12px;
border: 1px solid #ddd;
overflow: hidden;
}
}
}
}
.empty, .no-match {

View file

@ -1,120 +0,0 @@
body > footer {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
bottom: 0;
padding: 6px 0 8px 0;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-top: 1px solid rgb(210,210,210);
color: #999;
font-size: 0.85em;
text-align: center;
a, a:active, a:visited {
color: #555;
text-decoration: none;
.transition(all 0.2s ease-in-out);
opacity: 0.7;
&:hover {
color: #e80;
opacity: 1;
}
}
.left {
display: block;
padding: 0 8px;
float: left
}
.center {
display: block;
margin: 0 100px;
}
.right {
display: block;
padding: 0 8px;
float: right
}
.noJsMsg {
color: #c33;
margin-left: 16px;
}
.oldBrowser {
display: none;
color: #c33;
margin-left: 16px;
a, a:active, a:visited {
color: #c33;
text-decoration: underline;
&:hover {
color: #e80;
}
}
}
.status {
.sep {
display: inline-block;
padding: 0 6px;
}
&.default {
}
&.dynamic {
display: none;
}
}
#langSelector {
position: relative;
cursor: pointer;
.langOptions {
position: absolute;
z-index: 2;
overflow: auto;
display: none;
right: 0;
top: 0;
max-height: 200px;
background-color: rgb(241,241,241);
border: 1px solid rgb(210,210,210);
> .scrollbar {
margin: 0;
width: 6px;
background-color: rgb(210,210,210);
.drag {
background-color: rgb(180,180,180);
}
&.dragOn .drag {
background-color: rgb(150,150,150);
}
}
ul {
margin: 0;
padding: 0;
list-style: none;
text-align: left;
li {
padding: 8px 24px 10px 24px;
white-space: nowrap;
border-top: 1px solid rgb(231,231,231);
.transition(all 0.2s ease-in-out);
&.current {
color: #333;
background-color: rgba(255,255,255,0.8);
}
&:hover {
color: #e80;
background-color: rgba(255,255,255,0.8);
}
}
}
}
}
}

View file

@ -0,0 +1,59 @@
body#h5ai-info {
font-family: Ubuntu, Arial, sans;
margin: 0 auto;
font-size: 20px;
color: #555;
max-width: 600px;
text-align: center;
.h5ai {
font-family: 'Miltonian Tattoo';
font-weight: normal;
}
h1 {
font-size: 3.6em;
margin: 0.9em 0 0 0;
}
h2 {
font-size: 1.15em;
margin: 2.6em 0 0 0;
}
p {
line-height: 1.6em;
}
p + p {
margin-top: 1.2em;
}
li {
margin-top: 0.6em;
line-height: 1.4em;
}
#tests {
display: inline-block;
list-style-type: none;
text-align: left;
margin: 0;
padding: 0;
.test-label {
display: inline-block;
width: 300px;
}
.test-result {
display: inline-block;
width: 70px;
text-align: right;
font-weight: bold;
color: #aaa;
&.test-passed {
color: #5a5;
}
&.test-failed {
color: #a55;
}
}
}
}

View file

@ -0,0 +1,53 @@
#langSelector {
position: relative;
cursor: pointer;
.langOptions {
position: absolute;
z-index: 2;
overflow: auto;
display: none;
right: 0;
top: 0;
max-height: 200px;
background-color: rgb(241,241,241);
border: 1px solid rgb(210,210,210);
> .scrollbar {
margin: 0;
width: 6px;
background-color: rgb(210,210,210);
.drag {
background-color: rgb(180,180,180);
}
&.dragOn .drag {
background-color: rgb(150,150,150);
}
}
ul {
margin: 0;
padding: 0;
list-style: none;
text-align: left;
li {
padding: 8px 24px 10px 24px;
white-space: nowrap;
border-top: 1px solid rgb(231,231,231);
.transition(all 0.2s ease-in-out);
&.current {
color: #333;
background-color: rgba(255,255,255,0.8);
}
&:hover {
color: #e80;
background-color: rgba(255,255,255,0.8);
}
}
}
}
}

View file

@ -1,5 +1,4 @@
.border-radius (@radius) {
-webkit-border-radius: @radius; /* Saf3-4, iOS 1-3.2, Android <1.6 */
-moz-border-radius: @radius; /* FF1-3.6 */
@ -56,4 +55,3 @@
-moz-background-size: @size; /* FF3.6 */
background-size: @size; /* Opera, IE9, Saf5, Chrome, FF4 */
}

View file

@ -1,5 +1,6 @@
@media only screen and (max-width: 500px) {
body > nav {
#topbar {
.view span {
display: none;
}
@ -12,7 +13,7 @@ body > nav {
}
@media only screen and (max-width: 350px) {
body > nav {
#topbar {
.crumb {
display: none;
}
@ -28,7 +29,7 @@ body > nav {
display: none;
}
}
body > footer {
#bottombar {
.center {
display: none;
}
@ -39,18 +40,18 @@ body > footer {
a[href]:after {
content: "";
}
body > nav {
#topbar {
position: static;
margin-bottom: 2em;
.view, #download {
display: none;
}
}
body > footer {
#bottombar {
position: static;
margin-top: 2em;
}
#tree {
display: none !important;
}
}
}

View file

@ -1,59 +0,0 @@
html.h5ai-splash {
body {
font-family: Ubuntu, Arial, sans;
margin: 0 auto;
font-size: 20px;
color: #555;
max-width: 600px;
text-align: center;
.h5ai {
font-family: 'Miltonian Tattoo';
font-weight: normal;
}
h1 {
font-size: 3.6em;
margin: 0.9em 0 0 0;
}
h2 {
font-size: 1.15em;
margin: 2.6em 0 0 0;
}
p {
line-height: 1.6em;
}
p + p {
margin-top: 1.2em;
}
li {
margin-top: 0.6em;
line-height: 1.4em;
}
#tests {
display: inline-block;
list-style-type: none;
text-align: left;
margin: 0;
padding: 0;
.test-label {
display: inline-block;
width: 300px;
}
.test-result {
display: inline-block;
width: 70px;
text-align: right;
font-weight: bold;
&.test-passed {
color: #5a5;
}
&.test-failed {
color: #a55;
}
}
}
}
}

View file

@ -1,4 +1,16 @@
#topbar {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
top: 0;
font-size: @smaller-font;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-bottom: 1px solid rgb(210,210,210);
}
.nav-highlight {
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
@ -21,23 +33,13 @@
border-left: @nav-sep-border;
}
body > nav {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
top: 0;
font-size: 0.85em;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-bottom: 1px solid rgb(210,210,210);
span.jsDisabledFallback {
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: #999;
}
#navbar {
list-style: none;
list-style-image: none;
margin: 0;
padding: 0;
a, a:active, a:visited, span.element {
color: #555;
cursor: pointer;
@ -76,50 +78,54 @@ body > nav {
color: #999;
}
img.hint {
width: 10px;
height: 10px;
width: 14px;
height: 14px;
opacity: 0.8;
}
}
.view {
.nav-right;
}
#download {
}
#filter {
.nav-right;
input {
display: none;
.nav-right;
.transition(all 0.2s ease-in-out);
&.failed {
background-color: rgba(255,0,0,0.5);
}
border: none;
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(0,0,0,0);
width: 100px;
}
#filter {
.nav-right;
&.current {
input {
display: none;
border: none;
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(0,0,0,0);
width: 100px;
}
&.current {
input {
display: inline;
}
display: inline;
}
}
}
#download {
display: none;
.nav-right;
.transition(all 0.2s ease-in-out);
&.failed {
background-color: rgba(255,0,0,0.5);
}
}
#download-auth {
display: none;
position: fixed;
z-index: 5;
left: 0;
top: 0;
font-size: 0.85em;
font-size: @smaller-font;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border: 1px solid rgb(210,210,210);

View file

@ -7,7 +7,7 @@
height: 100%;
z-index: 3;
overflow: auto;
font-size: 0.85em;
font-size: @smaller-font;
padding: 8px;
background-color: rgb(241,241,241);
border-right: 2px solid rgb(221,221,221);
@ -28,20 +28,12 @@
}
.entry {
.blank, .indicator {
.indicator {
display: inline-block;
width: 16px;
height: 25px;
float: left;
}
.indicator {
opacity: 0.7;
.transition(all 0.2s ease-in-out);
cursor: pointer;
&:hover {
opacity: 1;
}
img {
position: relative;
left: 0;
@ -52,13 +44,23 @@
.transition(all 0.2s ease-in-out);
}
&.open {
cursor: pointer;
opacity: 0.7;
img {
.transform(rotate(90deg));
}
}
&.close {
cursor: pointer;
opacity: 0.7;
}
&.unknown {
cursor: pointer;
opacity: 0.3;
}
&.none {
opacity: 0;
}
}
> a, > a:active, > a.visited {
margin-left: 16px;
@ -92,16 +94,8 @@
margin-left: 12px;
font-size: 0.9em;
color: #ccc;
img {
width: 10px;
height: 10px;
vertical-align: baseline;
}
}
}
&.file {
display: none;
}
&.current {
> a, > a:active, > a:visited {
border: 1px solid rgb(221,221,221);

View file

@ -2,63 +2,37 @@
@import "inc/h5bp-norm";
@import "inc/mixins";
::-moz-selection { background: #68A9FF; color: #fff; text-shadow: none; }
::selection { background: #68A9FF; color: #fff; text-shadow: none; }
body {
font-family: Ubuntu, sans-serif;
font-size: 16px;
color: #555;
background-color: #fff;
margin: 80px 30px;
margin: 30px;
}
@import "inc/nav";
@smaller-font: 15px;
@import "inc/topbar";
@import "inc/content";
@import "inc/table";
@import "inc/extended";
@import "inc/bottombar";
@import "inc/l10n";
@import "inc/tree";
@import "inc/context";
@import "inc/footer";
@import "inc/apache-autoindex-table";
@import "inc/responsive";
html.js {
.hideOnJs {
display: none;
}
}
html.no-js {
.hideOnNoJs {
display: none;
}
}
html.h5ai-js {
#h5ai-reference:after {
content: " (js)";
}
}
html.h5ai-php {
#h5ai-reference:after {
content: " (php)";
}
#table {
display: none;
}
#tree, #content > header, #content > footer {
display: block;
}
&.no-js {
#extended.details-view, #extended.icons-view {
display: block;
}
}
html.js .hideOnJs, html.no-js .hideOnNoJs {
display: none;
}
html.oldie {
.oldBrowser {
display: inline;
display: inline !important;
}
#tree {
display: none !important;
@ -66,5 +40,4 @@ html.oldie {
}
@import "inc/splash";
@import "inc/h5ai-info";

View file

@ -1,32 +1,4 @@
<!-- generated code ends here -->
</section>
</section>
<div id="selection-rect"></div>
<footer class="clearfix">
<span class="left">
<a id="h5ai-reference" href="http://larsjung.de/h5ai" target="_blank" title="h5ai project page">h5ai %BUILD_VERSION%</a>
<span class="hideOnJs noJsMsg"> ⚡ JavaScript is disabled! ⚡ </span>
<span class="oldBrowser"> ⚡ Some features disabled! Works best in <a href="http://browsehappy.com" target="_blank">modern browsers</a>. ⚡ </span>
</span>
<span class="right">
<span id="langSelector">
<span class="lang">en</span> - <span class="l10n-lang">english</span>
<span class="langOptions"></span>
</span>
</span>
<span class="center">
<span class="hideOnNoJs">
<span class="status default">
<span class="folderTotal"></span> <span class="l10n-folders">folders</span>
<span class='sep'>·</span>
<span class="fileTotal"></span> <span class="l10n-files">files</span>
</span>
<span class="status dynamic">
</span>
</span>
</span>
</footer>
<script src="/_h5ai/config.js"></script>
<script src="/_h5ai/js/scripts.js"></script>
<!-- generated code ends here -->
</div>
</body>
</html>

11
src/_h5ai/footer.php Normal file
View file

@ -0,0 +1,11 @@
<!-- generated code ends here -->
</div>
<div id="data-generic-json" class="hidden">
<?php if (stripos($_SERVER["REQUEST_METHOD"], "HEAD") === false) {
require_once(str_replace("\\", "/", __DIR__) . "/php/inc/H5ai.php");
$h5ai = new H5ai();
echo $h5ai->getGenericJson();
} ?>
</div>
</body>
</html>

View file

@ -1,34 +1,41 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="h5ai-js no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="h5ai-js no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="h5ai-js no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="h5ai-js no-js" lang="en"> <!--<![endif]-->
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Directory index · styled with h5ai</title>
<meta name="h5ai-version" content="h5ai %BUILD_VERSION% (js)">
<meta name="description" content="Directory index styled with h5ai (http://larsjung.de/h5ai)">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/png" href="/_h5ai/images/h5ai-16x16.png">
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" href="/_h5ai/css/styles.css">
<script src="/_h5ai/js/modernizr.min.js"></script>
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
</head>
<body>
<nav class="clearfix hideOnNoJs">
<body id="h5ai-main">
<div id="topbar" class="clearfix">
<ul id="navbar"></ul>
</nav>
<section id="tree"></section>
<section id="content">
<header></header>
<section id="extended" class="clearfix"></section>
<footer></footer>
<section id="table" class="hideOnJs">
<!--
The following code was generated by Apache's autoindex module. It is not valid HTML5, but this
section gets removed from the DOM tree as soon as its information is parsed. The actual page
should render as valid HTML5, even if the produced source is not valid HTML5.
-->
</div>
<div id="content">
<div id="extended" class="clearfix"></div>
</div>
<div id="bottombar" class="clearfix">
<span class="left">
<a id="h5ai-reference" href="http://larsjung.de/h5ai" title="h5ai project page">h5ai %BUILD_VERSION%</a>
<span class="hideOnJs noJsMsg"> ⚡ JavaScript is disabled! ⚡ </span>
<span class="oldBrowser"> ⚡ Some features disabled! Works best in <a href="http://browsehappy.com">modern browsers</a>. ⚡ </span>
</span>
<span class="right"></span>
<span class="center"></span>
</div>
<script src="/_h5ai/config.js"></script>
<script src="/_h5ai/js/scripts.js"></script>
<div id="data-apache-autoindex" class="hideOnJs">
<!--
The following code was generated by Apache's autoindex module. It is not valid HTML5, but this
section gets removed from the DOM tree as soon as its information is parsed. The actual page
should render as valid HTML5, even if the produced source is not valid HTML5.
-->

View file

@ -1,33 +0,0 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="h5ai-php no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="h5ai-php no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="h5ai-php no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="h5ai-php no-js" lang="en"> <!--<![endif]-->
<?php include "php/main.php"; ?>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title><?php echo $h5ai->getTitle(); ?></title>
<meta name="h5ai-version" content="h5ai %BUILD_VERSION% (php)">
<meta name="description" content="Directory index styled with h5ai (http://larsjung.de/h5ai)">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/png" href="/_h5ai/images/h5ai-16x16.png">
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" href="/_h5ai/css/styles.css">
<script src="/_h5ai/js/modernizr.min.js"></script>
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>
<body>
<nav class="clearfix">
<ul id="navbar">
<?php echo $crumb->toHtml(); ?>
</ul>
</nav>
<?php echo $tree->toHtml(); ?>
<section id="content">
<?php echo $customize->getHeader(); ?>
<?php echo $extended->toHtml(); ?>
<?php echo $customize->getFooter(); ?>
<section id="table" class="hideOnJs">
<!-- The following code was generated by Apache's autoindex module and gets ignored and removed from the DOM tree. -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

After

Width:  |  Height:  |  Size: 564 B

View file

@ -1,32 +1,41 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="h5ai-splash no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="h5ai-splash no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="h5ai-splash no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="h5ai-splash no-js" lang="en"> <!--<![endif]-->
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>h5ai %BUILD_VERSION%</title>
<title>h5ai %BUILD_VERSION% info page</title>
<meta name="description" content="h5ai · a beautified Apache index">
<meta name="author" content="Lars Jung">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/png" href="/_h5ai/images/h5ai-16x16.png">
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Miltonian+Tattoo:regular">
<link rel="stylesheet" href="/_h5ai/css/styles.css">
<script src="/_h5ai/js/modernizr.min.js"></script>
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
</head>
<body>
<body id="h5ai-info">
<h1><span class="h5ai">h5ai</span></h1>
version %BUILD_VERSION%
<h2>server supports</h2>
<ul id="tests">
<li id="test-php"><span class="test-label">php version</span><span class="test-result"></span></li>
<li id="test-zips"><span class="test-label">zipped downloads</span><span class="test-result"></span></li>
<li id="test-thumbs"><span class="test-label">thumbnails</span><span class="test-result"></span></li>
<li id="test-php"><span class="test-label">php version</span><span class="test-result">?</span></li>
<li id="test-cache"><span class="test-label">cache</span><span class="test-result">?</span></li>
<li id="test-thumbs"><span class="test-label">thumbnails</span><span class="test-result">?</span></li>
<li id="test-temp"><span class="test-label">temp directory</span><span class="test-result">?</span></li>
<li id="test-zips"><span class="test-label">zipped downloads</span><span class="test-result">?</span></li>
</ul>
<div id="bottombar" class="clearfix">
<span class="left">
<a id="h5ai-reference" href="http://larsjung.de/h5ai" title="h5ai project page">h5ai %BUILD_VERSION%</a>
<span class="hideOnJs noJsMsg"> ⚡ JavaScript is disabled! ⚡ </span>
<span class="oldBrowser"> ⚡ Some features disabled! Works best in <a href="http://browsehappy.com">modern browsers</a>. ⚡ </span>
</span>
<span class="right"></span>
<span class="center"></span>
</div>
<script src="/_h5ai/config.js"></script>
<script src="/_h5ai/js/scripts.js"></script>
</body>

View file

@ -1,373 +0,0 @@
Module.define('conhtml', [jQuery, 'settings', 'path', 'util', 'core', 'localize'], function ($, settings, pathFactory, util, core, localize) {
var cache = {},
pathnameStatusCache = {},
contentTypeRegEx = /^text\/html;h5ai=/,
getPath = function (folder, tableRow) {
var absHref = util.getAbsHref(folder, tableRow),
path = cache[absHref];
if (!path) {
path = pathFactory.create(folder, tableRow);
if (!path.isParentFolder) {
cache[path.absHref] = path;
}
}
return path;
},
fetchStatus = function (pathname, callback) {
if (settings.folderStatus[pathname]) {
callback(settings.folderStatus[pathname]);
return;
} else if (pathnameStatusCache[pathname]) {
callback(pathnameStatusCache[pathname]);
return;
}
$.ajax({
url: pathname,
type: 'HEAD',
complete: function (xhr) {
var status = xhr.status;
if (status === 200 && contentTypeRegEx.test(xhr.getResponseHeader('Content-Type'))) {
status = 'h5ai';
}
pathnameStatusCache[pathname] = status;
callback(status);
}
});
},
updatePath = function (path) {
if (path.isFolder && !path.isParentFolder && path.status === undefined) {
fetchStatus(path.absHref, function (status) {
if (status !== 'h5ai') {
path.status = status;
}
updateHtml(path);
core.linkHoverStates();
});
}
},
updatePaths = function () {
$.each(cache, function (ref, cached) {
updatePath(cached);
});
},
fetchStatusAndContent = function (pathname, includeParent, callback) {
fetchStatus(pathname, function (status) {
if (status !== 'h5ai') {
callback(status, {});
return;
}
$.ajax({
url: pathname,
type: 'GET',
dataType: 'html',
error: function (xhr) {
callback(xhr.status, {}); // since it was checked before this should never happen
},
success: function (html, status, xhr) {
var content = {};
if (!contentTypeRegEx.test(xhr.getResponseHeader('Content-Type'))) {
callback(xhr.status, {}); // since it was checked before this should never happen
return;
}
$(html).find('#table td').closest('tr').each(function () {
var path = getPath(pathname, this);
if (path.isFolder && (!path.isParentFolder || includeParent)) {
content[path.absHref] = path;
updatePath(path);
}
});
callback('h5ai', content);
}
});
});
};
var onClick = function (path, context) {
},
updateCrumbHtml = function (path) {
var $html, $a;
if (path.html.$crumb && path.html.$crumb.data("status") === path.status) {
return path.html.$crumb;
}
$html = $("<li class='crumb'><a><img alt='>' /><span></span></a></li>")
.addClass(path.isFolder ? "folder" : "file");
if (path.status) {
$html.data("status", path.status);
}
$a = $html.find("a")
.attr("href", path.absHref)
.click(function() { onClick(path, "crumb"); })
.find("img").attr("src", core.image("crumb")).end()
.find("span").text(path.label).end();
if (path.isDomain) {
$html.addClass("domain");
$a.find("img").attr("src", core.image("home"));
}
if (path.isCurrentFolder) {
$html.addClass("current");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$a.append($("<img class='hint' src='" + core.image("page") + "' alt='not listable' />"));
} else {
$a.append($("<span class='hint'>(" + path.status + ")</span>"));
}
}
if (path.html.$crumb) {
path.html.$crumb.replaceWith($html);
}
path.html.$crumb = $html;
return $html;
},
updateExtendedHtml = function (path) {
var $html, $a, $label,
imgClass = "",
icon16 = core.icon(path.type),
icon48 = core.icon(path.type, true);
if (path.html.$extended && path.html.$extended.data("status") === path.status) {
return path.html.$extended;
}
$html = $("<li class='entry' />")
.data("path", path)
.addClass(path.isFolder ? "folder" : "file");
if (path.status) {
$html.data("status", path.status);
}
if (settings.showThumbs === true && $.inArray(path.type, settings.thumbTypes) >= 0) {
imgClass = "class='thumb'";
var escapedHref = path.absHref.replace(/'/g, "%27").replace(/"/g, "%22");
icon16 = core.api() + "?action=thumb&href=" + escapedHref + "&width=16&height=16&mode=square";
icon48 = core.api() + "?action=thumb&href=" + escapedHref + "&width=96&height=46&mode=rational";
}
$label = $("<span class='label'>" + path.label + "</span>");
$a = $("<a />")
.attr("href", path.absHref)
.click(function() { onClick(path, "extended"); })
.appendTo($html)
.append($("<span class='icon small'><img " + imgClass + " src='" + icon16 + "' alt='" + path.type + "' /></span>"))
.append($("<span class='icon big'><img " + imgClass + " src='" + icon48 + "' alt='" + path.type + "' /></span>"))
.append($label)
.append($("<span class='date' data-time='" + path.time + "'></span>"))
.append($("<span class='size' data-bytes='" + path.size + "'></span>"));
$a.hover(
function () {
if ($("#extended").hasClass("icons-view")) {
var $this = $(this);
$(".status.default").hide();
$(".status.dynamic")
.empty()
.append($this.find(".label").clone())
.append($("<span class='sep'>·</span>"))
.append($this.find(".date").clone())
.show();
if (!$this.closest(".entry").hasClass("folder")) {
$(".status.dynamic")
.append($("<span class='sep'>·</span>"))
.append($this.find(".size").clone());
}
}
},
function () {
$(".status.default").show();
$(".status.dynamic").empty().hide();
}
);
if (path.isParentFolder) {
if (!settings.setParentFolderLabels) {
$label.addClass("l10n-parentDirectory");
}
$html.addClass("folder-parent");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$html.addClass("page");
$a.find(".icon.small img").attr("src", core.icon("folder-page"));
$a.find(".icon.big img").attr("src", core.icon("folder-page", true));
} else {
$html.addClass("error");
$label.append($("<span class='hint'> " + path.status + " </span>"));
}
}
if (path.html.$extended) {
path.html.$extended.replaceWith($html);
localize.formatDates();
}
path.html.$extended = $html;
return $html;
},
updateTreeHtml = function (path) {
var $html, $blank, $a, $indicator, $ul, idx;
$html = $("<div class='entry' />")
.data("path", path)
.addClass(path.isFolder ? "folder" : "file");
$blank = $("<span class='blank' />").appendTo($html);
$a = $("<a />")
.attr("href", path.absHref)
.click(function() { onClick(path, "tree"); })
.appendTo($html)
.append($("<span class='icon'><img src='" + core.icon(path.type) + "' /></span>"))
.append($("<span class='label'>" + path.label + "</span>"));
if (path.isFolder) {
// indicator
if (path.status === undefined || !path.isEmpty()) {
$indicator = $("<span class='indicator initiated'><img src='" + core.image("tree") + "' /></span>")
.click(function (event) {
var $entry = $indicator.closest(".entry"); // $html
if ($indicator.hasClass("unknown")) {
fetchStatusAndContent(path.absHref, false, function (status, content) {
path.status = status;
path.content = content;
path.treeOpen = true;
$("#tree").get(0).updateScrollbar(true);
updateTreeHtml(path);
$("#tree").get(0).updateScrollbar();
});
} else if ($indicator.hasClass("open")) {
path.treeOpen = false;
$indicator.removeClass("open");
$("#tree").get(0).updateScrollbar(true);
$entry.find("> ul.content").slideUp(function() {
$("#tree").get(0).updateScrollbar();
});
} else {
path.treeOpen = true;
$indicator.addClass("open");
$("#tree").get(0).updateScrollbar(true);
$entry.find("> ul.content").slideDown(function() {
$("#tree").get(0).updateScrollbar();
});
}
});
if (path.status === undefined) {
$indicator.addClass("unknown");
} else if (path.treeOpen) {
$indicator.addClass("open");
}
$blank.replaceWith($indicator);
}
// is path the domain?
if (path.isDomain) {
$html.addClass("domain");
$a.find(".icon img").attr("src", core.icon("folder-home"));
}
// is path the current folder?
if (path.isCurrentFolder) {
$html.addClass("current");
$a.find(".icon img").attr("src", core.icon("folder-open"));
}
// does it have subfolders?
if (!path.isEmpty()) {
$ul = $("<ul class='content' />").appendTo($html);
$.each(path.content, function (idx, entry) {
$("<li />").append(updateTreeHtml(entry)).appendTo($ul);
});
if (path.status === undefined || !path.treeOpen) {
$ul.hide();
}
}
// reflect folder status
if (!isNaN(path.status)) {
if (path.status === 200) {
$a.find(".icon img").attr("src", core.icon("folder-page"));
$a.append($("<span class='hint'><img src='" + core.image("page") + "' /></span>"));
} else {
$html.addClass("error");
$a.append($("<span class='hint'>" + path.status + "</span>"));
}
}
}
if (path.html.$tree) {
path.html.$tree.replaceWith($html);
}
path.html.$tree = $html;
return $html;
},
updateHtml = function (path) {
updateCrumbHtml(path);
updateExtendedHtml(path);
updateTreeHtml(path);
};
return {
getPath: getPath,
updatePaths: updatePaths,
fetchStatusAndContent: fetchStatusAndContent,
updateCrumbHtml: updateCrumbHtml,
updateExtendedHtml: updateExtendedHtml,
updateTreeHtml: updateTreeHtml,
updateHtml: updateHtml
};
});

View file

@ -1,50 +0,0 @@
Module.define('context', [jQuery, 'settings'], function ($, settings) {
var $context,
qrCodesSize,
showQrCode = function ($a) {
var absHref = $a.attr('href'),
url = 'http://' + document.domain + absHref;
$context.find('.qrcode').empty().qrcode({
render: Modernizr.canvas ? 'canvas' : 'div',
width: qrCodesSize,
height: qrCodesSize,
color: '#333',
text: url
});
},
init = function () {
qrCodesSize = settings.qrCodesSize;
if (!qrCodesSize) {
return;
}
var hideTimeoutId = null;
$context = $('<div id="context"><div class="qrcode"/></div>');
$context.appendTo('body');
$('#extended')
.on('mouseenter', '.entry.file a', function () {
showQrCode($(this));
clearTimeout(hideTimeoutId);
$context.stop(true, true).fadeIn(400);
})
.on('mouseleave', '.entry.file a', function () {
hideTimeoutId = setTimeout(function () {
$context.stop(true, true).fadeOut(400);
}, 200);
});
};
return {
init: init
};
});

View file

@ -1,311 +0,0 @@
Module.define('core', [jQuery, 'settings', 'types', 'util'], function ($, settings, types, util) {
var $window = $(window),
extToFileType = (function (types) {
var map = {};
$.each(types, function (type, exts) {
$.each(exts, function (idx, ext) {
map[ext] = type;
});
});
return map;
}(types)),
hash = function (obj) {
if ($.isPlainObject(obj)) {
var hashStr = '';
$.each($.extend({}, hash(), obj), function (key, value) {
if (value) {
hashStr += '/' + encodeURIComponent(key) + '=' + encodeURIComponent(value);
}
});
hashStr = '#!' + hashStr;
// window.location.hash = hashStr;
return hashStr;
} else {
var result = {},
parts = document.location.hash.split('/');
if (parts.length >= 2 || parts[0] === '#!') {
parts.shift();
$.each(parts, function (idx, part) {
var match = /^([^=]*)=(.*?)$/.exec(part);
if (match) {
result[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
});
}
return typeof obj === 'string' ? result[obj] : result;
}
},
api = function () {
return settings.h5aiAbsHref + "php/api.php";
},
image = function (id, noPngExt) {
return settings.h5aiAbsHref + "images/" + id + (noPngExt ? "" : ".png");
},
icon = function (id, big) {
return settings.h5aiAbsHref + "icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png";
},
viewmode = function (viewmode) {
var $viewDetails = $("#viewdetails"),
$viewIcons = $("#viewicons"),
$extended = $("#extended");
if (viewmode) {
amplify.store(settings.store.viewmode, viewmode);
} else {
viewmode = amplify.store(settings.store.viewmode);
}
viewmode = $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0];
hash({view: viewmode});
$viewDetails.add($viewIcons).removeClass("current");
if (viewmode === "details") {
$viewDetails.addClass("current");
$extended.addClass("details-view").removeClass("icons-view").show();
} else if (viewmode === "icons") {
$viewIcons.addClass("current");
$extended.removeClass("details-view").addClass("icons-view").show();
} else {
$extended.hide();
}
},
initTopSpace = function () {
var $body = $("body"),
$tree = $("#tree"),
adjustTopSpace = function () {
var winHeight = $window.height(),
navHeight = $("body > nav").outerHeight(),
footerHeight = $("body > footer").outerHeight(),
contentSpacing = 50,
treeSpacing = 0;
$body.css({
"margin-top": navHeight + contentSpacing,
"margin-bottom": footerHeight + contentSpacing
});
$tree.css({
top: navHeight + treeSpacing,
height: winHeight - navHeight - footerHeight - 16 - 2 * treeSpacing
});
try {
$tree.get(0).updateScrollbar();
} catch (err) {}
};
$window.resize(function () {
adjustTopSpace();
});
adjustTopSpace();
},
initViews = function () {
var $navbar = $("#navbar"),
$extended = $("#extended");
$("#table").remove();
if (settings.viewmodes.length > 1) {
if ($.inArray("icons", settings.viewmodes) >= 0) {
$("<li id='viewicons' class='view'><a href='#'><img alt='view-icons' /><span class='l10n-icons'>icons</span></a></li>")
.find("img").attr("src", image("view-icons")).end()
.find("a").click(function (event) {
viewmode("icons");
event.preventDefault();
}).end()
.appendTo($navbar);
}
if ($.inArray("details", settings.viewmodes) >= 0) {
$("<li id='viewdetails' class='view'><a href='#'><img alt='view-details' /><span class='l10n-details'>details</span></a></li>")
.find("img").attr("src", image("view-details")).end()
.find("a").click(function (event) {
viewmode("details");
event.preventDefault();
}).end()
.appendTo($navbar);
}
}
// status update
$extended.find(".entry a").hover(
function () {
if ($extended.hasClass("icons-view")) {
var $this = $(this);
$(".status.default").hide();
$(".status.dynamic")
.empty()
.append($this.find(".label").clone())
.append($("<span class='sep'>·</span>"))
.append($this.find(".date").clone())
.show();
if (!$this.closest(".entry").hasClass("folder")) {
$(".status.dynamic")
.append($("<span class='sep'>·</span>"))
.append($this.find(".size").clone());
}
}
},
function () {
$(".status.default").show();
$(".status.dynamic").empty().hide();
}
);
},
shiftTree = function (forceVisible, dontAnimate) {
var $tree = $("#tree"),
$extended = $("#extended");
if ((settings.slideTree && $tree.outerWidth() < $extended.offset().left) || forceVisible) {
if (dontAnimate) {
$tree.stop().css({ left: 0 });
} else {
$tree.stop().animate({ left: 0 });
}
} else {
if (dontAnimate) {
$tree.stop().css({ left: 18 - $tree.outerWidth() });
} else {
$tree.stop().animate({ left: 18 - $tree.outerWidth() });
}
}
},
initTree = function () {
$("#tree").hover(
function () { shiftTree(true); },
function () { shiftTree(); }
);
$window.resize(function () { shiftTree(); });
shiftTree(false, true);
},
selectLinks = function (href) {
var elements = [];
$("a[href^='/']").each(function () {
if ($(this).attr("href") === href) {
elements.push(this);
}
});
return $(elements);
},
linkHoverStates = function () {
if (settings.linkHoverStates) {
$("a[href^='/']:not(.linkedHoverStates)").each(function () {
var $a = $(this).addClass("linkedHoverStates"),
href = $a.attr("href");
$a.hover(
function () { selectLinks(href).addClass("hover"); },
function () { selectLinks(href).removeClass("hover"); }
);
});
}
},
onIndicatorClick = function (event) {
var $indicator = $(this),
$entry = $indicator.closest(".entry"),
updateTreeScrollbar = $("#tree").get(0).updateScrollbar;
if ($indicator.hasClass("unknown")) {
$.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) {
var $content = $(html);
$indicator.removeClass("unknown");
if ($content.find("> li").size() === 0) {
$indicator.replaceWith($("<span class='blank' />"));
} else {
$indicator.addClass("open");
$entry.find("> .content").replaceWith($content);
updateTreeScrollbar();
$content.find(".indicator:not(.initiated)")
.click(onIndicatorClick)
.addClass("initiated");
}
});
} else if ($indicator.hasClass("open")) {
$indicator.removeClass("open");
updateTreeScrollbar(true);
$entry.find("> .content").slideUp(function () {
updateTreeScrollbar();
});
} else {
$indicator.addClass("open");
updateTreeScrollbar(true);
$entry.find("> .content").slideDown(function () {
updateTreeScrollbar();
});
}
},
initIndicators = function () {
$("#tree .entry.folder .indicator:not(.initiated)")
.click(onIndicatorClick)
.addClass("initiated");
},
getFileType = function (filename) {
var dotidx = filename.lastIndexOf('.'),
ext = dotidx >= 0 ? filename.substr(dotidx) : filename;
return extToFileType[ext.toLowerCase()] || "unknown";
},
formatSizes = function () {
$("#extended .entry .size").each(function () {
var $this = $(this),
bytes = $this.data("bytes"),
formattedSize = bytes >= 0 ? util.formatSize(bytes) : "";
$this.text(formattedSize);
});
},
setTotals = function () {
var $extended = $("#extended");
$(".folderTotal").text($extended.find(".entry.folder:not(.folder-parent)").length);
$(".fileTotal").text($extended.find(".entry.file").length);
},
init = function () {
initViews();
viewmode();
initTopSpace();
initTree();
linkHoverStates();
formatSizes();
setTotals();
initIndicators();
};
return {
init: init,
hash: hash,
api: api,
image: image,
icon: icon,
shiftTree: shiftTree,
linkHoverStates: linkHoverStates,
initIndicators: initIndicators,
getFileType: getFileType
};
});

View file

@ -0,0 +1,16 @@
module.define('core/entry', [jQuery, 'core/parser', 'model/entry'], function ($, parser, Entry) {
var absHref = document.location.pathname;
parser.parse(absHref, $('body'));
$('#data-apache-autoindex').remove();
var entry = Entry.get(absHref);
entry.status = 'h5ai';
if (entry.parent) {
entry.parent.isParentFolder = true;
}
return entry;
});

View file

@ -0,0 +1,25 @@
module.define('core/event', [amplify], function (amplify) {
var sub = function (topic, callback) {
amplify.subscribe(topic, callback);
},
unsub = function (topic, callback) {
amplify.unsubscribe(topic, callback);
},
pub = function (topic, data) {
// console.log('EVENT PUB', topic, data);
amplify.publish(topic, data);
};
return {
sub: sub,
unsub: unsub,
pub: pub
};
});

View file

@ -0,0 +1,80 @@
module.define('core/format', [moment], function (moment) {
var reParseSize = /^\s*([\.\d]+)\s*([kmgt]?)b?\s*$/i,
treshhold = 1000.0,
kilo = 1000.0,
sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB'],
parseSize = function (str) {
var match = reParseSize.exec(str),
val, unit;
if (!match) {
return null;
}
val = parseFloat(match[1]);
unit = match[2].toLowerCase();
if (unit === 'k') {
val *= kilo;
} else if (unit === 'm') {
val *= kilo * kilo;
} else if (unit === 'g') {
val *= kilo * kilo * kilo;
} else if (unit === 't') {
val *= kilo * kilo * kilo * kilo;
}
return val;
},
formatSize = function (size) {
if (!_.isNumber(size) || size < 0) {
return '';
}
var i = 0,
maxI = sizeUnits.length - 1;
while (size >= treshhold && i < maxI) {
size /= kilo;
i += 1;
}
return (i <= 1 ? Math.round(size) : size.toFixed(1)).toString() + ' ' + sizeUnits[i];
},
defaultDateFormat = 'YYYY-MM-DD HH:mm',
setDefaultDateFormat = function (dateFormat) {
defaultDateFormat = dateFormat;
},
parseDate = function (str, dateFormat) {
try { // problems with ie < 9 :(
return moment(str, dateFormat || defaultDateFormat).valueOf() || null;
} catch (err) {}
return Date.parse(str).valueOf() || null;
},
formatDate = function (millis, dateFormat) {
if (!_.isNumber(millis) || !millis) {
return '';
}
return moment(millis).format(dateFormat || defaultDateFormat);
};
return {
parseSize: parseSize,
formatSize: formatSize,
setDefaultDateFormat: setDefaultDateFormat,
parseDate: parseDate,
formatDate: formatDate
};
});

View file

@ -0,0 +1,9 @@
module.define('core/parser', [jQuery], function ($) {
if ($('#data-generic-json').length) {
return module.require('parser/generic-json');
}
return module.require('parser/apache-autoindex');
});

View file

@ -0,0 +1,22 @@
module.define('core/resource', ['core/settings'], function (settings) {
var api = function () {
return settings.h5aiAbsHref + 'php/api.php';
},
image = function (id, noPngExt) {
return settings.h5aiAbsHref + 'images/' + id + (noPngExt ? '' : '.png');
},
icon = function (id, big) {
return settings.h5aiAbsHref + 'icons/' + (big ? '48x48' : '16x16') + '/' + id + '.png';
};
return {
api: api,
image: image,
icon: icon
};
});

View file

@ -0,0 +1,32 @@
module.define('core/config', [H5AI_CONFIG], function (config) {
var defaults = {
rootAbsHref: '/',
h5aiAbsHref: '/_h5ai/',
};
return {
settings: _.extend({}, defaults, config.options),
types: _.extend({}, config.types),
langs: _.extend({}, config.langs)
};
});
module.define('core/settings', ['core/config'], function (config) {
return config.settings;
});
module.define('core/types', ['core/config'], function (config) {
return config.types;
});
module.define('core/langs', ['core/config'], function (config) {
return config.langs;
});

View file

@ -0,0 +1,18 @@
module.define('core/store', [amplify], function (amplify) {
var put = function (key, value) {
amplify.store(key, value);
},
get = function (key) {
return amplify.store(key);
};
return {
put: put,
get: get
};
});

View file

@ -0,0 +1,84 @@
module.define('ext/crumb', [jQuery, 'core/settings', 'core/resource', 'core/entry'], function ($, allsettings, resource, entry) {
var defaults = {
enabled: true
},
settings = _.extend({}, defaults, allsettings.crumb),
template = '<li class="crumb">' +
'<a>' +
'<img src="' + resource.image('crumb') + '" alt=">" />' +
'<span />' +
'</a>' +
'</li>',
pageHintTemplate = '<img class="hint" src="' + resource.image('page') + '" alt="has index page" />',
statusHintTemplate = '<span class="hint"></span>',
// updates the crumb for this single entry
update = function (entry) {
if (entry.$crumb && entry.$crumb.data('status') === entry.status) {
return entry.$crumb;
}
var $html = $(template),
$a = $html.find('a');
$html
.addClass(entry.isFolder() ? 'folder' : 'file')
.data('status', entry.status);
$a
.attr('href', entry.absHref)
.find('span').text(entry.label).end();
if (entry.isDomain()) {
$html.addClass('domain');
$a.find('img').attr('src', resource.image('home'));
}
if (entry.isCurrentFolder()) {
$html.addClass('current');
}
if (_.isNumber(entry.status)) {
if (entry.status === 200) {
$a.append($(pageHintTemplate));
} else {
$a.append($(statusHintTemplate).text('(' + entry.status + ')'));
}
}
if (entry.$crumb) {
entry.$crumb.replaceWith($html);
}
entry.$crumb = $html;
return $html;
},
// creates the complete crumb from entry down to the root
init = function (entry) {
if (!settings.enabled) {
return;
}
var crumb = entry.getCrumb(),
$ul = $('#navbar');
_.each(crumb, function (e) {
$ul.append(update(e));
e.fetchStatus(function (e) {
update(e);
});
});
};
init(entry);
});

View file

@ -0,0 +1,42 @@
module.define('ext/custom', [jQuery, 'core/settings'], function ($, allsettings) {
var defaults = {
enabled: false,
header: '_h5ai.header.html',
footer: '_h5ai.footer.html'
},
settings = _.extend({}, defaults, allsettings.custom),
init = function () {
if (!settings.enabled) {
return;
}
if (_.isString(settings.header)) {
$.ajax({
url: settings.header,
dataType: 'html',
success: function (data) {
$('<div id="content-header">' + data + '</div>').prependTo('#content');
}
});
}
if (_.isString(settings.footer)) {
$.ajax({
url: settings.footer,
dataType: 'html',
success: function (data) {
$('<div id="content-footer">' + data + '</div>').appendTo('#content');
}
});
}
};
init();
});

View file

@ -0,0 +1,123 @@
module.define('ext/filter', [jQuery, 'core/settings', 'core/resource'], function ($, allsettings, resource) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings.filter),
template = '<li id="filter">' +
'<span class="element">' +
'<img src="' + resource.image('filter') + '" alt="filter" />' +
'<input type="text" value="" placeholder="filter" />' +
'</span>' +
'</li>',
noMatchTemplate = '<div class="no-match l10n-noMatch">no match</div>',
$filter, $input, $noMatch,
filter = function (re) {
var match = [],
noMatch = [],
duration = 200;
if (re) {
$('#extended .entry').each(function () {
var label = $(this).find('.label').text();
if (label.match(re)) {
match.push(this);
} else {
noMatch.push(this);
}
});
} else {
match = $('#extended .entry');
}
if ($(match).length) {
$noMatch.hide();
} else {
setTimeout(function () { $noMatch.show(); }, duration);
}
$(match).fadeIn(duration);
$(noMatch).fadeOut(duration);
},
checkState = function (focus) {
var val = $input.val();
if (val || focus) {
$filter.addClass('current');
} else {
$filter.removeClass('current');
}
},
escapeRegExp = function (sequence) {
return sequence.replace(/[\-\[\]{}()*+?.,\\$\^|#\s]/g, '\\$&');
// return sequence.replace(/[|()\[{.+*?^$\\]/g,"\\$0");
},
parseFilterSequence = function (sequence) {
if (sequence.substr(0, 3) === 're:') {
return new RegExp(sequence.substr(3));
}
sequence = $.map($.trim(sequence).split(/\s+/), function (part) {
return escapeRegExp(part);
}).join('|');
return new RegExp(sequence);
},
update = function () {
var val = $input.val();
if (val) {
filter(parseFilterSequence(val));
} else {
filter();
}
checkState($input.is(':focus'));
},
init = function () {
if (!settings.enabled) {
return;
}
$filter = $(template);
$input = $filter.find('input');
$noMatch = $(noMatchTemplate).appendTo($('#extended'));
$filter
.on('click', function () {
$input.focus();
})
.appendTo($('#navbar'));
$input
.on('focus', function () {
checkState(true);
})
.on('blur', function () {
checkState(false);
})
.on('keyup', update);
};
init();
});

View file

@ -0,0 +1,14 @@
module.define('ext/folderstatus', [jQuery, 'core/settings'], function ($, allsettings) {
var defaults = {
enabled: true,
folders: {}
},
settings = _.extend({}, defaults, allsettings.folderstatus),
folders = settings.enabled ? settings.folders : defaults.folders;
return folders;
});

View file

@ -1,26 +1,29 @@
Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, settings, langs, core) {
module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format', 'core/store'], function ($, allsettings, langs, format, store) {
var currentDateFormat = settings.dateFormat,
formatDates = function (dateFormat) {
if (dateFormat) {
currentDateFormat = dateFormat;
}
$('#extended .entry .date').each(function () {
var $this = $(this),
time = $this.data('time'),
formattedDate = time ? moment(time).format(currentDateFormat) : '';
$this.text(formattedDate);
});
var defaults = {
enabled: true,
lang: "en",
useBrowserLang: true,
defaultDateFormat: 'YYYY-MM-DD HH:mm'
},
settings = _.extend({}, defaults, allsettings.l10n),
template = '<span id="langSelector">' +
'<span class="lang">en</span> - <span class="l10n-lang">english</span>' +
'<span class="langOptions"> <ul /> </span>' +
'</span>',
langOptionTemplate = '<li class="langOption" />',
storekey = 'h5ai.language',
currentLang = null,
localize = function (langs, lang, useBrowserLang) {
var storedLang = amplify.store(settings.store.lang),
browserLang, selected, key;
var storedLang = store.get(storekey),
browserLang, key;
if (langs[storedLang]) {
lang = storedLang;
@ -39,38 +42,45 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se
lang = 'en';
}
selected = langs[lang];
if (selected) {
$.each(selected, function (key, value) {
currentLang = langs[lang];
if (currentLang) {
$.each(currentLang, function (key, value) {
$('.l10n-' + key).text(value);
});
$('.lang').text(lang);
$('.langOption').removeClass('current');
$('.langOption.' + lang).addClass('current');
core.hash({lang: lang});
}
formatDates(selected.dateFormat || settings.dateFormat);
format.setDefaultDateFormat(currentLang.dateFormat || settings.defaultDateFormat);
$('#extended .entry .date').each(function () {
var $this = $(this);
$this.text(format.formatDate($this.data('time')));
});
},
initLangSelector = function (langs) {
var $langOptions = $('#langSelector .langOptions'),
sortedLangsKeys = [],
$ul;
var $langSelector = $(template).appendTo('#bottombar .right'),
$langOptions = $langSelector.find('.langOptions'),
$ul = $langOptions.find('ul'),
sortedLangsKeys = [];
$.each(langs, function (lang) {
sortedLangsKeys.push(lang);
});
sortedLangsKeys.sort();
$ul = $('<ul />');
$.each(sortedLangsKeys, function (idx, lang) {
$('<li class="langOption" />')
$(langOptionTemplate)
.addClass(lang)
.text(lang + ' - ' + langs[lang].lang)
.appendTo($ul)
.click(function () {
amplify.store(settings.store.lang, lang);
store.put(storekey, lang);
localize(langs, lang, false);
});
});
@ -78,7 +88,7 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se
.append($ul)
.scrollpanel();
$('#langSelector').hover(
$langSelector.hover(
function () {
$langOptions
.css('top', '-' + $langOptions.outerHeight() + 'px')
@ -93,15 +103,16 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se
}
);
},
init = function () {
if (!settings.enabled) {
return;
}
initLangSelector(langs);
localize(langs, settings.lang, settings.useBrowserLang);
};
return {
init: init,
formatDates: formatDates
};
init();
});

View file

@ -0,0 +1,44 @@
module.define('ext/link-hover-states', [jQuery, 'core/settings'], function ($, allsettings) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings['link-hover-states']),
selector = "a[href^='/']",
selectLinks = function (href) {
return $(_.filter($(selector), function (el) {
return $(el).attr('href') === href;
}));
},
onMouseEnter = function () {
var href = $(this).attr('href');
selectLinks(href).addClass('hover');
},
onMouseLeave = function () {
var href = $(this).attr('href');
selectLinks(href).removeClass('hover');
},
init = function () {
if (settings.enabled) {
$('body')
.on('mouseenter', selector, onMouseEnter)
.on('mouseleave', selector, onMouseLeave);
}
};
init();
});

View file

@ -0,0 +1,56 @@
module.define('ext/qrcode', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) {
var defaults = {
enabled: false,
size: 150
},
settings = _.extend({}, defaults, allsettings.qrcode),
template = '<div id="context"><div class="qrcode" /></div>',
$context, hideTimeoutId,
update = function (entry) {
$context.find('.qrcode').empty().qrcode({
render: Modernizr.canvas ? 'canvas' : 'div',
width: settings.size,
height: settings.size,
color: '#333',
text: 'http://' + document.domain + entry.absHref
});
},
onMouseenter = function (entry) {
if (!entry.isFolder()) {
update(entry);
clearTimeout(hideTimeoutId);
$context.stop(true, true).fadeIn(400);
}
},
onMouseleave = function (entry) {
hideTimeoutId = setTimeout(function () {
$context.stop(true, true).fadeOut(400);
}, 200);
},
init = function () {
if (!settings.enabled) {
return;
}
$context = $(template).appendTo('body');
event.sub('entry.mouseenter', onMouseenter);
event.sub('entry.mouseleave', onMouseleave);
};
init();
});

View file

@ -0,0 +1,114 @@
module.define('ext/select', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings.select),
x = 0,
y = 0,
$document = $(document),
$selectionRect = $('<div id="selection-rect"></div>'),
publish = function () {
var entries = _.map($('#extended .entry.selected'), function (entryElement) {
return $(entryElement).data('entry');
});
event.pub('selection', entries);
},
selectionUpdate = function (event) {
var l = Math.min(x, event.pageX),
t = Math.min(y, event.pageY),
w = Math.abs(x - event.pageX),
h = Math.abs(y - event.pageY),
selRect;
event.preventDefault();
$selectionRect.css({left: l, top: t, width: w, height: h});
selRect = $selectionRect.fracs('rect');
$('#extended .entry').removeClass('selecting').each(function () {
var $entry = $(this),
rect = $entry.find('a').fracs('rect'),
inter = selRect.intersection(rect);
if (inter && !$entry.hasClass('folder-parent')) {
$entry.addClass('selecting');
}
});
},
selectionEnd = function (event) {
event.preventDefault();
$document.off('mousemove', selectionUpdate);
$selectionRect.hide().css({left: 0, top: 0, width: 0, height: 0});
$('#extended .entry.selecting.selected').removeClass('selecting').removeClass('selected');
$('#extended .entry.selecting').removeClass('selecting').addClass('selected');
publish();
},
selectionStart = function (event) {
var view = $(document).fracs('viewport');
x = event.pageX;
y = event.pageY;
// only on left button and don't block the scrollbars
if (event.button !== 0 || x >= view.right || y >= view.bottom) {
return;
}
event.preventDefault();
$(':focus').blur();
if (!event.ctrlKey) {
$('#extended .entry').removeClass('selected');
publish();
}
$selectionRect.show().css({left: x, top: y, width: 0, height: 0});
$document
.on('mousemove', selectionUpdate)
.one('mouseup', selectionEnd);
},
noSelection = function (event) {
event.stopImmediatePropagation();
return false;
},
noSelectionUnlessCtrl = function (event) {
if (!event.ctrlKey) {
noSelection(event);
}
},
init = function () {
if (!settings.enabled) {
return;
}
$selectionRect.hide().appendTo($('body'));
// $('#topbar,#bottombar,#tree,input').on('mousedown', noSelection);
// $('#content').on('mousedown', 'a', noSelectionUnlessCtrl);
// $document.on('mousedown', selectionStart);
$document
.on('mousedown', '.noSelection', noSelection)
.on('mousedown', '.noSelectionUnlessCtrl,input,a', noSelectionUnlessCtrl)
.on('mousedown', selectionStart);
};
init();
});

View file

@ -1,7 +1,16 @@
Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core) {
module.define('ext/sort', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) {
var type = function (entry) {
var defaults = {
enabled: false,
order: 'na'
},
settings = _.extend({}, defaults, allsettings.sort),
storekey = 'h5ai.sortorder',
type = function (entry) {
var $entry = $(entry);
@ -54,17 +63,21 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core)
var order = orders[id];
store.put(storekey, id);
$all.removeClass('ascending').removeClass('descending');
order.head.addClass(order.clas);
$('#extended .entry').detach().sort(order.fn).appendTo($('#extended > ul'));
core.hash({sort: id});
},
init = function () {
var $ascending = $('<img src="' + core.image('ascending') + '" class="sort ascending" alt="ascending" />'),
$descending = $('<img src="' + core.image('descending') + '" class="sort descending" alt="descending" />'),
initialOrder = core.hash('sort'),
if (!settings.enabled) {
return;
}
var $ascending = $('<img src="' + resource.image('ascending') + '" class="sort ascending" alt="ascending" />'),
$descending = $('<img src="' + resource.image('descending') + '" class="sort descending" alt="descending" />'),
$header = $('#extended li.header'),
$label = $header.find('a.label'),
$date = $header.find('a.date'),
@ -104,7 +117,7 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core)
}
};
sortBy(initialOrder || settings.sortorder);
sortBy(store.get(storekey) || settings.order);
$label
.append($ascending.clone()).append($descending.clone())
@ -128,7 +141,5 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core)
});
};
return {
init: init
};
init();
});

View file

@ -0,0 +1,76 @@
module.define('ext/statusbar', [jQuery, 'core/settings', 'core/format', 'core/event', 'core/entry'], function ($, allsettings, format, event, entry) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings.statusbar),
template = '<span class="statusbar">' +
'<span class="status default">' +
'<span class="folderTotal"></span> <span class="l10n-folders">folders</span>' +
'<span class="sep">·</span>' +
'<span class="fileTotal"></span> <span class="l10n-files">files</span>' +
'</span>' +
'<span class="status dynamic"></span>' +
'</span>',
sepTemplate = '<span class="sep">·</span>',
$statusDynamic,
$statusDefault,
update = function (html) {
if (html) {
$statusDefault.hide();
$statusDynamic.empty().append(html).show();
} else {
$statusDynamic.empty().hide();
$statusDefault.show();
}
},
init = function (entry) {
if (!settings.enabled) {
return;
}
var $statusbar = $(template),
$folderTotal = $statusbar.find('.folderTotal'),
$fileTotal = $statusbar.find('.fileTotal');
$statusDefault = $statusbar.find('.status.default');
$statusDynamic = $statusbar.find('.status.dynamic');
var stats = entry.getStats();
$folderTotal.text(stats.folders);
$fileTotal.text(stats.files);
update();
event.sub('statusbar', update);
$('#bottombar > .center').append($statusbar);
event.sub('entry.mouseenter', function (entry) {
var $span = $('<span/>').append(entry.label).append(sepTemplate).append(format.formatDate(entry.time));
if (!entry.isFolder()) {
$span.append(sepTemplate).append(format.formatSize(entry.size));
}
update($span);
});
event.sub('entry.mouseleave', function (entry) {
update();
});
};
init(entry);
});

View file

@ -0,0 +1,59 @@
module.define('ext/thumbnails', [jQuery, 'core/settings', 'core/resource', 'core/entry'], function ($, allsettings, resource, entry) {
var defaults = {
enabled: false,
types: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
delay: 1000
},
settings = _.extend({}, defaults, allsettings.thumbnails),
requestThumb = function ($img, data) {
$.getJSON(resource.api(), data, function (json) {
if (json.code === 0) {
$img.addClass('thumb').attr('src', json.absHref);
}
});
},
checkEntry = function (entry) {
if (entry.$extended && $.inArray(entry.type, settings.types) >= 0) {
var $imgSmall = entry.$extended.find('.icon.small img');
var $imgBig = entry.$extended.find('.icon.big img');
requestThumb($imgSmall, {
action: 'thumbsrc',
href: entry.absHref,
width: 16,
height: 16,
mode: 'square'
});
requestThumb($imgBig, {
action: 'thumbsrc',
href: entry.absHref,
width: 100,
height: 48,
mode: 'rational'
});
}
},
init = function (entry) {
if (!settings.enabled) {
return;
}
setTimeout(function () {
_.each(entry.content, checkEntry);
}, settings.delay);
};
init(entry);
});

View file

@ -0,0 +1,27 @@
module.define('ext/title', [jQuery, 'core/settings', 'core/entry'], function ($, allsettings, entry) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings.title),
init = function (entry) {
if (!settings.enabled) {
return;
}
var labels = _.pluck(entry.getCrumb(), 'label'),
title = labels.join(' > ');
if (labels.length > 1) {
title = labels[labels.length - 1] + ' - ' + title;
}
document.title = title;
};
init(entry);
});

View file

@ -0,0 +1,227 @@
module.define('ext/tree', [jQuery, 'core/settings', 'core/resource', 'core/event', 'core/entry', 'core/parser'], function ($, allsettings, resource, event, entry, parser) {
var defaults = {
enabled: false,
slide: true
},
settings = _.extend({}, defaults, allsettings.tree),
template = '<div class="entry">' +
'<span class="indicator none">' +
'<img src="' + resource.image('tree') + '" />' +
'</span>' +
'<a>' +
'<span class="icon"><img /></span>' +
'<span class="label"></span>' +
'</a>' +
'</span>',
statusHintTemplate = '<span class="hint"></span>',
// updates the tree for this single entry
update = function (entry) {
var $html = $(template),
$indicator = $html.find('.indicator'),
$a = $html.find('a'),
$img = $html.find('.icon img'),
$label = $html.find('.label');
$html
.addClass(entry.isFolder() ? 'folder' : 'file')
.data('entry', entry)
.data('status', entry.status);
$a.attr('href', entry.absHref);
$img.attr('src', resource.icon(entry.type));
$label.text(entry.label);
if (entry.isFolder()) {
var subfolders = entry.getSubfolders();
// indicator
if (!entry.status || (entry.status === 'h5ai' && !entry.isContentFetched) || subfolders.length) {
$indicator.removeClass('none');
if (!entry.status || (entry.status === 'h5ai' && !entry.isContentFetched)) {
$indicator.addClass('unknown');
} else if (entry.isContentVisible) {
$indicator.addClass('open');
} else {
$indicator.addClass('close');
}
}
// is it the domain?
if (entry.isDomain()) {
$html.addClass('domain');
$img.attr('src', resource.icon('folder-home'));
}
// is it the current folder?
if (entry.isCurrentFolder()) {
$html.addClass('current');
$img.attr('src', resource.icon('folder-open'));
}
// does it have subfolders?
if (subfolders.length) {
var $ul = $('<ul class="content" />').appendTo($html);
_.each(subfolders, function (e) {
$('<li />').append(update(e)).appendTo($ul);
});
if (!entry.isContentVisible) {
$ul.hide();
}
}
// reflect folder status
if (_.isNumber(entry.status)) {
if (entry.status === 200) {
$img.attr('src', resource.icon('folder-page'));
} else {
$html.addClass('error');
$a.append($(statusHintTemplate).text(entry.status));
}
}
}
if (entry.$tree) {
entry.$tree.replaceWith($html);
}
entry.$tree = $html;
return $html;
},
createOnIndicatorClick = function (parser) {
var $tree = $('#tree'),
tree = $tree.get(0),
slide = function (entry, $indicator, $content, down) {
entry.isContentVisible = down;
$indicator.removeClass('open close').addClass(down ? 'open' : 'close');
tree.updateScrollbar(true);
$content[down ? 'slideDown' : 'slideUp'](function () {
tree.updateScrollbar();
});
};
return function () {
var $indicator = $(this),
$entry = $indicator.closest('.entry'),
entry = $entry.data('entry'),
$content = $entry.find('> ul.content');
if ($indicator.hasClass('unknown')) {
entry.fetchContent(parser, function (entry) {
entry.isContentVisible = false;
var $entry = update(entry),
$indicator = $entry.find('> .indicator'),
$content = $entry.find('> ul.content');
if (!$indicator.hasClass('none')) {
slide(entry, $indicator, $content, true);
}
});
} else if ($indicator.hasClass('open')) {
slide(entry, $indicator, $content, false);
} else if ($indicator.hasClass('close')) {
slide(entry, $indicator, $content, true);
}
};
},
shiftTree = function (forceVisible, dontAnimate) {
var $tree = $("#tree"),
$extended = $("#extended"),
left = ((settings.slide && $tree.outerWidth() < $extended.offset().left) || forceVisible || !$extended.is(':visible')) ? 0 : 18 - $tree.outerWidth();
if (dontAnimate) {
$tree.stop().css({ left: left });
} else {
$tree.stop().animate({ left: left });
}
},
fetchTree = function (entry, parser, callback) {
entry.isContentVisible = true;
entry.fetchContent(parser, function (entry) {
if (entry.parent) {
fetchTree(entry.parent, parser, callback);
} else {
callback(entry);
}
});
},
adjustSpacing = function () {
var $tree = $('#tree'),
tree = $tree[0],
winHeight = $(window).height(),
navHeight = $('#topbar').outerHeight(),
footerHeight = $('#bottombar').outerHeight();
$tree.css({
top: navHeight,
height: winHeight - navHeight - footerHeight - 16
});
if (tree.updateScrollbar) {
tree.updateScrollbar();
}
},
// creates the complete tree from entry down to the root
init = function (entry, parser) {
if (!settings.enabled) {
return;
}
var $tree = $('<div id="tree" />').appendTo($('body'));
fetchTree(entry, parser, function (root) {
$tree
.append(update(root))
.scrollpanel()
.show();
adjustSpacing();
shiftTree(false, true);
setTimeout(function () { $tree.get(0).updateScrollbar(); }, 1);
});
$tree
.on('click', '.indicator', createOnIndicatorClick(parser))
.on('mouseenter', function () { shiftTree(true); })
.on('mouseleave', function () { shiftTree(); });
event.sub('ready', adjustSpacing);
$(window).on('resize', function () {
adjustSpacing();
shiftTree();
});
};
init(entry, parser);
});

View file

@ -0,0 +1,133 @@
module.define('ext/zipped-download', [jQuery, 'core/settings', 'core/resource', 'core/event'], function ($, allsettings, resource, event) {
var defaults = {
enabled: false
},
settings = _.extend({}, defaults, allsettings['zipped-download']),
downloadBtnTemplate = '<li id="download">' +
'<a href="#">' +
'<img src="' + resource.image('download') + '" alt="download" />' +
'<span class="l10n-download">download</span>' +
'</a>' +
'</li>',
authTemplate = '<div id="download-auth">' +
'<input id="download-auth-user" type="text" value="" placeholder="user" />' +
'<input id="download-auth-password" type="text" value="" placeholder="password" />' +
'</div>',
selectedHrefsStr = '',
$download, $img, $downloadAuth, $downloadUser, $downloadPassword,
failed = function () {
$download.addClass('failed');
setTimeout(function () {
$download.removeClass('failed');
}, 1000);
},
handleResponse = function (response) {
$download.removeClass('current');
$img.attr('src', resource.image('download'));
if (response) {
if (response.status === 'ok') {
setTimeout(function () { // wait here so the img above can be updated in time
window.location = resource.api() + '?action=getzip&id=' + response.id;
}, 200);
} else {
if (response.code === 401) {
$downloadAuth
.css({
left: $download.offset().left,
top: $download.offset().top + $download.outerHeight()
})
.show();
$downloadUser.focus();
}
failed();
}
} else {
failed();
}
},
requestZipping = function (hrefsStr) {
$download.addClass('current');
$img.attr('src', resource.image('loading.gif', true));
$.ajax({
url: resource.api(),
data: {
action: 'zip',
hrefs: hrefsStr
},
type: 'POST',
dataType: 'json',
beforeSend: function (xhr) {
var user = $downloadUser.val(),
password = $downloadPassword.val();
if (user) {
xhr.setRequestHeader('Authorization', 'Basic ' + Base64.encode(user + ':' + password));
}
},
success: function (response) {
handleResponse(response);
},
error: function () {
handleResponse();
}
});
},
onSelection = function (entries) {
var $downloadBtn = $('#download');
selectedHrefsStr = '';
if (entries.length) {
selectedHrefsStr = _.map(entries, function (entry) {
return entry.absHref;
}).join(':');
$downloadBtn.show();
} else {
$downloadBtn.hide();
$downloadAuth.hide();
}
},
init = function () {
if (!settings.enabled) {
return;
}
$download = $(downloadBtnTemplate)
.appendTo($('#navbar'))
.find('a').on('click', function (event) {
event.preventDefault();
$downloadAuth.hide();
requestZipping(selectedHrefsStr);
});
$img = $download.find('img');
$downloadAuth = $(authTemplate).appendTo($('body'));
$downloadUser = $downloadAuth.find('#download-auth-user');
$downloadPassword = $downloadAuth.find('#download-auth-password');
event.sub('selection', onSelection);
};
init();
});

View file

@ -1,130 +0,0 @@
Module.define('extended', [jQuery, 'settings', 'conhtml', 'util', 'core'], function ($, settings, conhtml, util, core) {
var initBreadcrumb = function () {
var $ul = $("body > nav ul"),
pathname = "/",
path = conhtml.getPath(pathname),
pathnameParts = document.location.pathname.split("/"),
lastPart = "",
title = document.domain;
$ul.append(conhtml.updateCrumbHtml(path));
$.each(pathnameParts, function (idx, part) {
if (part !== "") {
pathname += part + "/";
$ul.append(conhtml.updateCrumbHtml(conhtml.getPath(pathname)));
lastPart = part + " - ";
title += " > " + part;
}
});
document.title = util.checkedDecodeUri(lastPart + title);
},
initExtendedView = function () {
var $ul, $li;
$ul = $("<ul/>");
$li = $("<li class='header' />")
.appendTo($ul)
.append($("<a class='icon'></a>"))
.append($("<a class='label' href='#'><span class='l10n-name'></span></a>"))
.append($("<a class='date' href='#'><span class='l10n-lastModified'></span></a>"))
.append($("<a class='size' href='#'><span class='l10n-size'></span></a>"));
// entries
$("#table td").closest("tr").each(function () {
var path = conhtml.getPath(document.location.pathname, this);
$ul.append(conhtml.updateExtendedHtml(path));
});
$("#extended").append($ul);
// empty
if ($ul.children(".entry:not(.folder-parent)").size() === 0) {
$("#extended").append($("<div class='empty l10n-empty'>empty</div>"));
}
// no match
$("#extended").append($("<div class='no-match l10n-noMatch'>no match</div>"));
},
customize = function () {
if (settings.customHeader) {
$.ajax({
url: settings.customHeader,
dataType: "html",
success: function (data) {
$("#content > header").append($(data)).show();
}
});
}
if (settings.customFooter) {
$.ajax({
url: settings.customFooter,
dataType: "html",
success: function (data) {
$("#content > footer").prepend($(data)).show();
}
});
}
},
fetchPath = function (pathname, callback) {
conhtml.fetchStatusAndContent(pathname, false, function (status, content) {
var path = conhtml.getPath(pathname);
path.status = status;
path.content = content;
callback(path);
});
},
fetchTree = function (pathname, callback, childPath) {
fetchPath(pathname, function (path) {
var parent = util.splitPath(pathname).parent;
path.treeOpen = true;
if (childPath) {
path.content[childPath.absHref] = childPath;
}
if (parent === null) {
callback(path);
} else {
fetchTree(parent, callback, path);
}
});
},
populateTree = function () {
fetchTree(document.location.pathname, function (path) {
$("#tree")
.append(conhtml.updateTreeHtml(path))
.scrollpanel()
.show();
core.shiftTree(false, true);
core.linkHoverStates();
setTimeout(function () { $("#tree").get(0).updateScrollbar(); }, 1);
});
},
init = function () {
initBreadcrumb();
initExtendedView();
customize();
conhtml.updatePaths();
if (settings.showTree) {
populateTree();
}
};
return {
init: init
};
});

View file

@ -1,106 +0,0 @@
Module.define('finder', [jQuery, 'settings', 'util', 'core'], function ($, settings, util, core) {
var filter = function (re) {
var match = [],
noMatch = [];
if (re) {
$('#extended .entry').each(function () {
var label = $(this).find('.label').text();
if (label.match(re)) {
match.push(this);
} else {
noMatch.push(this);
}
});
} else {
match = $('#extended .entry');
}
if ($(match).length) {
$('#extended .no-match').hide();
} else {
setTimeout(function () {
$('#extended .no-match').show();
}, 200);
}
$(match).fadeIn(200);
$(noMatch).fadeOut(200);
},
checkState = function (focus) {
var $filter = $('#filter'),
$input = $filter.find('input'),
val = $input.val();
if (val || focus) {
$filter.addClass('current');
} else {
$filter.removeClass('current');
}
core.hash({filter: val});
},
parseFilterSequence = function (sequence) {
if (sequence.substr(0,3) === 're:') {
return new RegExp(sequence.substr(3));
}
sequence = $.map($.trim(sequence).split(/\s+/), function (part) {
return util.reEscape(part);
}).join('|');
return new RegExp(sequence);
},
init = function () {
if (settings.showFilter) {
$('<li id="filter"><span class="element"><img alt="filter" /><input type="text" value="" placeholder="filter" /></span></li>')
.on('click', function () {
var $input = $(this).find('input');
$input.focus();
})
.find('img').attr('src', core.image('filter')).end()
.find('input')
.on('focus', function () {
checkState(true);
})
.on('blur', function () {
checkState(false);
})
.on('keyup', function () {
var $input = $(this),
val = $input.val();
if (val) {
filter(parseFilterSequence(val));
} else {
filter();
}
checkState($input.is(':focus'));
})
.end()
.appendTo($('#navbar'));
var initialFilter = core.hash('filter');
if (initialFilter) {
$('#filter input').val(initialFilter);
checkState(false);
}
}
};
return {
init: init,
filter: filter
};
});

View file

@ -1,5 +1,5 @@
Module.define('splash', [jQuery, 'core'], function ($, core) {
module.define('h5ai-info', [jQuery, 'core/resource'], function ($, resource) {
var setCheckResult = function (id, result) {
@ -11,16 +11,19 @@ Module.define('splash', [jQuery, 'core'], function ($, core) {
$ele.addClass('test-failed').text('no');
}
},
handleChecksResponse = function (response) {
setCheckResult('#test-php', response && response.php);
setCheckResult('#test-zips', response && response.zips);
setCheckResult('#test-thumbs', response && response.thumbs);
_.each(['php', 'cache', 'thumbs', 'temp', 'zips'], function (test) {
setCheckResult('#test-' + test, response && response[test]);
})
},
checks = function () {
$.ajax({
url: core.api(),
url: resource.api(),
data: {
action: 'checks'
},
@ -36,12 +39,11 @@ Module.define('splash', [jQuery, 'core'], function ($, core) {
}
});
},
init = function () {
checks();
};
return {
init: init
};
init();
});

View file

@ -0,0 +1,21 @@
module.define('h5ai-main', [jQuery, 'core/event'], function ($, event) {
event.pub('beforeView');
module.require('view/extended');
module.require('view/viewmode');
module.require('view/spacing');
$('#h5ai-reference').append(module.require('core/parser').id === 'apache-autoindex' ? ' (js)' : ' (php)');
event.pub('beforeExt');
_.each(module.getIds(/^ext\/.+/), function (id) {
module.require(id);
});
event.pub('ready');
});

View file

@ -1,38 +0,0 @@
Module.define('h5ai', [jQuery, 'core', 'extended', 'localize', 'sort', 'finder', 'zip', 'context', 'splash'], function ($, core, extended, localize, sort, finder, zip, context, splash) {
var h5ai = {};
h5ai.init = function () {
var $html = $('html');
h5ai.isJs = $html.hasClass('h5ai-js');
h5ai.isPhp = $html.hasClass('h5ai-php');
h5ai.isSplash = $html.hasClass('h5ai-splash');
if (h5ai.isJs || h5ai.isPhp) {
if (h5ai.isJs) {
extended.init();
}
core.init();
localize.init();
sort.init();
finder.init();
zip.init();
context.init();
if (h5ai.isPhp) {
$('#tree').scrollpanel();
core.shiftTree(false, true);
}
}
if (h5ai.isSplash) {
splash.init();
}
};
return h5ai;
});

View file

@ -0,0 +1,84 @@
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.0.6
*
* Requires: 1.2.2+
*/
(function($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for ( var i=types.length; i; ) {
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i=types.length; i; ) {
this.addEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
this.removeEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);

View file

@ -1,84 +0,0 @@
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.0.5
*
* Requires: 1.2.2+
*/
(function($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for ( var i=types.length; i; ) {
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i=types.length; i; ) {
this.addEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
this.removeEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( event.wheelDelta ) { delta = event.wheelDelta/120; }
if ( event.detail ) { delta = -event.detail/3; }
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);

View file

@ -0,0 +1,196 @@
/*!
* module.js
* author: Lars Jung
* license: MIT
*/
(function (global, name) {
'use strict';
var self = {},
previous = global[name],
noConflict = function () {
if (global[name] === self) {
global[name] = previous;
}
return self;
},
err = function (message) {
throw name + ' exception: ' + message;
},
definitions = {},
modules = {},
findDepsUnsafe = function (ids) {
var self = this;
var deps = [];
if (_.isString(ids)) {
var def = definitions[ids];
if (def) {
_.each(def.deps, function (id) {
deps = deps.concat(findDepsUnsafe(id));
});
deps.push(def.id);
} else {
deps.push(ids);
}
} else if (_.isArray(ids)) {
_.each(ids, function (id) {
deps = deps.concat(findDepsUnsafe(id));
});
}
return _.uniq(deps);
},
findDeps = function (ids) {
if (ids) {
try {
return findDepsUnsafe(ids);
} catch (e) {
err('cyclic dependencies for ids "' + ids + '"');
}
} else {
var res = {};
_.each(definitions, function (def, id) {
res[id] = findDeps(id);
});
return res;
}
},
log = function (showInvDeps) {
var allDeps = findDeps(),
allInvDeps = {},
out = '';
if (!showInvDeps) {
_.each(allDeps, function (deps, id) {
deps.pop();
out += (_.has(modules, id) ? '* ' : ' ') + id + ' -> [ ' + deps.join(', ') + ' ]\n';
});
} else {
_.each(definitions, function (def) {
var invDeps = [];
_.each(allDeps, function (depId, id) {
if (_.inArray(def.id, depId) >= 0) {
invDeps.push(id);
}
});
allInvDeps[def.id] = invDeps;
});
_.each(allInvDeps, function (invDeps, id) {
invDeps.shift();
out += (_.has(modules, id) ? '* ' : ' ') + id + ' <- [ ' + invDeps.join(', ') + ' ]\n';
});
}
return out;
},
define = function (id, deps, fn) {
if (_.isFunction(deps)) {
fn = deps;
deps = [];
}
if (!_.isString(id)) {
err('id must be a string "' + id + '"');
}
if (!_.isArray(deps)) {
err('dependencies must be an array "' + deps + '"');
}
if (!_.isFunction(fn)) {
err('constructor must be a function "' + fn + '"');
}
if (definitions[id]) {
err('id already defined "' + id + '"');
}
definitions[id] = {
id: id,
deps: deps,
fn: fn
};
},
getIds = function (regexp) {
var ids = _.map(definitions, function (def) {
return def.id;
});
if (!_.isRegExp(regexp)) {
return ids;
}
return _.filter(ids, function (id) {
return regexp.test(id);
});
},
isDefined = function (id) {
return _.isString(id) ? !!definitions[id] : !!id;
},
require = function (id) {
if (!_.isString(id)) {
return id;
}
if (_.has(modules, id)) {
return modules[id];
}
var def = definitions[id];
if (!def) {
err('id not defined "' + id + '"');
}
var deps = _.map(def.deps, function (depId) {
return require(depId);
});
var obj = def.fn.apply(this, deps);
modules[id] = obj;
return obj;
};
if (!_) {
err(name + ' depends on underscore');
}
self.noConflict = noConflict;
self.log = log;
self.define = define;
self.require = require;
self.getIds = getIds;
self.isDefined = isDefined;
global[name] = self;
}(this, 'module'));

View file

@ -1,36 +1,48 @@
(function () {
'use strict';
/*jslint browser: true, confusion: true, regexp: true, vars: true, white: true */
/*global Modernizr, jQuery, amplify, Base64, H5AI_CONFIG */
(function ($) {
'use strict';
/*jshint browser: true */
/*global _, amplify, Base64, H5AI_CONFIG, jQuery, Modernizr, module, moment */
// @include "module.js"
// @include "core/entry.js"
// @include "core/event.js"
// @include "core/format.js"
// @include "core/parser.js"
// @include "core/resource.js"
// @include "core/settings.js"
// @include "core/store.js"
// @include "settings.js"
// @include "model/entry.js"
// @include "util.js"
// @include "core.js"
// @include "localize.js"
// @include "sort.js"
// @include "zip.js"
// @include "finder.js"
// @include "context.js"
// @include "parser/apache-autoindex.js"
// @include "parser/generic-json.js"
// @include "path.js"
// @include "connector.js"
// @include "html.js"
// @include "extended.js"
// @include "view/extended.js"
// @include "view/spacing.js"
// @include "view/viewmode.js"
// @include "splash.js"
// @include "ext/crumb.js"
// @include "ext/custom.js"
// @include "ext/filter.js"
// @include "ext/folderstatus.js"
// @include "ext/l10n.js"
// @include "ext/link-hover-states.js"
// @include "ext/qrcode.js"
// @include "ext/select.js"
// @include "ext/sort.js"
// @include "ext/statusbar.js"
// @include "ext/thumbnails.js"
// @include "ext/title.js"
// @include "ext/tree.js"
// @include "ext/zipped-download.js"
// @include "h5ai.js"
// @include "h5ai-info.js"
// @include "h5ai-main.js"
jQuery(function () {
$(function () {
var h5ai = Module.require('h5ai');
h5ai.init();
module.require($('body').attr('id'));
});
}());
}(jQuery));

View file

@ -0,0 +1,282 @@
module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
var domain = document.domain,
location = document.location.pathname,
// utils
reEndsWithSlash = /\/$/,
pathEndsWithSlash = function (sequence) {
return reEndsWithSlash.test(sequence);
},
createLabel = function (sequence) {
if (sequence.length > 1 && reEndsWithSlash.test(sequence)) {
sequence = sequence.slice(0, -1);
}
try {
sequence = decodeURI(sequence);
} catch (err) {}
return sequence;
},
reSplitPath = /^\/([^\/]+\/?)$/,
reSplitPath2 = /^(\/(?:.*\/)*?([^\/]+)\/)([^\/]+\/?)$/,
splitPath = function (sequence) {
var match;
sequence = sequence.replace(/\/+/g, '/');
if (sequence === '/') {
return {
parent: null,
parentname: null,
name: '/'
};
}
match = reSplitPath2.exec(sequence);
if (match) {
return {
parent: match[1],
parentname: match[2],
name: match[3]
};
}
match = reSplitPath.exec(sequence);
if (match) {
return {
parent: '/',
parentname: '/',
name: match[1]
};
}
},
extToFileType = (function (types) {
var map = {};
$.each(types, function (type, exts) {
$.each(exts, function (idx, ext) {
map[ext] = type;
});
});
return map;
}(types)),
getFileType = function (sequence) {
if (pathEndsWithSlash(sequence)) {
return 'folder';
}
var dotidx = sequence.lastIndexOf('.'),
ext = dotidx >= 0 ? sequence.substr(dotidx) : sequence;
return extToFileType[ext.toLowerCase()] || 'unknown';
},
reContentType = /^text\/html;h5ai=/,
ajaxRequest = function (self, parser, callback) {
$.ajax({
url: self.absHref,
type: parser ? 'GET' : 'HEAD',
complete: function (xhr) {
if (xhr.status === 200 && reContentType.test(xhr.getResponseHeader('Content-Type'))) {
self.status = 'h5ai';
if (parser) {
parser.parse(self.absHref, xhr.responseText);
}
} else {
self.status = xhr.status;
}
callback(self);
}
});
},
// Entry
cache = {},
Entry = function (absHref) {
var split = splitPath(absHref);
cache[absHref] = this;
this.absHref = absHref;
this.type = getFileType(absHref);
this.label = createLabel(absHref === '/' ? domain : split.name);
this.time = null;
this.size = null;
this.parent = null;
this.status = null;
this.content = {};
if (split.parent) {
this.parent = cache[split.parent] || new Entry(split.parent);
this.parent.content[this.absHref] = this;
}
},
get = function (absHref, time, size, status) {
absHref = absHref || location;
var self = cache[absHref] || new Entry(absHref);
if (_.isNumber(time)) {
self.time = time;
}
if (_.isNumber(size)) {
self.size = size;
}
if (status) {
self.status = status;
}
return self;
},
folderstatus = module.isDefined('ext/folderstatus') ? module.require('ext/folderstatus') : {},
fetchStatus = function (absHref, callback) {
var self = cache[absHref] || new Entry(absHref);
if (self.status || !self.isFolder()) {
callback(self);
} else if (folderstatus[absHref]) {
self.status = folderstatus[absHref];
callback(self);
} else {
ajaxRequest(self, null, callback);
}
},
fetchContent = function (absHref, parser, callback) {
var self = cache[absHref] || new Entry(absHref);
if (self.isContentFetched || _.keys(self.content).length > 1) {
self.isContentFetched = true;
callback(self);
} else {
fetchStatus(absHref, function (self) {
self.isContentFetched = true;
if (self.status === 'h5ai') {
ajaxRequest(self, parser, callback);
} else {
callback(self);
}
});
}
};
_.extend(Entry.prototype, {
isFolder: function () {
return pathEndsWithSlash(this.absHref);
},
isCurrentFolder: function () {
return this.absHref === location;
},
isDomain: function () {
return this.absHref === '/';
},
isEmpty: function () {
return _.keys(this.content).length === 0;
},
fetchStatus: function (callback) {
return fetchStatus(this.absHref, callback);
},
fetchContent: function (parser, callback) {
return fetchContent(this.absHref, parser, callback);
},
getCrumb: function () {
var entry = this,
crumb = [entry];
while (entry.parent) {
entry = entry.parent;
crumb.unshift(entry);
}
return crumb;
},
getSubfolders: function () {
return _.sortBy(_.filter(this.content, function (entry) {
return entry.isFolder();
}), function (entry) {
return entry.absHref;
});
},
getStats: function () {
var folders = 0,
files = 0;
_.each(this.content, function (entry) {
if (entry.isFolder()) {
folders += 1;
} else {
files += 1;
}
});
var depth = 0,
entry = this;
while (entry.parent) {
depth += 1;
entry = entry.parent;
}
return {
folders: folders,
files: files,
depth: depth
};
}
});
return {
get: get
};
});

View file

@ -1,174 +0,0 @@
var Module = window.Module = (function ($) {
var definitions = {},
modules = {},
err = function (message) {
$.error('module: ' + message);
},
uniq = function (array) {
var set = {},
uniq = [];
$.each(array, function (idx, element) {
if (!set[element]) {
set[element] = true;
uniq.push(element);
}
});
return uniq;
},
depsIntern = function (ids) {
var self = this;
var deps = [];
if (typeof ids === 'string') {
var def = definitions[ids];
if (def) {
$.each(def.deps, function (idx, id) {
deps = deps.concat(depsIntern(id));
});
deps.push(def.id);
} else {
deps.push(ids);
}
} else if ($.isArray(ids)) {
$.each(ids, function (idx, id) {
deps = deps.concat(depsIntern(id));
});
}
return uniq(deps);
},
deps = function (ids) {
if (ids) {
try {
return depsIntern(ids);
} catch (e) {
err('cyclic dependencies for ids "' + ids + '"');
}
} else {
var res = {};
$.each(definitions, function (id, def) {
res[id] = deps(id);
});
return res;
}
},
log = function () {
var allDeps = deps(),
allInvDeps = {};
$.each(definitions, function (id, def) {
var invDeps = [];
$.each(allDeps, function (i, depId) {
if ($.inArray(id, depId) >= 0) {
invDeps.push(i);
}
});
allInvDeps[id] = invDeps;
});
$.each(allDeps, function (id, deps) {
deps.pop();
console.log(id + ' -> [ ' + deps.join(', ') + ' ]');
});
console.log('\n');
$.each(allInvDeps, function (id, invDeps) {
invDeps.shift();
console.log(id + ' <- [ ' + invDeps.join(', ') + ' ]');
});
},
defs = function () {
return $.extend({}, definitions);
},
mods = function () {
return $.extend({}, modules);
},
define = function (id, deps, fn) {
if ($.isFunction(deps)) {
fn = deps;
deps = [];
}
if (typeof id !== 'string') {
err('id must be a string "' + id + '"');
}
if (!$.isArray(deps)) {
err('dependencies must be an array "' + deps + '"');
}
if (!$.isFunction(fn)) {
err('constructor must be a function "' + fn + '"');
}
if (definitions[id]) {
err('id already defined "' + id + '"');
}
definitions[id] = {
id: id,
deps: deps,
fn: fn
};
},
require = function (id) {
if (typeof id !== 'string') {
return id;
}
if (modules[id]) {
return modules[id];
}
var def = definitions[id];
if (!def) {
err('id not defined "' + id + '"');
}
var deps = $.map(def.deps, function (depId) {
return require(depId);
});
var obj = def.fn.apply(this, deps);
modules[id] = obj;
return obj;
};
return {
deps: deps,
log: log,
defs: defs,
mods: mods,
define: define,
require: require
};
}(jQuery));

View file

@ -0,0 +1,42 @@
module.define('parser/apache-autoindex', [jQuery, 'core/format', 'model/entry'], function ($, format, Entry) {
var parseTableRow = function (absHref, tr) {
var $tds = $(tr).find('td'),
$a = $tds.eq(1).find('a'),
label = $a.text(),
time = format.parseDate($tds.eq(2).text(), 'DD-MMM-YYYY HH:mm'),
size = format.parseSize($tds.eq(3).text());
absHref = absHref + $a.attr('href');
return label === 'Parent Directory' ? null : Entry.get(absHref, time, size);
},
parseTable = function (absHref, table) {
return _.compact(_.map($(table).find('td').closest('tr'), function (tr) {
return parseTableRow(absHref, tr);
}));
},
parse = function (absHref, html) {
var id = '#data-apache-autoindex',
$html = $(html),
$id = $html.filter(id);
if (!$id.length) {
$id = $html.find(id);
}
return parseTable(absHref, $id.find('table'));
};
return {
id: 'apache-autoindex',
parse: parse
};
});

View file

@ -0,0 +1,48 @@
module.define('parser/generic-json', [jQuery, 'core/settings', 'model/entry'], function ($, settings, Entry) {
// expectes an hash of the form
// {
// entries: [
// {absHref: String, time: Number, size: Number, status: Number or "h5ai"}
// ]
// }
var parseJson = function (absHref, json) {
_.each(json.entries, function (jsonEntry) {
Entry.get(jsonEntry.absHref, jsonEntry.time, jsonEntry.size, jsonEntry.status);
});
if (json.hasOwnProperty('customHeader')) {
settings.custom.header = json.customHeader;
}
if (json.hasOwnProperty('customFooter')) {
settings.custom.footer = json.customFooter;
}
},
parseJsonStr = function (absHref, jsonStr) {
return parseJson(absHref, JSON.parse($.trim(jsonStr) || '{}'));
},
parse = function (absHref, html) {
var id = '#data-generic-json',
$html = $(html),
$id = $html.filter(id);
if (!$id.length) {
$id = $html.find(id);
}
return parseJsonStr(absHref, $id.text());
};
return {
id: 'generic-json',
parse: parse
};
});

View file

@ -1,98 +0,0 @@
Module.define('path', [jQuery, 'settings', 'util', 'core'], function ($, settings, util, core) {
var create = function (folder, tableRow) {
var path = {},
$tds, $a, time, size, splits;
// path.parentFolder: undefined
// path.label: undefined
// path.type: undefined
// path.href: undefined
// path.time: undefined
// path.size: undefined
// path.absHref: undefined
// path.isFolder: undefined
// path.isParentFolder: undefined
// path.isCurrentFolder: undefined
// path.isDomain: undefined
path.status = undefined; // undefined, 'h5ai' or HTTP response code
path.content = undefined; // associative array path.absHref -> path
path.html = {
$crumb: undefined,
$extended: undefined,
$tree: undefined
};
path.treeOpen = false;
if (!util.pathEndsWithSlash(folder)) {
folder += '/';
}
if (tableRow) {
$tds = $(tableRow).find('td');
$a = $tds.eq(1).find('a');
time = Date.parse($tds.eq(2).text()) || 0;
size = util.parseSize($tds.eq(3).text());
path.parentFolder = folder;
path.label = $a.text();
path.type = util.pathEndsWithSlash(path.label) ? 'folder' : core.getFileType(path.label);
path.href = $a.attr('href');
path.time = time;
path.size = size;
} else {
splits = util.splitPath(folder);
path.parentFolder = splits.parent || '';
path.label = util.checkedDecodeUri(splits.name);
if (path.label === '/') {
path.label = util.checkedDecodeUri(document.domain);
}
path.type = 'folder';
path.href = splits.name;
path.time = 0;
path.size = -1;
}
if (util.pathEndsWithSlash(path.label)) {
path.label = path.label.slice(0, -1);
}
path.isFolder = (path.type === 'folder');
path.isParentFolder = (path.label === 'Parent Directory');
if (path.isParentFolder) {
path.isFolder = true;
path.type = 'folder-parent';
}
path.absHref = path.isParentFolder ? path.href : path.parentFolder + path.href;
path.isCurrentFolder = (path.absHref === document.location.pathname);
path.isDomain = (path.absHref === '/');
if (path.isParentFolder && settings.setParentFolderLabels) {
if (path.isDomain) {
path.label = util.checkedDecodeUri(document.domain);
} else {
splits = util.splitPath(path.parentFolder);
path.label = util.checkedDecodeUri(splits.parentname);
}
}
path.isEmpty = function () {
return !path.content || $.isEmptyObject(path.content);
};
path.onClick = function (context) {
core.triggerPathClick(path, context);
};
return path;
};
return {
create: create
};
});

View file

@ -1,57 +0,0 @@
Module.define('config', [jQuery, H5AI_CONFIG], function ($, config) {
var defaults = {
store: {
viewmode: 'h5ai.pref.viewmode',
lang: 'h5ai.pref.lang'
},
callbacks: {
pathClick: []
},
rootAbsHref: '/',
h5aiAbsHref: '/_h5ai/',
customHeader: null,
customFooter: null,
viewmodes: ['details', 'icons'],
sortorder: 'na',
showTree: true,
slideTree: true,
folderStatus: {},
lang: 'en',
useBrowserLang: true,
setParentFolderLabels: true,
linkHoverStates: true,
dateFormat: 'yyyy-MM-dd HH:mm',
showThumbs: false,
thumbTypes: ['bmp', 'gif', 'ico', 'image', 'jpg', 'png', 'tiff'],
zippedDownload: false,
qrCodesSize: null,
showFilter: false
};
return {
settings: $.extend({}, defaults, config.options),
types: $.extend({}, config.types),
langs: $.extend({}, config.langs)
};
});
Module.define('settings', ['config'], function (config) {
return config.settings;
});
Module.define('types', ['config'], function (config) {
return config.types;
});
Module.define('langs', ['config'], function (config) {
return config.langs;
});

View file

@ -1,117 +0,0 @@
Module.define('util', [jQuery], function ($) {
var reSplitPath = /^\/([^\/]+\/?)$/,
reSplitPath2 = /^(\/(?:.*\/)*?([^\/]+)\/)([^\/]+\/?)$/,
rePathEndsWithSlash = /\/$/,
reParseSize = /^\s*([\.\d]+)\s*([kmg]?)b?\s*$/i,
kilo = 1000.0,
sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB'],
splitPath = function (pathname) {
var match;
if (pathname === '/') {
return {
parent: null,
parentname: null,
name: '/'
};
}
match = reSplitPath2.exec(pathname);
if (match) {
return {
parent: match[1],
parentname: match[2],
name: match[3]
};
}
match = reSplitPath.exec(pathname);
if (match) {
return {
parent: '/',
parentname: '/',
name: match[1]
};
}
},
pathEndsWithSlash = function (pathname) {
return rePathEndsWithSlash.test(pathname);
},
getAbsHref = function (folder, tableRow) {
var $a, isParentFolder, href;
if (!pathEndsWithSlash(folder)) {
folder += '/';
}
if (!tableRow) {
return folder;
}
$a = $(tableRow).find('td').eq(1).find('a');
isParentFolder = ($a.text() === 'Parent Directory');
href = $a.attr('href');
return isParentFolder ? undefined : folder + href;
},
parseSize = function (str) {
var match = reParseSize.exec(str),
val, unit;
if (!match) {
return -1;
}
val = parseFloat(match[1]);
unit = match[2].toLowerCase();
if (unit === 'k') {
val *= kilo;
} else if (unit === 'm') {
val *= kilo * kilo;
} else if (unit === 'g') {
val *= kilo * kilo * kilo;
} else if (unit === 't') {
val *= kilo * kilo * kilo * kilo;
}
return val;
},
formatSize = function (size) {
var th = 1000.0,
i = 0,
maxI = sizeUnits.length - 1;
if (isNaN(size)) {
return size;
}
while (size >= th && i < maxI) {
size /= kilo;
i += 1;
}
return (i <= 1 ? Math.round(size) : size.toFixed(1)).toString() + ' ' + sizeUnits[i];
},
checkedDecodeUri = function (uri) {
try {
return decodeURI(uri);
} catch (err) {}
return uri;
},
reEscape = function (sequence) {
return sequence.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
};
return {
splitPath: splitPath,
pathEndsWithSlash: pathEndsWithSlash,
getAbsHref: getAbsHref,
parseSize: parseSize,
formatSize: formatSize,
checkedDecodeUri: checkedDecodeUri,
reEscape: reEscape
};
});

View file

@ -0,0 +1,135 @@
module.define('view/extended', [jQuery, 'core/settings', 'core/resource', 'core/format', 'core/event', 'core/entry'], function ($, allsettings, resource, format, event, entry) {
var defaults = {
modes: ['details', 'icons'],
setParentFolderLabels: false
},
settings = _.extend({}, defaults, allsettings.view),
template = '<li class="entry">' +
'<a>' +
'<span class="icon small"><img /></span>' +
'<span class="icon big"><img /></span>' +
'<span class="label" />' +
'<span class="date" />' +
'<span class="size" />' +
'</a>' +
'</li>',
hintTemplate = '<span class="hint"></span>',
listTemplate = '<ul>' +
'<li class="header">' +
'<a class="icon"></a>' +
'<a class="label" href="#"><span class="l10n-name"></span></a>' +
'<a class="date" href="#"><span class="l10n-lastModified"></span></a>' +
'<a class="size" href="#"><span class="l10n-size"></span></a>' +
'</li>' +
'</ul>',
emptyTemplate = '<div class="empty l10n-empty">empty</div>',
// updates this single entry
update = function (entry) {
if (entry.$extended && entry.status && entry.$extended.data('status') === entry.status) {
return entry.$extended;
}
var $html = $(template),
$a = $html.find('a'),
$imgSmall = $html.find('.icon.small img'),
$imgBig = $html.find('.icon.big img'),
$label = $html.find('.label'),
$date = $html.find('.date'),
$size = $html.find('.size'),
icon16 = resource.icon(entry.type),
icon48 = resource.icon(entry.type, true),
escapedHref = entry.absHref.replace(/'/g, "%27").replace(/"/g, "%22");
$html
.addClass(entry.isFolder() ? 'folder' : 'file')
.data('entry', entry)
.data('status', entry.status);
if (entry.isParentFolder) {
icon16 = resource.icon('folder-parent');
icon48 = resource.icon('folder-parent', true);
if (!settings.setParentFolderLabels) {
$label.addClass('l10n-parentDirectory');
}
$html.addClass('folder-parent');
}
$a.attr('href', entry.absHref);
$imgSmall.attr('src', icon16).attr('alt', entry.type);
$imgBig.attr('src', icon48).attr('alt', entry.type);
$label.text(entry.label);
$date.data('time', entry.time).text(format.formatDate(entry.time));
$size.data('bytes', entry.size).text(format.formatSize(entry.size));
if (entry.isFolder() && _.isNumber(entry.status)) {
if (entry.status === 200) {
$html.addClass('page');
$imgSmall.attr('src', resource.icon('folder-page'));
$imgBig.attr('src', resource.icon('folder-page', true));
} else {
$html.addClass('error');
$label.append($(hintTemplate).text(' ' + entry.status + ' '));
}
}
if (entry.$extended) {
entry.$extended.replaceWith($html);
}
entry.$extended = $html;
return $html;
},
onMouseenter = function () {
var entry = $(this).closest('.entry').data('entry');
event.pub('entry.mouseenter', entry);
},
onMouseleave = function () {
var entry = $(this).closest('.entry').data('entry');
event.pub('entry.mouseleave', entry);
},
// creates the view for entry content
init = function (entry) {
var $extended = $('#extended'),
$ul = $(listTemplate);
if (entry.parent) {
$ul.append(update(entry.parent));
}
_.each(entry.content, function (e) {
$ul.append(update(e));
e.fetchStatus(function (e) {
update(e);
});
});
$extended.append($ul);
if (entry.isEmpty()) {
$extended.append($(emptyTemplate));
}
$extended
.on('mouseenter', '.entry a', onMouseenter)
.on('mouseleave', '.entry a', onMouseleave);
};
init(entry);
});

View file

@ -0,0 +1,35 @@
module.define('view/spacing', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) {
var defaults = {
maxWidth: 960,
top: 50,
right: "auto",
bottom: 50,
left: "auto"
},
settings = _.extend({}, defaults, allsettings.spacing),
adjustSpacing = function () {
$('#content').css({
'margin-top': settings.top + $('#topbar').outerHeight(),
'margin-bottom': settings.bottom + $('#bottombar').outerHeight()
});
},
init = function () {
$('#content').css({
'max-width': settings.maxWidth,
'margin-right': settings.right,
'margin-left': settings.left
});
event.sub('ready', adjustSpacing);
$(window).on('resize', adjustSpacing);
};
init();
});

View file

@ -0,0 +1,77 @@
module.define('view/viewmode', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) {
var defaults = {
modes: ['details', 'icons'],
setParentFolderLabels: false
},
settings = _.extend({}, defaults, allsettings.view),
storekey = 'h5ai.viewmode',
templates = {
details: '<li id="viewdetails" class="view">' +
'<a href="#">' +
'<img src="' + resource.image('view-details') + '" alt="view-details" />' +
'<span class="l10n-details">details</span>' +
'</a>' +
'</li>',
icons: '<li id="viewicons" class="view">' +
'<a href="#">' +
'<img src="' + resource.image('view-icons') + '" alt="view-icons" />' +
'<span class="l10n-icons">icons</span>' +
'</a>' +
'</li>'
},
update = function (viewmode) {
var $viewDetails = $('#viewdetails'),
$viewIcons = $('#viewicons'),
$extended = $('#extended');
if (viewmode) {
store.put(storekey, viewmode);
} else {
viewmode = store.get(storekey);
}
viewmode = $.inArray(viewmode, settings.modes) >= 0 ? viewmode : settings.modes[0];
$viewDetails.add($viewIcons).removeClass('current');
if (viewmode === 'details') {
$viewDetails.addClass('current');
$extended.addClass('details-view').removeClass('icons-view').show();
} else if (viewmode === 'icons') {
$viewIcons.addClass('current');
$extended.removeClass('details-view').addClass('icons-view').show();
} else {
$extended.hide();
}
},
init = function () {
var $navbar = $('#navbar'),
$extended = $('#extended');
settings.modes = _.intersection(settings.modes, defaults.modes);
if (settings.modes.length > 1) {
_.each(['icons', 'details'], function (view) {
if ($.inArray(view, settings.modes) >= 0) {
$(templates[view])
.appendTo($navbar)
.on('click', 'a', function (event) {
update(view);
event.preventDefault();
});
}
});
}
update();
};
init();
});

View file

@ -1,187 +0,0 @@
Module.define('zip', [jQuery, 'settings', 'core'], function ($, settings, core) {
var x = 0,
y = 0,
$document = $(document),
$selectionRect = $('#selection-rect'),
selectedHrefsStr = '',
$download, $img, $downloadAuth, $downloadUser, $downloadPassword,
updateDownloadBtn = function () {
var $selected = $('#extended a.selected'),
$downloadBtn = $('#download');
selectedHrefsStr = '';
if ($selected.length) {
$selected.each(function () {
var href = $(this).attr('href');
selectedHrefsStr = selectedHrefsStr ? selectedHrefsStr + ':' + href : href;
});
$downloadBtn.show();
} else {
$downloadBtn.hide();
$downloadAuth.hide();
}
},
selectionUpdate = function (event) {
var l = Math.min(x, event.pageX),
t = Math.min(y, event.pageY),
w = Math.abs(x - event.pageX),
h = Math.abs(y - event.pageY),
selRect;
event.preventDefault();
$selectionRect.css({left: l, top: t, width: w, height: h});
selRect = $selectionRect.fracs('rect');
$('#extended a').removeClass('selecting').each(function () {
var $a = $(this),
rect = $a.fracs('rect'),
inter = selRect.intersection(rect);
if (inter && !$a.closest('.entry').hasClass('folder-parent')) {
$a.addClass('selecting');
}
});
},
selectionEnd = function (event) {
event.preventDefault();
$document.off('mousemove', selectionUpdate);
$selectionRect.hide().css({left: 0, top: 0, width: 0, height: 0});
$('#extended a.selecting.selected').removeClass('selecting').removeClass('selected');
$('#extended a.selecting').removeClass('selecting').addClass('selected');
updateDownloadBtn();
},
selectionStart = function (event) {
var view = $(document).fracs('viewport');
x = event.pageX;
y = event.pageY;
// only on left button and don't block the scrollbars
if (event.button !== 0 || x >= view.right || y >= view.bottom) {
return;
}
event.preventDefault();
$(':focus').blur();
if (!event.ctrlKey) {
$("#extended a").removeClass("selected");
updateDownloadBtn();
}
$selectionRect.show().css({left: x, top: y, width: 0, height: 0});
$document
.on("mousemove", selectionUpdate)
.one("mouseup", selectionEnd);
},
noSelection = function (event) {
event.stopImmediatePropagation();
return false;
},
noSelectionUnlessCtrl = function (event) {
if (!event.ctrlKey) {
noSelection(event);
}
},
failed = function () {
$download.addClass('failed');
setTimeout(function () {
$download.removeClass('failed');
}, 1000);
},
handleResponse = function (response) {
$download.removeClass('current');
$img.attr('src', core.image("download"));
if (response) {
if (response.status === 'ok') {
window.location = core.api() + '?action=getzip&id=' + response.id;
} else {
if (response.code === 401) {
$downloadAuth
.css({
left: $download.offset().left,
top: $download.offset().top + $download.outerHeight()
})
.show();
$downloadUser.focus();
}
failed();
}
} else {
failed();
}
},
requestZipping = function (hrefsStr) {
$download.addClass('current');
$img.attr('src', core.image("loading.gif", true));
$.ajax({
url: core.api(),
data: {
action: 'zip',
hrefs: selectedHrefsStr
},
type: 'POST',
dataType: 'json',
beforeSend: function (xhr) {
var user = $downloadUser.val(),
password = $downloadPassword.val();
if (user) {
xhr.setRequestHeader ('Authorization', 'Basic ' + Base64.encode(user + ':' + password));
}
},
success: function (response) {
handleResponse(response);
},
error: function () {
handleResponse();
}
});
},
init = function () {
if (settings.zippedDownload) {
$('<li id="download"><a href="#"><img alt="download" /><span class="l10n-download">download</span></a></li>')
.find('img').attr('src', core.image('download')).end()
.find('a').click(function (event) {
event.preventDefault();
$downloadAuth.hide();
requestZipping(selectedHrefsStr);
}).end()
.appendTo($('#navbar'));
$('<div id="download-auth"><input id="download-auth-user" type="text" value="" placeholder="user" /><input id="download-auth-password" type="text" value="" placeholder="password" /></div>')
.appendTo($('body'));
$download = $('#download');
$downloadAuth = $('#download-auth');
$downloadUser = $('#download-auth-user');
$downloadPassword = $('#download-auth-password');
$img = $download.find('img');
$('body>nav,body>footer,#tree,input').on('mousedown', noSelection);
$('#content').on('mousedown', 'a', noSelectionUnlessCtrl);
$document.on('mousedown', selectionStart);
}
};
return {
init: init
};
});

4
src/_h5ai/js/modernizr-2.5.3.min.js vendored Normal file
View file

@ -0,0 +1,4 @@
/* Modernizr 2.5.3 (Custom Build) | MIT & BSD
* Build: http://www.modernizr.com/download/#-opacity-rgba-canvas-history-audio-video-shiv-cssclasses-prefixes
*/
;window.Modernizr=function(a,b,c){function v(a){j.cssText=a}function w(a,b){return v(m.join(a+";")+(b||""))}function x(a,b){return typeof a===b}function y(a,b){return!!~(""+a).indexOf(b)}function z(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:x(f,"function")?f.bind(d||b):f}return!1}var d="2.5.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={},o={},p={},q=[],r=q.slice,s,t={}.hasOwnProperty,u;!x(t,"undefined")&&!x(t.call,"undefined")?u=function(a,b){return t.call(a,b)}:u=function(a,b){return b in a&&x(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=r.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(r.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(r.call(arguments)))};return e}),n.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},n.history=function(){return!!a.history&&!!history.pushState},n.rgba=function(){return v("background-color:rgba(150,255,150,.5)"),y(j.backgroundColor,"rgba")},n.opacity=function(){return w("opacity:.55"),/^0.55$/.test(j.opacity)},n.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},n.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c};for(var A in n)u(n,A)&&(s=A.toLowerCase(),e[s]=n[A](),q.push((e[s]?"":"no-")+s));return v(""),i=k=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="<xyz></xyz>",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e._prefixes=m,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+q.join(" "):""),e}(this,this.document);

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,7 @@
// ------------------
// @include "inc/lib/jquery-1.7.1.min.js"
// @include "inc/lib/jquery.fracs-0.11.min.js"
// @include "inc/lib/jquery.mousewheel.js"
// @include "inc/lib/jquery.mousewheel-3.0.6.js"
// @include "inc/lib/jquery.qrcode.js"
// @include "inc/lib/jquery.scrollpanel.js"
@ -14,6 +14,7 @@
// @include "inc/lib/json2.js"
// @include "inc/lib/moment-1.5.0.min.js"
// @include "inc/lib/underscore-1.3.1.min.js"
// @include "inc/lib/module.js"
// h5ai
// ----

View file

@ -1,17 +1,10 @@
<?php
function safe_dirname($path, $endWithSlash = false) {
require_once(str_replace("\\", "/", __DIR__) . "/inc/H5ai.php");
$path = str_replace("\\", "/", dirname($path));
return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : ""));
}
define("H5AI_ABS_PATH", safe_dirname(safe_dirname(__FILE__)));
function require_h5ai($lib) {
require_once(H5AI_ABS_PATH . $lib);
}
$h5ai = new H5ai();
$options = $h5ai->getOptions();
function fail($code, $msg, $cond = true) {
@ -31,11 +24,6 @@ function checkKeys($keys) {
}
require_h5ai("/php/inc/H5ai.php");
$h5ai = new H5ai();
$options = $h5ai->getOptions();
list($action) = checkKeys(array("action"));
@ -64,11 +52,11 @@ if ($action === "httpcodes") {
else if ($action === "thumb") {
fail(0, "thumbs are disabled", !$options["showThumbs"]);
fail(0, "thumbs are disabled", !$options["thumbnails"]["enabled"]);
list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode"));
require_h5ai("/php/inc/Thumbnail.php");
require_h5ai("/php/inc/Image.php");
H5ai::req_once("/php/inc/Thumbnail.php");
H5ai::req_once("/php/inc/Image.php");
$srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref);
@ -90,28 +78,42 @@ else if ($action === "thumb") {
}
else if ($action === "tree") {
else if ($action === "thumbsrc") {
list($href) = checkKeys(array("href"));
if (!$options["thumbnails"]["enabled"]) {
echo json_encode(array("code" => 1, "absHref" => null));
exit;
}
require_h5ai("/php/inc/Tree.php");
list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode"));
$absHref = trim($href);
$absPath = $h5ai->getAbsPath($absHref);
H5ai::req_once("/php/inc/Thumbnail.php");
H5ai::req_once("/php/inc/Image.php");
$tree = new TreeEntry($h5ai, $absPath, $absHref);
$tree->loadContent();
$srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref);
echo $tree->contentToHtml();
if (!Thumbnail::isUsable()) {
echo json_encode(array("code" => 2, "absHref" => null));
exit;
}
$thumbnail = new Thumbnail($h5ai, $srcAbsHref, $mode, $width, $height);
$thumbnail->create(1);
if (!file_exists($thumbnail->getPath())) {
echo json_encode(array("code" => 3, "absHref" => null));
exit;
}
echo json_encode(array("code" => 0, "absHref" => $thumbnail->getHref()));
}
else if ($action === "zip") {
fail(0, "zipped download is disabled", !$options["zippedDownload"]);
fail(0, "zipped download is disabled", !$options["zipped-download"]["enabled"]);
list($hrefs) = checkKeys(array("hrefs"));
require_h5ai("/php/inc/ZipIt.php");
H5ai::req_once("/php/inc/ZipIt.php");
$zipit = new ZipIt($h5ai);
@ -147,8 +149,10 @@ else if ($action === "checks") {
$response = array(
'php' => $h5ai->checks["php"],
'zips' => $h5ai->checks["php"] && $h5ai->checks["zip"],
'thumbs' => $h5ai->checks["php"] && $h5ai->checks["gd"]
'cache' => $h5ai->checks["php"] && $h5ai->checks["cache"],
'thumbs' => $h5ai->checks["php"] && $h5ai->checks["cache"] && $h5ai->checks["gd"],
'temp' => $h5ai->checks["php"] && $h5ai->checks["temp"],
'zips' => $h5ai->checks["php"] && $h5ai->checks["temp"] && $h5ai->checks["zip"]
);
echo json_encode($response);
}

View file

@ -1,55 +0,0 @@
<?php
class Crumb {
private $h5ai, $parts;
public function __construct($h5ai) {
$this->h5ai = $h5ai;
$this->parts = array();
$href = $h5ai->getAbsHref();
while ($href !== "/") {
$this->parts[] = $href;
$href = safe_dirname($href, true);
}
$this->parts[] = "/";
$this->parts = array_reverse($this->parts);
}
public function toHtml() {
$html = "";
$idx = 0;
foreach($this->parts as $href) {
$idx++;
$classes = "crumb folder" . ($idx === 1 ? " domain" : "") . ($idx === count($this->parts) ? " current" : "");
$image = $this->h5ai->image($idx === 1 ? "home" : "crumb");
$label = $this->h5ai->getLabel($href);
$hint = "";
$code = $this->h5ai->getHttpCode($href);
$classes .= " checkedHttpCode";
if ($code !== "h5ai") {
if ($code === 200) {
$hint = "<img class='hint' src='" . $this->h5ai->image("page") . "' alt='page' />";
} else {
$hint = "<span class='hint'>(" . $code . ")</span>";
}
}
$html .= "<li class='$classes'>\n";
$html .= "\t<a href='$href'>\n";
$html .= "\t\t<img src='$image' alt='>' /><span>" . $label . "</span>" . $hint . "\n";
$html .= "\t</a>\n";
$html .= "</li>\n";
}
return $html;
}
}
?>

View file

@ -1,35 +0,0 @@
<?php
class Customize {
private $customHeader, $customFooter;
public function __construct($h5ai) {
$absPath = $h5ai->getAbsPath();
$options = $h5ai->getOptions();
$this->customHeader = $options["customHeader"] ? $absPath . "/" . $options["customHeader"] : false;
$this->customFooter = $options["customFooter"] ? $absPath . "/" . $options["customFooter"] : false;
}
public function getHeader() {
return $this->getContent($this->customHeader, "header");
}
public function getFooter() {
return $this->getContent($this->customFooter, "footer");
}
private function getContent($file, $tag) {
return (is_string($file) && file_exists($file)) ? ("<$tag>" . file_get_contents($file) . "</$tag>") : "";
}
}
?>

105
src/_h5ai/php/inc/Entry.php Normal file
View file

@ -0,0 +1,105 @@
<?php
class Entry {
private static $cache = array();
public static function getCache() {
return Entry::$cache;
}
public static function get($h5ai, $absPath, $absHref) {
if (array_key_exists($absHref, Entry::$cache)) {
return Entry::$cache[$absHref];
}
return new Entry($h5ai, $absPath, $absHref);
}
public static function sort() {
uasort(Entry::$cache, function ($entry1, $entry2) {
return strcasecmp($entry1->absHref, $entry2->absHref);
});
}
public $h5ai, $absPath, $absHref, $date, $size, $isFolder, $parent;
private function __construct($h5ai, $absPath, $absHref) {
$this->h5ai = $h5ai;
$this->absPath = H5ai::normalize_path($absPath);
$this->isFolder = is_dir($this->absPath);
$this->absHref = H5ai::normalize_path($absHref, $this->isFolder);
$this->date = filemtime($this->absPath);
if ($this->isFolder) {
$this->size = null;
} else {
$this->size = filesize($this->absPath);
}
$this->parent = null;
if ($this->absHref !== "/") {
$this->parent = Entry::get($this->h5ai, H5ai::normalize_path(dirname($this->absPath)), H5ai::normalize_path(dirname($this->absHref), true));
}
Entry::$cache[$this->absHref] = $this;
}
public function toJsonObject($withStatus) {
$obj = array(
"absHref" => $this->absHref,
"time" => ($this->date * 1000),
"size" => $this->size
);
if ($withStatus && $this->isFolder) {
$obj["status"] = $this->h5ai->getHttpCode($this->absHref);
}
return $obj;
}
public function getParent() {
return $this->parent;
}
public function getContent() {
$content = array();
if ($this->h5ai->getHttpCode($this->absHref) !== "h5ai") {
return $content;
}
$files = $this->h5ai->readDir($this->absPath);
foreach ($files as $file) {
$entry = Entry::get($this->h5ai, $this->absPath . "/" . $file, $this->absHref . rawurlencode($file));
$content[$entry->absPath] = $entry;
}
return $content;
}
}
?>

View file

@ -1,152 +0,0 @@
<?php
require_h5ai("/php/inc/Thumbnail.php");
class Entry {
private $h5ai, $label, $absPath, $absHref, $date, $isFolder, $type, $size;
public function __construct($h5ai, $absPath, $absHref, $type = null, $label = null) {
$this->h5ai = $h5ai;
$this->label = $label !== null ? $label : $this->h5ai->getLabel($absHref);
$this->absPath = $this->h5ai->normalizePath($absPath, false);
$this->isFolder = is_dir($this->absPath);
$this->absHref = $this->h5ai->normalizePath($absHref, $this->isFolder);
$this->date = filemtime($this->absPath);
if ($this->isFolder) {
$this->type = $type !== null ? $type : "folder";
$this->size = "";
} else {
$this->type = $type !== null ? $type : $this->h5ai->getType($this->absPath);
$this->size = filesize($this->absPath);
}
}
public function isFolder() {
return $this->isFolder;
}
public function toHtml() {
$classes = "entry " . ($this->isFolder ? "folder " : "file ") . $this->type;
$imgClass = "";
$img = $this->type;
$smallImg = $this->h5ai->icon($this->type);
$bigImg = $this->h5ai->icon($this->type, true);
$hint = "";
if ($this->isFolder && $this->type !== "folder-parent") {
$code = $this->h5ai->getHttpCode($this->absHref);
$classes .= " checkedHttpCode";
if ($code !== "h5ai") {
if ($code === 200) {
$img = "folder-page";
$smallImg = $this->h5ai->icon("folder-page");
$bigImg = $this->h5ai->icon("folder-page", true);
} else {
$classes .= " error";
$hint = "<span class='hint'> " . $code . " </span>";
}
}
}
if ($this->h5ai->showThumbs() && in_array($this->type, $this->h5ai->getThumbTypes())) {
$imgClass = " class='thumb' ";
$thumbnail = new Thumbnail($this->h5ai, $this->absHref, "square", 16, 16);
$thumbnail->create();
$smallImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref();
$thumbnail = new Thumbnail($this->h5ai,$this->absHref, "rational", 96, 46);
$thumbnail->create();
$bigImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref();
}
$html = "\t<li class='" . $classes . "'>\n";
$html .= "\t\t<a href='" . $this->absHref . "'>\n";
$html .= "\t\t\t<span class='icon small'><img " . $imgClass . " src='" . $smallImg . "' alt='" . $img . "' /></span>\n";
$html .= "\t\t\t<span class='icon big'><img " . $imgClass . " src='" . $bigImg . "' alt='" . $img . "' /></span>\n";
$html .= "\t\t\t<span class='label'>" . $this->label . $hint . "</span>\n";
$html .= "\t\t\t<span class='date' data-time='" . $this->date . "000'></span>\n";
$html .= "\t\t\t<span class='size' data-bytes='" . $this->size . "'>" . $this->size . "</span>\n";
$html .= "\t\t</a>\n";
$html .= "\t</li>\n";
return $html;
}
}
class Extended {
private $h5ai, $parent, $content;
public function __construct($h5ai) {
$this->h5ai = $h5ai;
$this->parent = null;
$this->content = array();
$this->loadContent();
}
private function loadContent() {
if ($this->h5ai->getAbsHref() !== "/") {
$options = $this->h5ai->getOptions();
$parentPath = safe_dirname($this->h5ai->getAbsPath());
$parentHref = safe_dirname($this->h5ai->getAbsHref(), true);
$label = $options["setParentFolderLabels"] === true ? $this->h5ai->getLabel($parentHref) : "<span class='l10n-parentDirectory'>Parent Directory</span>";
$this->parent = new Entry($this->h5ai, $parentPath, $parentHref, "folder-parent", $label);
}
$this->content = array();
$files = $this->h5ai->readDir($this->h5ai->getAbsPath());
foreach ($files as $file) {
$absPath = $this->h5ai->getAbsPath() . "/" . $file;
$absHref = $this->h5ai->getAbsHref() . rawurlencode($file);
$this->content[$absPath] = new Entry($this->h5ai, $absPath, $absHref);
}
}
public function toHtml() {
$html = "<section id='extended' class='" . $this->h5ai->getView() . "-view clearfix'>\n";
$html .= "<ul>\n";
$html .= $this->generateHeaders();
if ($this->parent !== null) {
$html .= $this->parent->toHtml();
}
foreach($this->content as $entry) {
$html .= $entry->toHtml();
}
$html .= "</ul>\n";
if (count($this->content) === 0) {
$html .= "<div class='empty l10n-empty'>empty</div>";
}
$html .= "<div class='no-match l10n-noMatch'>no match</div>";
$html .="</section>";
return $html;
}
private function generateHeaders() {
$html = "\t<li class='header'>\n";
$html .= "\t\t<a class='icon'></a>\n";
$html .= "\t\t<a class='label' href='#'><span class='l10n-name'>Name</span></a>\n";
$html .= "\t\t<a class='date' href='#'><span class='l10n-lastModified'>Last modified</span></a>\n";
$html .= "\t\t<a class='size' href='#'><span class='l10n-size'>Size</span></a>\n";
$html .= "\t</li>\n";
return $html;
}
}
?>

View file

@ -1,58 +1,43 @@
<?php
require_h5ai("/config.php");
require_h5ai("/php/inc/Cache.php");
define("H5AI_ABS_PATH", H5ai::normalize_path(dirname(dirname(dirname(__FILE__)))));
H5ai::req_once("/config.php");
H5ai::req_once("/php/inc/Cache.php");
H5ai::req_once("/php/inc/Entry.php");
class H5ai {
private static $VIEWMODES = array("details", "icons");
private $h5aiAbsPath,
$rootAbsPath, $ignore, $ignoreRE,
$config, $options, $types, $langs,
$cache,
$rootAbsHref, $h5aiAbsHref, $domain,
$absHref, $absPath,
$view;
public static final function normalize_path($path, $endWithSlash = false) {
public function __construct() {
$this->checks = array(
"php" => version_compare(PHP_VERSION, "5.2.0") >= 0,
"zip" => class_exists("ZipArchive"),
"gd" => GD_VERSION != "GD_VERSION"
);
$this->h5aiAbsPath = H5AI_ABS_PATH;
global $H5AI_CONFIG;
$this->rootAbsPath = $H5AI_CONFIG["ROOT_ABS_PATH"];
$this->ignore = $H5AI_CONFIG["IGNORE"];
$this->ignoreRE = $H5AI_CONFIG["IGNORE_PATTERNS"];
$this->config = $this->loadConfig($this->h5aiAbsPath . "/config.js");
$this->options = $this->config["options"];
$this->types = $this->config["types"];
$this->langs = $this->config["langs"];
$this->cache = new Cache($this->h5aiAbsPath . "/cache");
$this->rootAbsHref = $this->options["rootAbsHref"];
$this->h5aiAbsHref = $this->options["h5aiAbsHref"];
$this->domain = getenv("HTTP_HOST");
$this->absHref = $this->normalizePath(preg_replace('/\\?.*/', '', getenv("REQUEST_URI")), true);
$this->absPath = $this->getAbsPath($this->absHref);
$this->view = $this->options["viewmodes"][0];
if (!in_array($this->view, H5ai::$VIEWMODES)) {
$this->view = H5ai::$VIEWMODES[0];
}
$path = str_replace("\\", "/", $path);
return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : ""));
}
private function loadConfig($file) {
public static final function req_once($lib) {
require_once(H5AI_ABS_PATH . $lib);
}
public static final function starts_with($sequence, $start) {
return strcasecmp(substr($sequence, 0, strlen($start)), $start) === 0;
}
public static final function ends_with($sequence, $end) {
return strcasecmp(substr($sequence, -strlen($end)), $end) === 0;
}
private static final function load_config($file) {
$str = file_exists($file) ? file_get_contents($file) : "";
@ -66,9 +51,43 @@ class H5ai {
}
public function getH5aiAbsPath() {
return $this->h5aiAbsPath;
private $h5aiAbsPath,
$rootAbsPath, $ignore, $ignoreRE,
$config, $options,
$cache,
$rootAbsHref, $h5aiAbsHref,
$absHref, $absPath;
public function __construct() {
$this->h5aiAbsPath = H5ai::normalize_path(H5AI_ABS_PATH);
global $H5AI_CONFIG;
$this->rootAbsPath = H5ai::normalize_path($H5AI_CONFIG["ROOT_ABS_PATH"]);
$this->ignore = $H5AI_CONFIG["IGNORE"];
$this->ignoreRE = $H5AI_CONFIG["IGNORE_PATTERNS"];
$this->config = H5ai::load_config($this->h5aiAbsPath . "/config.js");
$this->options = $this->config["options"];
$this->rootAbsHref = H5ai::normalize_path($this->options["rootAbsHref"], true);
$this->h5aiAbsHref = H5ai::normalize_path($this->options["h5aiAbsHref"], true);
$this->absHref = H5ai::normalize_path(preg_replace('/\\?.*/', '', getenv("REQUEST_URI")), true);
$this->absPath = $this->getAbsPath($this->absHref);
$this->cache = new Cache($this->h5aiAbsPath . "/cache");
$this->checks = array(
"php" => version_compare(PHP_VERSION, "5.2.0") >= 0,
"zip" => class_exists("ZipArchive"),
"gd" => GD_VERSION != "GD_VERSION",
"cache" => is_writable($this->h5aiAbsPath . "/cache"),
"temp" => is_writable(sys_get_temp_dir())
);
}
@ -78,6 +97,12 @@ class H5ai {
}
public function getH5aiAbsPath() {
return $this->h5aiAbsPath;
}
public function getRootAbsHref() {
return $this->rootAbsHref;
@ -90,54 +115,18 @@ class H5ai {
}
public function getDomain() {
return $this->domain;
}
public function getView() {
return $this->view;
}
public function api() {
return $this->h5aiAbsHref . "php/api.php";
}
public function image($id) {
return $this->h5aiAbsHref . "images/" . $id . ".png";
}
public function icon($id, $big = false) {
return $this->h5aiAbsHref . "icons/" . ($big ? "48x48" : "16x16") . "/" . $id . ".png";
}
public function getOptions() {
return $this->options;
}
public function getLangs() {
return $this->langs;
}
public function normalizePath($path, $endWithSlash) {
return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : ""));
}
public function getAbsHref($absPath = null, $endWithSlash = true) {
if ($absPath === null) {
@ -152,7 +141,7 @@ class H5ai {
$encodedParts[] = rawurlencode($part);
}
return $this->normalizePath($this->rootAbsHref . implode("/", $encodedParts), $endWithSlash);
return H5ai::normalize_path($this->rootAbsHref . implode("/", $encodedParts), $endWithSlash);
}
@ -164,51 +153,14 @@ class H5ai {
$absHref = substr($absHref, strlen($this->rootAbsHref));
return $this->normalizePath($this->rootAbsPath . "/" . rawurldecode($absHref), false);
}
public function showThumbs() {
return $this->options["showThumbs"] === true;
}
public function getThumbTypes() {
return $this->options["thumbTypes"];
}
public function getTitle() {
$title = $this->domain . rawurldecode($this->absHref);
$title = preg_replace("/\/$/", "", $title);
$title = preg_replace("/\//", " > ", $title);
if ($this->absHref !== "/") {
$title = basename($this->absPath) . " - " . $title;
}
return $title;
}
public function getType($absPath) {
foreach($this->types as $type => $exts) {
foreach($exts as $ext) {
if ($this->endsWith($absPath, $ext)) {
return $type;
}
}
}
return "unknown";
return H5ai::normalize_path($this->rootAbsPath . "/" . rawurldecode($absHref));
}
public function ignoreThisFile($file) {
// always ignore
if ($file === "." || $file === ".." || $this->startsWith($file, '.ht')) {
if ($file === "." || $file === ".." || H5ai::starts_with($file, '.ht')) {
return true;
}
@ -242,24 +194,6 @@ class H5ai {
}
public function getLabel($absHref) {
return $absHref === "/" ? $this->domain : rawurldecode(basename($absHref));
}
public function startsWith($sequence, $start) {
return strcasecmp(substr($sequence, 0, strlen($start)), $start) === 0;
}
public function endsWith($sequence, $end) {
return strcasecmp(substr($sequence, -strlen($end)), $end) === 0;
}
public function getHttpCode($absHref) {
//return $this->cachedHttpCode($absHref);
@ -271,12 +205,7 @@ class H5ai {
$cached = $this->cache->get($absHref);
if ($cached === false) {
$folderStatus = $this->options["folderStatus"];
if (array_key_exists($absHref, $folderStatus)) {
$code = $folderStatus[$absHref];
} else {
$code = $this->fetchHttpCode($absHref);
}
$code = $this->fetchHttpCode($absHref);
$cached = array("href" => $absHref, "code" => $code);
$this->cache->set($absHref, $cached);
}
@ -286,6 +215,17 @@ class H5ai {
public function fetchHttpCode($absHref) {
if (!is_dir($this->getAbsPath($absHref))) {
return null;
}
if ($this->options["folderstatus"]["enabled"]) {
$folders = $this->options["folderstatus"]["folders"];
if (array_key_exists($absHref, $folders)) {
return $folders[$absHref];
}
}
$contentType = "Content-Type:";
$h5aiContentType = "Content-Type: text/html;h5ai=";
$host = getenv("HTTP_HOST");
@ -307,16 +247,53 @@ class H5ai {
$content = fgets($socket);
$code = intval(trim(substr($content, 9, 4)));
if ($code === 200) {
while (! $this->startsWith($content, $contentType)) {
while (! H5ai::starts_with($content, $contentType)) {
$content = fgets($socket);
}
if ($this->startsWith($content, $h5aiContentType)) {
if (H5ai::starts_with($content, $h5aiContentType)) {
$code = "h5ai";
}
}
fclose($socket);
return $code;
}
private function fileExists($file) {
return is_string($file) && file_exists($file);
}
public function getGenericJson() {
$header = $this->options["custom"]["header"];
$footer = $this->options["custom"]["footer"];
$header = $this->fileExists($header ? $this->absPath . "/" . $header : null) ? $header : null;
$footer = $this->fileExists($footer ? $this->absPath . "/" . $footer : null) ? $footer : null;
// collect and sort entries
$folder = Entry::get($this, $this->absPath, $this->absHref);
while ($folder !== null) {
$folder->getContent();
$folder = $folder->getParent();
}
Entry::sort();
$entries = array();
foreach(Entry::getCache() as $entry) {
$entries[] = $entry->toJsonObject(true);
}
$json = array(
"entries" => $entries,
"customHeader" => $header,
"customFooter" => $footer
);
return json_encode($json) . "\n";
}
}
?>

View file

@ -51,7 +51,15 @@ class Image {
$this->sourceFile = $filename;
list($this->width, $this->height, $this->type) = getimagesize($this->sourceFile);
list($this->width, $this->height, $this->type) = @getimagesize($this->sourceFile);
if (!$this->width || !$this->height) {
$this->sourceFile = null;
$this->width = null;
$this->height = null;
$this->type = null;
return;
}
$this->source = imagecreatefromstring(file_get_contents($this->sourceFile));
}
@ -99,6 +107,10 @@ class Image {
private function magic($destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight, $canWidth = null, $canHeight = null, $color = null) {
if (is_null($this->source)) {
return;
}
if (!is_null($canWidth) && !is_null($canHeight)) {
$this->dest = imagecreatetruecolor($canWidth, $canHeight);
} else {
@ -134,6 +146,10 @@ class Image {
public function squareThumb($width) {
if (is_null($this->source)) {
return;
}
$a = min($this->width, $this->height);
$x = intval(($this->width - $a) / 2);
$y = intval(($this->height - $a) / 2);
@ -144,6 +160,10 @@ class Image {
public function rationalThumb($width, $height) {
if (is_null($this->source)) {
return;
}
$r = 1.0 * $this->width / $this->height;
$h = $height;
@ -164,6 +184,10 @@ class Image {
public function centerThumb($width, $height, $color = null) {
if (is_null($this->source)) {
return;
}
$r = 1.0 * $this->width / $this->height;
$h = $height;
@ -187,6 +211,10 @@ class Image {
public function freeThumb($width, $height) {
if (is_null($this->source)) {
return;
}
$w = intval($width);
$h = intval($height);

View file

@ -1,6 +1,6 @@
<?php
require_h5ai("/php/inc/Image.php");
H5ai::req_once("/php/inc/Image.php");
class Thumbnail {

View file

@ -1,158 +0,0 @@
<?php
class TreeEntry {
private $h5ai, $label, $absPath, $absHref, $isFolder, $type, $content;
public function __construct($h5ai, $absPath, $absHref, $type = null) {
$this->h5ai = $h5ai;
$this->label = $this->h5ai->getLabel($absHref);
$this->absPath = $this->h5ai->normalizePath($absPath, false);
$this->isFolder = is_dir($this->absPath);
$this->absHref = $this->h5ai->normalizePath($absHref, $this->isFolder);
$this->type = $type !== null ? $type : ($this->isFolder ? "folder" : $this->h5ai->getType($this->absPath));
$this->content = null;
}
public function loadContent() {
$this->content = array();
if ($this->h5ai->getHttpCode($this->absHref) !== "h5ai") {
return;
}
$files = $this->h5ai->readDir($this->absPath);
foreach ($files as $file) {
$tree = new TreeEntry($this->h5ai, $this->absPath . "/" . $file, $this->absHref . rawurlencode($file));
if ($tree->isFolder) {
$this->content[$tree->absPath] = $tree;
}
}
$this->sort();
}
public function cmpTrees($t1, $t2) {
if ($t1->isFolder && !$t2->isFolder) {
return -1;
}
if (!$t1->isFolder && $t2->isFolder) {
return 1;
}
return strcasecmp($t1->absPath, $t2->absPath);
}
public function sort() {
if ($this->content !== null) {
uasort($this->content, array($this, "cmpTrees"));
}
}
public function toHtml() {
$classes = "entry " . $this->type . ($this->absHref === $this->h5ai->getAbsHref() ? " current" : "");
$icon = $this->type;
if ($this->absHref === "/") {
$icon = "folder-home";
}
$hint = "";
$code = "h5ai";
if ($this->isFolder) {
$code = $this->h5ai->getHttpCode($this->absHref);
$classes .= " checkedHttpCode";
if ($code !== "h5ai") {
if ($code === 200) {
$icon = "folder-page";
$hint = "<span class='hint'><img src='" . $this->h5ai->image("page") . "' alt='page' /></span>";
} else {
$classes .= " error";
$hint = "<span class='hint'> " . $code . " </span>";
}
}
}
$html = "<div class='" . $classes ."'>\n";
if ($this->content !== null && count($this->content) === 0 || $code !== "h5ai") {
$html .= "<span class='blank'></span>\n";
} else {
$indicatorState = $this->content === null ? " unknown" : " open";
$html .= "<span class='indicator" . $indicatorState . "'><img src='" . $this->h5ai->image("tree") . "' alt='>' /></span>\n";
}
$html .= "<a href='" . $this->absHref . "'>\n";
$html .= "<span class='icon'><img src='" . $this->h5ai->icon($icon) . "' alt='" . $icon . "' /></span>";
$html .= "<span class='label'>" . $this->label . "</span>" . $hint . "\n";
$html .= "</a>\n";
$html .= $this->contentToHtml();
$html .= "</div>\n";
return $html;
}
public function contentToHtml() {
$html = "<ul class='content'>\n";
if ($this->content !== null) {
foreach($this->content as $tree) {
$html .= "<li>" . $tree->toHtml() . "</li>";
}
}
$html .= "</ul>\n";
return $html;
}
public function getRoot() {
if ($this->absHref === "/") {
return $this;
};
$tree = new TreeEntry($this->h5ai, safe_dirname($this->absPath), safe_dirname($this->absHref, true));
$tree->loadContent();
$tree->content[$this->absPath] = $this;
return $tree->getRoot();
}
}
class Tree {
private $h5ai;
public function __construct($h5ai) {
$this->h5ai = $h5ai;
}
public function toHtml() {
$options = $this->h5ai->getOptions();
if ($options["showTree"] === false) {
return "";
}
$tree = new TreeEntry($this->h5ai, $this->h5ai->getAbsPath(), $this->h5ai->getAbsHref());
$tree->loadContent();
$root = $tree->getRoot();
return "<section id='tree'>\n" . $root->toHtml() . "</section>\n";
}
}
?>

View file

@ -28,7 +28,7 @@ class ZipIt {
$zip->addEmptyDir("/");
foreach ($hrefs as $href) {
$d = safe_dirname($href, true);
$d = H5ai::normalize_path(dirname($href, true));
$n = basename($href);
$code = $this->h5ai->getHttpCode($d);
if ($code == 401) {
@ -82,7 +82,7 @@ class ZipIt {
}
}
}
return code;
return $code;
}
}

View file

@ -1,28 +0,0 @@
<?php
function safe_dirname($path, $endWithSlash = false) {
$path = str_replace("\\", "/", dirname($path));
return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : ""));
}
define("H5AI_ABS_PATH", safe_dirname(safe_dirname(__FILE__)));
function require_h5ai($lib) {
require_once(H5AI_ABS_PATH . $lib);
}
require_h5ai("/php/inc/H5ai.php");
require_h5ai("/php/inc/Crumb.php");
require_h5ai("/php/inc/Customize.php");
require_h5ai("/php/inc/Extended.php");
require_h5ai("/php/inc/Tree.php");
$h5ai = new H5ai();
$crumb = new Crumb($h5ai);
$customize = new Customize($h5ai);
$extended = new Extended($h5ai);
$tree = new Tree($h5ai);
?>

View file

@ -6,21 +6,25 @@
# Options +Indexes
# Options +FollowSymLinks
# pure JavaScript version
HeaderName /_h5ai/header.html
# PHP version
# HeaderName /_h5ai/header.php
# pure JavaScript version
ReadmeName /_h5ai/footer.html
# PHP version
# ReadmeName /_h5ai/footer.php
IndexIgnore _h5ai*
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions Charset=UTF-8
IndexOptions FancyIndexing
IndexOptions FoldersFirst
IndexOptions HTMLTable
IndexOptions NameWidth=*
IndexOptions SuppressDescription
IndexOptions SuppressHTMLPreamble
IndexOptions SuppressRules
IndexOptions SuppressDescription
IndexOptions NameWidth=*
IndexOptions HTMLTable
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions XHTML

59
src/index.php Normal file
View file

@ -0,0 +1,59 @@
<?php header("Content-type: text/html;h5ai=%BUILD_VERSION%"); ?>
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Directory index · styled with h5ai</title>
<meta name="description" content="Directory index styled with h5ai (http://larsjung.de/h5ai)">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/png" href="/_h5ai/images/h5ai-16x16.png">
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" href="/_h5ai/css/styles.css">
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
</head>
<body id="h5ai-main">
<div id="topbar" class="clearfix">
<ul id="navbar"></ul>
</div>
<div id="content">
<div id="extended" class="clearfix"></div>
</div>
<div id="bottombar" class="clearfix">
<span class="left">
<a id="h5ai-reference" href="http://larsjung.de/h5ai" title="h5ai project page">h5ai %BUILD_VERSION%</a>
<span class="hideOnJs noJsMsg"> JavaScript is disabled! </span>
<span class="oldBrowser"> Some features disabled! Works best in <a href="http://browsehappy.com">modern browsers</a>. </span>
</span>
<span class="right"></span>
<span class="center"></span>
</div>
<script src="/_h5ai/config.js"></script>
<script src="/_h5ai/js/scripts.js"></script>
<div id="data-generic-json" class="hidden">
<?php if (stripos($_SERVER["REQUEST_METHOD"], "HEAD") === false) {
function find_h5ai($path, $h5ai) {
if (file_exists($path . $h5ai)) {
return $path . $h5ai;
} else {
$parent = str_replace("\\", "/", dirname($path));
if ($parent !== $path) {
return find_h5ai($parent, $h5ai);
}
}
error_log("h5ai not found from " . __DIR__);
}
require_once(find_h5ai(str_replace("\\", "/", __DIR__), "/_h5ai/php/inc/H5ai.php"));
$h5ai = new H5ai();
echo $h5ai->getGenericJson();
} ?>
</div>
</body>
</html>