Added PHP implementation. For a full list of changes see README.md.

This commit is contained in:
Lars Jung 2011-08-06 13:26:44 +02:00
parent 8da046d550
commit b9835ebaad
44 changed files with 1896 additions and 551 deletions

View file

@ -9,17 +9,31 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
## Changelog
#### v0.12.3 · *2011-07-30*
### v0.13 · *2011-08-06*
* added tr translation by [Batuhan Icoz](http://github.com/batuhanicoz/h5ai)
* added PHP implementation! (should work with PHP 5.2+)
* added new options
* changed layout of the bottom bar to display status information
* added language selector to the bottom bar
* quoted keys in `options.js` to make it valid json
* changed value of option `lang` from `undefined` to `null`
* added some new keys to `h5aiLangs`
* added browser caching rules for css and js
* added pt translation by [Jonnathan](http://github.com/jonnsl)
* added bg translation by George Andonov
#### v0.12.2 · *2011-07-30*
### v0.12.3 · *2011-07-30*
* added tr translation by [Batuhan Icoz](http://github.com/batuhanicoz)
### v0.12.2 · *2011-07-30*
* added es translation by Jose David Calderon Serrano
#### v0.12.1 · *2011-07-29*
### v0.12.1 · *2011-07-29*
* fixed unchecked use of console.log
@ -34,12 +48,12 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
* changed license to MIT license, see `LICENSE.txt`
#### v0.10.2 · *2011-07-26*
### v0.10.2 · *2011-07-26*
* improved tree scrollbar
#### v0.10.1 · *2011-07-24*
### v0.10.1 · *2011-07-24*
* fixed problems with ' in links
@ -85,7 +99,7 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
* added localization, see `options.js`
#### v0.5.3 · *2011-07-04*
### v0.5.3 · *2011-07-04*
* refactored js
* added basic options support via `options.js`
@ -93,13 +107,13 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
* optional tree sidebar
#### v0.5.2 · *2011-07-02*
### v0.5.2 · *2011-07-02*
* details view adjusts to window width
* linked icon for *.gz and *.bz2
#### v0.5.1 · *2011-07-01*
### v0.5.1 · *2011-07-01*
* disabled tree sidebar for now, since it had unwanted side effects
@ -119,13 +133,13 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
* updated dot.access
#### v0.3.2 · *2011-06-24*
### v0.3.2 · *2011-06-24*
* removed lib versions from file names
* added 'empty' indicator for icons view
#### v0.3.1 · *2011-06-24*
### v0.3.1 · *2011-06-24*
* refactored js
* added `folderClick` and `fileClick` callback hooks
@ -140,20 +154,20 @@ It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-1733
* updated jQuery to version 1.6.1
#### v0.2.3 · *2011-06-17*
### v0.2.3 · *2011-06-17*
* more refactoring in main.js
* ~~added custom js support, and global includes~~ *removed, only custom top and bottom sections supported*
#### v0.2.2 · *2011-06-16*
### v0.2.2 · *2011-06-16*
* refactored a lot, added some comments
* included fixes from [NumEricR](http://github.com/NumEricR/h5ai)
* included fixes from [NumEricR](http://github.com/NumEricR)
* added top/bottom message support, only basicly styled
#### v0.2.1 · *2011-06-16*
### v0.2.1 · *2011-06-16*
* fixed croped filenames
* fixed missing .png extension in header

View file

@ -3,7 +3,7 @@ custom = true
# project
project.name = h5ai
project.version = 0.12.3
project.version = 0.13
# src

Binary file not shown.

BIN
release/h5ai-0.13.tar.gz Normal file

Binary file not shown.

16
src/h5ai/.htaccess Normal file
View file

@ -0,0 +1,16 @@
AddType text/html .php
# cache images, css and js for 52 weeks
<IfModule headers_module>
<FilesMatch "\.png$">
Header set Cache-Control "max-age=31449600, public"
</FilesMatch>
<FilesMatch "\.css$">
Header set Cache-Control "max-age=31449600, public"
</FilesMatch>
<FilesMatch "\.js$">
Header set Cache-Control "max-age=31449600, public"
</FilesMatch>
</IfModule>

7
src/h5ai/cache/readme.md vendored Normal file
View file

@ -0,0 +1,7 @@
# Cache
This directory is used for server side caching. To use caching make this
directory writable for Apache.
There is no critical data in here. You can savely remove any content. This
will clear the cache.

View file

@ -64,6 +64,16 @@
}
}
}
&.folder-parent {
.date, .size {
display: none;
}
}
&.folder {
.size {
display: none;
}
}
}
.icon, .label, .date, .size {
padding: 6px;

View file

@ -1,15 +1,15 @@
@import "inc/html5reset";
@import "inc/mixins";
@import "html5reset";
@import "mixins";
html.js {
.jsDisabledFallback {
.hideOnJs {
display: none;
}
}
html.no-js {
body > nav ul {
.hideOnNoJs {
display: none;
}
}
@ -109,9 +109,9 @@ body > nav {
}
@import "inc/table";
@import "inc/extended";
@import "inc/tree";
@import "table";
@import "extended";
@import "tree";
body > footer {
@ -120,7 +120,7 @@ body > footer {
width: 100%;
left: 0;
bottom: 0;
padding: 10px 0;
padding: 6px 0 8px 0;
background-color: rgb(241,241,241);
border-top: 2px solid rgb(210,210,210);
@ -132,27 +132,63 @@ body > footer {
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 300px;
}
.right {
display: block;
padding: 0 8px;
float: right
}
#langSelector {
position: relative;
cursor: pointer;
.langOptions {
position: absolute;
z-index: 2;
display: none;
right: 0;
top: 0;
background-color: rgb(241,241,241);
border: 1px solid rgb(210,210,210);
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);
}
}
}
}
}
}
#html5 {
position: absolute;
left: 6px;
bottom: 6px;
opacity: 0.4;
.transition( all 0.2s ease-in-out );
img {
width: 20px;
height: 20px;
}
&:hover {
opacity: 0.8;
}
}

View file

@ -1,9 +1,10 @@
#tree {
position: fixed;
display: none;
position: fixed;
left: 0;
top: 0;
top: 82px;
z-index: 1;
overflow: auto;
font-size: 0.85em;
padding: 16px 16px 16px 16px;

View file

@ -0,0 +1,3 @@
@import "inc/main";

View file

@ -0,0 +1,15 @@
@import "inc/main";
#table {
display: none;
}
#tree, #content > header, #content > footer {
display: block;
}
html.no-js {
#extended.details-view, #extended.icons-view {
display: block;
}
}

View file

@ -4,20 +4,27 @@
<footer></footer>
</section>
<section id="tree"></section>
<footer>
<a id="html5" href="http://www.w3.org/html/logo/" target="_blank" title="HTML5 semantics, storage & CSS3">
<img class="logo" src="/h5ai/images/html5.png" alt="html5" />
<img class="techclass" src="/h5ai/images/html5-semantics.png" alt="html5-semantics" />
<img class="techclass" src="/h5ai/images/html5-storage.png" alt="html5-storage" />
<img class="techclass" src="/h5ai/images/html5-css3.png" alt="html5-css3" />
</a>
<a href="http://larsjung.de/h5ai" target="_blank" title="h5ai project page">h5ai %BUILD_VERSION%</a>
<span class="l10n-footerUsing">using</span>
<a href="http://tiheum.deviantart.com/art/Faenza-Icons-173323228" target="_blank" title="icon theme for Gnome">Faenza icons</a>
<footer class="clearfix">
<span class="left">
<a href="http://larsjung.de/h5ai" target="_blank" title="h5ai project page">h5ai %BUILD_VERSION% (js)</a>
</span>
<span class="right">
<span class="hideOnJs">JavaScript is disabled!</span>
<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="folderCount"></span> <span class="l10n-folders">folders</span>
·
<span class="fileCount"></span> <span class="l10n-files">files</span>
</span>
</span>
</footer>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script>window.jQuery || document.write( '<script src="/h5ai/js/lib/jquery.min.js"><\/script>' )</script>
<script src="/h5ai/js/lib/jquery.min.js"></script>
<script src="/h5ai/options.js"></script>
<script src="/h5ai/js/main.js"></script>
<script src="/h5ai/js/main-js.js"></script>
</body>
</html>

4
src/h5ai/footer.php Normal file
View file

@ -0,0 +1,4 @@
<!-- generated code ends here -->
</section>
</body>
</html>

View file

@ -3,30 +3,29 @@
<head>
<meta charset="utf-8">
<title>Directory index · styled with h5ai</title>
<meta name="h5ai-version" content="h5ai %BUILD_VERSION%">
<meta name="h5ai-version" content="h5ai %BUILD_VERSION% (js)">
<meta name="description" content="Directory index styled with h5ai (http://larsjung.de/h5ai)">
<meta name="keywords" content="directory, index, autoindex, h5ai">
<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" type="text/css" href="http://fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" type="text/css" href="/h5ai/css/main.css">
<link rel="stylesheet" type="text/css" href="/h5ai/css/main-js.css">
<script src="/h5ai/js/lib/modernizr.min.js"></script>
</head>
<body>
<nav class="clearfix">
<span class="jsDisabledFallback">Directory index · JavaScript is disabled</span>
<ul>
<li id="viewicons" class="view">
<a href="#"><img src="/h5ai/images/view-icons.png" alt="view-icons" /><span class="l10n-viewIcons">icons</span></a>
<li id="viewicons" class="view hideOnNoJs">
<a href="#"><img src="/h5ai/images/view-icons.png" alt="view-icons" /><span class="l10n-icons">icons</span></a>
</li>
<li id="viewdetails" class="view" >
<a href="#"><img src="/h5ai/images/view-details.png" alt="view-details" /><span class="l10n-viewDetails">details</span></a>
<li id="viewdetails" class="view hideOnNoJs" >
<a href="#"><img src="/h5ai/images/view-details.png" alt="view-details" /><span class="l10n-details">details</span></a>
</li>
</ul>
</nav>
<section id="content">
<header></header>
<section id="table" class="jsDisabledFallback">
<section id="table" class="hideOnJs">
<!--
The following code was generated by apache's autoindex module. It is not valid HTML 5 for the
reason, that 'align' and 'valign' attributes on the td element are obsolete. Both of them are

55
src/h5ai/header.php Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html class="no-js">
<?php include "php/main.php"; ?>
<head>
<meta charset="utf-8">
<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="keywords" content="directory, index, autoindex, h5ai">
<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" type="text/css" href="http://fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
<link rel="stylesheet" type="text/css" href="/h5ai/css/main-php.css">
<script src="/h5ai/js/lib/modernizr.min.js"></script>
</head>
<body>
<nav class="clearfix">
<ul>
<?php echo $crumb->toHtml(); ?>
<li id="viewicons" class="view hideOnNoJs">
<a href="#"><img src="/h5ai/images/view-icons.png" alt="view-icons" /><span class="l10n-icons">icons</span></a>
</li>
<li id="viewdetails" class="view hideOnNoJs" >
<a href="#"><img src="/h5ai/images/view-details.png" alt="view-details" /><span class="l10n-details">details</span></a>
</li>
</ul>
</nav>
<?php echo $tree->toHtml(); ?>
<section id="content">
<?php echo $customize->getHeader(); ?>
<?php echo $extended->toHtml(); ?>
<?php echo $customize->getFooter(); ?>
</section>
<footer class="clearfix">
<span class="left">
<a href="http://larsjung.de/h5ai" target="_blank" title="h5ai project page">h5ai %BUILD_VERSION% (php)</a>
</span>
<span class="right">
<span class="hideOnJs">JavaScript is disabled!</span>
<span id="langSelector">
<span class="lang">en</span> - <span class="l10n-lang">english</span>
<span class="langOptions"></span>
</span>
</span>
<span class="center">
<?php echo $extended->getFolderCount(); ?> <span class="l10n-folders">folders</span>
·
<?php echo $extended->getFileCount(); ?> <span class="l10n-files">files</span>
</span>
</footer>
<script src="/h5ai/js/lib/jquery.min.js"></script>
<script src="/h5ai/options.js"></script>
<script src="/h5ai/js/main-php.js"></script>
<section id="table">
<!-- the following code was generated by apache's autoindex module and gets ignored -->

View file

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 494 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

155
src/h5ai/js/inc/extended.js Normal file
View file

@ -0,0 +1,155 @@
var Extended = function ( pathCache ) {
/*******************************
* config
*******************************/
this.config = {
defaultSortOrder: "C=N;O=A",
customHeader: "h5ai.header.html",
customFooter: "h5ai.footer.html"
};
/*******************************
* init
*******************************/
this.init = function () {
try {
document.title = decodeURI( document.domain + document.location.pathname );
} catch ( err ) {
document.title = document.domain + document.location.pathname;
};
this.initBreadcrumb();
this.initExtendedView();
this.customize();
this.initCounts();
};
/*******************************
* breadcrumb
*******************************/
this.initBreadcrumb = function () {
var $ul = $( "body > nav ul" );
var pathname = "/";
var path = pathCache.getPathForFolder( pathname );
$ul.append( path.updateCrumbHtml() );
var pathnameParts = document.location.pathname.split( "/" );
for ( idx in pathnameParts ) {
var part = pathnameParts[idx];
if ( part !== "" ) {
pathname += part + "/";
var path = pathCache.getPathForFolder( pathname );
$ul.append( path.updateCrumbHtml() );
};
};
};
/*******************************
* extended view
*******************************/
this.initExtendedView = function () {
var $ul = $( "<ul/>" );
// headers
var $ths = $( "#table th" );
var $label = $ths.eq( 1 ).find( "a" );
var $date = $ths.eq( 2 ).find( "a" );
var $size = $ths.eq( 3 ).find( "a" );
var $li = $( "<li class='header' />" ).appendTo( $ul );
$( "<a class='icon'></a>" ).appendTo( $li );
$( "<a class='label' href='" + $label.attr( "href" ) + "'><span class='l10n-name'>" + $label.text() + "</span></a>" ).appendTo( $li );
$( "<a class='date' href='" + $date.attr( "href" ) + "'><span class='l10n-lastModified'>" + $date.text() + "</span></a>" ).appendTo( $li );
$( "<a class='size' href='" + $size.attr( "href" ) + "'><span class='l10n-size'>" + $size.text() + "</span></a>" ).appendTo( $li );
// header sort icons
var order = document.location.search;
if ( order === "" ) {
order = this.config.defaultSortOrder;
};
var $icon;
if ( order.indexOf( "O=A" ) >= 0 ) {
$icon = $( "<img src='/h5ai/images/ascending.png' class='sort' alt='ascending' />" );
} else {
$icon = $( "<img src='/h5ai/images/descending.png' class='sort' alt='descending' />" );
};
if ( order.indexOf( "C=N" ) >= 0 ) {
$li.find( "a.label" ).append( $icon );
} else if ( order.indexOf( "C=M" ) >= 0 ) {
$li.find( "a.date" ).prepend( $icon );
} else if ( order.indexOf( "C=S" ) >= 0 ) {
$li.find( "a.size" ).prepend( $icon );
};
$.timer.log( "start entries" );
// entries
$( "#table td" ).closest( "tr" ).each( function () {
var path = pathCache.getPathForTableRow( document.location.pathname, this );
$ul.append( path.updateExtendedHtml() );
} );
$.timer.log( "end entries" );
$( "#extended" ).append( $ul );
$.log( document.location.pathname, "folders:", $( "#extended .folder" ).size() , "files:", $( "#extended .file" ).size() );
// empty
if ( $ul.children( ".entry:not(.parentfolder)" ).size() === 0 ) {
$( "#extended" ).append( $( "<div class='empty l10n-empty'>empty</div>" ) );
};
// in case of floats
$( "#extended" ).addClass( "clearfix" );
};
/*******************************
* customize
*******************************/
this.customize = function () {
$.ajax( {
url: this.config.customHeader,
dataType: "html",
success: function ( data ) {
$( "#content > header" ).append( $( data ) ).show();
}
} );
$.ajax( {
url: this.config.customFooter,
dataType: "html",
success: function ( data ) {
$( "#content > footer" ).prepend( $( data ) ).show();
}
} );
};
/*******************************
* init counts
*******************************/
this.initCounts = function () {
$( ".folderCount" ).text( $( "#extended .entry.folder:not(.parentfolder)" ).size() );
$( ".fileCount" ).text( $( "#extended .entry.file" ).size() );
};
};

View file

@ -1,5 +1,5 @@
var H5ai = function ( options, langs, pathCache ) {
var H5ai = function ( options, langs ) {
/*******************************
@ -7,28 +7,27 @@ var H5ai = function ( options, langs, pathCache ) {
*******************************/
var defaults = {
defaultSortOrder: "C=N;O=A",
store: {
viewmode: "h5ai.viewmode"
viewmode: "h5ai.viewmode",
lang: "h5ai.lang"
},
customHeader: "h5ai.header.html",
customFooter: "h5ai.footer.html",
callbacks: {
pathClick: []
},
viewmodes: [ "details", "icons" ],
showTree: false,
showTree: true,
folderStatus: {
},
lang: undefined,
lang: null,
useBrowserLang: true,
setParentFolderLabels: true,
linkHoverStates: true
};
this.config = $.extend( {}, defaults, options );
/*******************************
* public api
*******************************/
@ -49,14 +48,14 @@ var H5ai = function ( options, langs, pathCache ) {
this.init = function () {
document.title = decodeURI( document.domain + document.location.pathname );
this.applyViewmode();
this.initBreadcrumb();
this.initTopSpace();
this.initViews();
this.customize();
this.initTree();
this.linkHoverStates();
this.initLangSelector( langs );
this.localize( langs, this.config.lang, this.config.useBrowserLang );
this.initIndicators();
};
@ -93,7 +92,7 @@ var H5ai = function ( options, langs, pathCache ) {
viewmode = this.getViewmode();
$( "#viewdetails,#viewicons" ).hide().removeClass( "current" );
if ( this.config.viewmodes.length > 1 ) {
if ( $.inArray( "details", this.config.viewmodes ) >= 0 ) {
$( "#viewdetails" ).show();
@ -116,31 +115,6 @@ var H5ai = function ( options, langs, pathCache ) {
/*******************************
* breadcrumb
*******************************/
this.initBreadcrumb = function () {
var $ul = $( "body > nav ul" );
var pathname = "/";
var path = pathCache.getPathForFolder( pathname );
$ul.append( path.updateCrumbHtml() );
var pathnameParts = document.location.pathname.split( "/" );
for ( idx in pathnameParts ) {
var part = pathnameParts[idx];
if ( part !== "" ) {
pathname += part + "/";
var path = pathCache.getPathForFolder( pathname );
$ul.append( path.updateCrumbHtml() );
};
};
};
/*******************************
* top space, depending on nav height
*******************************/
@ -175,74 +149,13 @@ var H5ai = function ( options, langs, pathCache ) {
/*******************************
* extended view
*******************************/
this.initExtendedView = function () {
var $ul = $( "<ul/>" );
// headers
var $ths = $( "#table th" );
var $label = $ths.eq( 1 ).find( "a" );
var $date = $ths.eq( 2 ).find( "a" );
var $size = $ths.eq( 3 ).find( "a" );
var $li = $( "<li class='header' />" ).appendTo( $ul );
$( "<a class='icon'></a>" ).appendTo( $li );
$( "<a class='label' href='" + $label.attr( "href" ) + "'><span class='l10n-columnName'>" + $label.text() + "</span></a>" ).appendTo( $li );
$( "<a class='date' href='" + $date.attr( "href" ) + "'><span class='l10n-columnLastModified'>" + $date.text() + "</span></a>" ).appendTo( $li );
$( "<a class='size' href='" + $size.attr( "href" ) + "'><span class='l10n-columnSize'>" + $size.text() + "</span></a>" ).appendTo( $li );
// header sort icons
var order = document.location.search;
if ( order === "" ) {
order = this.config.defaultSortOrder;
};
var $icon;
if ( order.indexOf( "O=A" ) >= 0 ) {
$icon = $( "<img src='/h5ai/images/ascending.png' class='sort' alt='ascending' />" );
} else {
$icon = $( "<img src='/h5ai/images/descending.png' class='sort' alt='descending' />" );
};
if ( order.indexOf( "C=N" ) >= 0 ) {
$li.find( "a.label" ).append( $icon );
} else if ( order.indexOf( "C=M" ) >= 0 ) {
$li.find( "a.date" ).prepend( $icon );
} else if ( order.indexOf( "C=S" ) >= 0 ) {
$li.find( "a.size" ).prepend( $icon );
};
$.timer.log( "start entries" );
// entries
$( "#table td" ).closest( "tr" ).each( function () {
var path = pathCache.getPathForTableRow( document.location.pathname, this );
$ul.append( path.updateExtendedHtml() );
} );
$.timer.log( "end entries" );
$( "#table" ).remove();
$( "#extended" ).append( $ul );
$.log( document.location.pathname, "folders:", $( "#extended .folder" ).size() , "files:", $( "#extended .file" ).size() );
// empty
if ( $ul.children( ".entry:not(.parentfolder)" ).size() === 0 ) {
$( "#extended" ).append( $( "<div class='empty l10n-empty'>empty</div>" ) );
};
// in case of floats
$( "#extended" ).addClass( "clearfix" );
};
/*******************************
* init views
*******************************/
this.initViews = function () {
this.initExtendedView();
$( "#table" ).remove();
$( "#viewdetails" ).closest( "li" )
.click( $.proxy( function () {
@ -257,25 +170,61 @@ var H5ai = function ( options, langs, pathCache ) {
/*******************************
* customize
* init tree
*******************************/
this.customize = function () {
this.initTree = function () {
$.ajax( {
url: this.config.customHeader,
dataType: "html",
success: function ( data ) {
$( "#content > header" ).append( $( data ) ).show();
}
var $tree = $( "#tree" );
var $extended = $( "#extended" );
var shiftTree = function ( forceVisible, dontAnimate ) {
if ( $tree.outerWidth() < $extended.offset().left || forceVisible === true ) {
if ( dontAnimate === true ) {
$tree.stop().css( { left: 0 } );
} else {
$tree.stop().animate( { left: 0 } );
};
} else {
if ( dontAnimate === true ) {
$tree.stop().css( { left: 18 - $tree.outerWidth() } );
} else {
$tree.stop().animate( { left: 18 - $tree.outerWidth() } );
};
};
};
$tree.hover( function () { shiftTree( true ); }, function () { shiftTree(); } );
$( window ).resize( function() {
shiftTree();
} );
$.ajax( {
url: this.config.customFooter,
dataType: "html",
success: function ( data ) {
$( "#content > footer" ).prepend( $( data ) ).show();
}
shiftTree( false, true );
};
/*******************************
* link hover states
*******************************/
this.linkHoverStates = function () {
if ( !this.config.linkHoverStates ) {
return;
};
$( "a[href^='/']:not(.linkedHoverStates)" ).each( function () {
var $a = $( this ).addClass( "linkedHoverStates" );
var href = $a.attr( "href" );
$a.hover(
function () {
$( "a[href='" + href + "']" ).addClass( "hover" );
},
function () {
$( "a[href='" + href + "']" ).removeClass( "hover" );
}
);
} );
};
@ -285,22 +234,111 @@ var H5ai = function ( options, langs, pathCache ) {
* localization
*******************************/
this.localize = function ( data, lang, useBrowserLang ) {
this.initLangSelector = function ( langs ) {
var sortedLangsKeys = [];
for ( lang in langs ) {
sortedLangsKeys.push( lang );
};
sortedLangsKeys.sort();
var THIS = this;
var $ul = $( "<ul />" );
for ( idx in sortedLangsKeys ) {
( function ( lang ) {
$( "<li class='langOption' />" )
.addClass( lang )
.text( lang + " - " + langs[lang]["lang"] )
.appendTo( $ul )
.click( function () {
localStorage.setItem( THIS.config.store.lang, lang );
THIS.localize( langs, lang, false );
} );
} )( sortedLangsKeys[idx] );
};
$( "#langSelector .langOptions" )
.append( $ul );
$( "#langSelector" ).hover(
function () {
var $ele = $( ".langOptions" );
$ele.css( "top", "-" + $ele.outerHeight() + "px" ).stop( true, true ).fadeIn();
},
function () {
$( ".langOptions" ).stop( true, true ).fadeOut();
}
);
};
this.localize = function ( langs, lang, useBrowserLang ) {
if ( useBrowserLang === true ) {
var browserLang = navigator.language;
if ( data[ browserLang ] !== undefined ) {
if ( langs[ browserLang ] !== undefined ) {
lang = browserLang;
} else if ( browserLang.length > 2 && data[ browserLang.substr( 0, 2 ) ] !== undefined ) {
} else if ( browserLang.length > 2 && langs[ browserLang.substr( 0, 2 ) ] !== undefined ) {
lang = browserLang.substr( 0, 2 );
};
};
if ( lang !== "en" && data[ lang ] !== undefined ) {
var selected = data[ lang ];
for ( key in selected ) {
$( ".l10n-" + key ).text( selected[key] );
};
if ( langs[ lang ] === undefined ) {
lang = "en";
};
var storedLang = localStorage.getItem( this.config.store.lang );
if ( langs[ storedLang ] !== undefined ) {
lang = storedLang;
};
var selected = langs[ lang ];
for ( key in selected ) {
$( ".l10n-" + key ).text( selected[key] );
};
$( ".lang" ).text( lang );
$( ".langOption" ).removeClass( "current" );
$( ".langOption." + lang ).addClass( "current" );
};
/*******************************
* initiate tree indicators
*******************************/
this.initIndicators = function () {
var THIS = this;
$( "#tree .entry.folder:not(.initiatedIndicator)" ).each( function () {
var $entry = $( this ).addClass( "initiatedIndicator" );
var $indicator = $entry.find( "> .indicator" );
$indicator.click( function( event ) {
if ( $indicator.hasClass( "unknown" ) ) {
$.get( "/h5ai/php/treecontent.php", { "href": $entry.find( "> a" ).attr( "href" ) }, function ( html ) {
$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 );
$( "#tree" ).get( 0 ).updateScrollbar();
THIS.initIndicators();
};
} );
} else if ( $indicator.hasClass( "open" ) ) {
$indicator.removeClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$entry.find( "> .content" ).slideUp( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
} );
} else {
$indicator.addClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$entry.find( "> .content" ).slideDown( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
} );
};
} );
} );
};
};

View file

@ -0,0 +1,133 @@
( function ( $ ) {
var init = function ( htmlElement ) {
var $element = $( htmlElement );
if ( $element.css( "position" ) === undefined || $element.css( "position" ) === "static" ) {
$element.css( "position", "relative" );
};
var $scrollbar = $( "<div class='scrollbar' />" );
var $drag = $( "<div class='drag' />" ).appendTo( $scrollbar );
$element
.wrapInner( "<div class='wrapper'><div class='content' /></div>" )
.append( $scrollbar );
var $wrapper = $element.find( "> .wrapper" );
var $content = $wrapper.find( "> .content" );
var mouseOffsetY = 0;
var updateId = undefined;
var update = function ( repeat ) {
if ( updateId !== undefined && !repeat ) {
clearInterval( updateId );
updateId = undefined;
} else if ( updateId === undefined && repeat ) {
updateId = setInterval( function() { update( true ); }, 50 );
};
$wrapper.css( "height", $element.height() );
var visibleHeight = $element.height();
var contentHeight = $content.outerHeight();
var scrollTop = $wrapper.scrollTop();
var scrollTopFrac = scrollTop / contentHeight;
var visVertFrac = Math.min( visibleHeight / contentHeight, 1 );
if ( visVertFrac < 1 ) {
$scrollbar
.fadeIn( 50 )
.css( {
height: $element.innerHeight() + $scrollbar.height() - $scrollbar.outerHeight( true )
} );
$drag
.css( {
top: $scrollbar.height() * scrollTopFrac,
height: $scrollbar.height() * visVertFrac
} );
} else {
$scrollbar.fadeOut( 50 );
};
};
var scroll = function ( event ) {
var clickFrac = ( event.pageY - $scrollbar.offset().top - mouseOffsetY ) / $scrollbar.height();
$wrapper.scrollTop( $content.outerHeight() * clickFrac );
update();
};
$element
.mousewheel( function ( event, delta) {
$wrapper.scrollTop( $wrapper.scrollTop() - 50 * delta );
update();
event.stopPropagation();
event.preventDefault();
} )
.scroll( update );
$element.get( 0 ).updateScrollbar = update;
$wrapper
.css( {
"padding-right": $scrollbar.outerWidth( true ),
height: $element.height(),
overflow: "hidden"
} );
$scrollbar
.css( {
position: "absolute",
top: 0,
right: 0,
overflow: "hidden"
} )
.mousedown( function ( event ) {
mouseOffsetY = $drag.outerHeight() / 2;
scroll( event );
$scrollbar.addClass( "dragOn" );
$( window )
.bind( "mousemove", scroll )
.one( "mouseup", function ( event ) {
$scrollbar.removeClass( "dragOn" );
$( window ).unbind( "mousemove", scroll );
scroll( event );
event.stopPropagation();
} );
event.stopPropagation();
} )
.attr( "unselectable", "on" )
.css( "-moz-user-select", "none" )
.each( function () {
this.onselectstart = function () {
return false;
};
} );
$drag
.css( {
position: "absolute",
left: 0,
width: "100%"
} )
.mousedown( function ( event ) {
mouseOffsetY = event.pageY - $drag.offset().top;
scroll( event );
$scrollbar.addClass( "dragOn" );
$( window )
.bind( "mousemove", scroll )
.one( "mouseup", function ( event ) {
$scrollbar.removeClass( "dragOn" );
$( window ).unbind( "mousemove", scroll );
scroll( event );
event.stopPropagation();
} );
event.stopPropagation();
} );
update();
};
$.fn.scrollpanel = function () {
return this.each( function () {
init( this );
} );
};
} )( jQuery );

View file

@ -0,0 +1,24 @@
( function( $ ) {
// http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
// modified
$.log = function () {
$.log.history = $.log.history || [];
$.log.history.push( arguments );
if ( window.console ) {
window.console.log( Array.prototype.slice.call( arguments ) );
};
};
var Timer = function () {
this.start = new Date().getTime();;
this.last = this.start;
this.log = function ( label ) {
var now = new Date().getTime();
$.log( "timer", label, "+" + (now - this.last), "=" + (now - this.start) );
this.last = now;
};
};
$.timer = new Timer();
} )( jQuery );

View file

@ -170,6 +170,14 @@ var PathCache = function () {
var Path = function ( pathCache, folder, tableRow ) {
this.checkedDecodeUri = function ( uri ) {
try {
return decodeURI( uri );
} catch ( err ) {
};
return uri;
}
if ( ! pathEndsWithSlashRegEx.test( folder ) ) {
folder += "/";
};
@ -191,13 +199,13 @@ var Path = function ( pathCache, folder, tableRow ) {
this.parentFolder = splits[0];
this.href = splits[1];
this.label = decodeURI( splits[1] );
this.label = this.checkedDecodeUri( splits[1] );
this.icon16 = "/h5ai/icons/16x16/folder.png";
this.alt = "[DIR]";
this.date = "";
this.size = "";
if ( this.label === "/" ) {
this.label = decodeURI( document.domain ) + "/";
this.label = this.checkedDecodeUri( document.domain ) + "/";
};
};
@ -214,9 +222,9 @@ var Path = function ( pathCache, folder, tableRow ) {
if ( this.isParentFolder && h5ai.config.setParentFolderLabels ) {
if ( this.isDomain ) {
this.label = decodeURI( document.domain );
this.label = this.checkedDecodeUri( document.domain );
} else {
this.label = decodeURI( pathCache.splitPathname( pathCache.splitPathname( this.parentFolder )[0] )[1].slice( 0, -1 ) );
this.label = this.checkedDecodeUri( pathCache.splitPathname( pathCache.splitPathname( this.parentFolder )[0] )[1].slice( 0, -1 ) );
};
};
@ -237,37 +245,10 @@ var Path = function ( pathCache, folder, tableRow ) {
this.onClick = function ( context ) {
pathCache.storeCache();
h5ai.triggerPathClick( this, context );
};
this.onHoverIn = function () {
if ( h5ai.config.linkHoverStates ) {
for ( ref in this.html ) {
$ref = this.html[ref];
if ( $ref !== undefined ) {
$ref.find( "> a" ).addClass( "hover" );
};
};
};
};
this.onHoverOut = function () {
if ( h5ai.config.linkHoverStates ) {
for ( ref in this.html ) {
$ref = this.html[ref];
if ( $ref !== undefined ) {
$ref.find( "> a" ).removeClass( "hover" );
};
};
};
};
this.updateHtml = function () {
this.updateCrumbHtml();
@ -292,7 +273,6 @@ var Path = function ( pathCache, folder, tableRow ) {
var $a = $( "<a><img src='/h5ai/images/crumb.png' alt='>' />" + this.label + "</a>" );
$a.attr( "href", this.absHref );
$a.click( $.proxy( function() { this.onClick( "crumb" ); }, this ) );
$a.hover( $.proxy( function() { this.onHoverIn( "crumb" ); }, this ), $.proxy( function() { this.onHoverOut( "crumb" ); }, this ) );
$html.append( $a );
if ( this.isDomain ) {
@ -340,7 +320,6 @@ var Path = function ( pathCache, folder, tableRow ) {
var $a = $( "<a />" ).appendTo( $html );
$a.attr( "href", this.absHref );
$a.click( $.proxy( function() { this.onClick( "extended" ); }, this ) );
$a.hover( $.proxy( function() { this.onHoverIn( "extended" ); }, this ), $.proxy( function() { this.onHoverOut( "extended" ); }, this ) );
$( "<span class='icon small'><img src='" + this.icon16 + "' alt='" + this.alt + "' /></span>" ).appendTo( $a );
$( "<span class='icon big'><img src='" + this.icon48 + "' alt='" + this.alt + "' /></span>" ).appendTo( $a );
@ -391,7 +370,6 @@ var Path = function ( pathCache, folder, tableRow ) {
.append( $( "<span class='label'>" + this.label + "</span>" ) );
$a.attr( "href", this.absHref );
$a.click( $.proxy( function() { this.onClick( "tree" ); }, this ) );
$a.hover( $.proxy( function() { this.onHoverIn( "tree" ); }, this ), $.proxy( function() { this.onHoverOut( "tree" ); }, this ) );
if ( this.isFolder ) {
// indicator
@ -409,6 +387,7 @@ var Path = function ( pathCache, folder, tableRow ) {
this.content = content;
this.treeOpen = true;
pathCache.objectCache[this.absHref] = pathCache.pathToObject( this );
pathCache.storeCache();
$( "#tree" ).get( 0 ).updateScrollbar( true );
this.updateTreeHtml( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
@ -417,6 +396,7 @@ var Path = function ( pathCache, folder, tableRow ) {
} else if ( $indicator.hasClass( "open" ) ) {
this.treeOpen = false;
pathCache.objectCache[this.absHref] = pathCache.pathToObject( this );
pathCache.storeCache();
$indicator.removeClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$html.find( "> ul.content" ).slideUp( function() {
@ -425,6 +405,7 @@ var Path = function ( pathCache, folder, tableRow ) {
} else {
this.treeOpen = true;
pathCache.objectCache[this.absHref] = pathCache.pathToObject( this );
pathCache.storeCache();
$indicator.addClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$html.find( "> ul.content" ).slideDown( function() {
@ -432,6 +413,7 @@ var Path = function ( pathCache, folder, tableRow ) {
} );
};
}, this ) );
$html.addClass( "initiatedIndicator" );
$blank.replaceWith( $indicator );
};

View file

@ -1,8 +1,6 @@
var Tree = function ( pathCache, h5ai ) {
var THIS = this;
var contentTypeRegEx = /^text\/html;h5ai=/;
this.init = function () {
@ -21,6 +19,7 @@ var Tree = function ( pathCache, h5ai ) {
path.status = status;
};
path.updateHtml();
h5ai.linkHoverStates();
} );
};
};
@ -36,34 +35,16 @@ var Tree = function ( pathCache, h5ai ) {
this.populateTree = function () {
var $tree = $( "#tree" );
var $extended = $( "#extended" );
var shiftTree = function ( forceVisible, dontAnimate ) {
if ( $tree.outerWidth() < $extended.offset().left || forceVisible === true ) {
if ( dontAnimate === true ) {
$tree.stop().css( { left: 0 } );
} else {
$tree.stop().animate( { left: 0 } );
};
} else {
if ( dontAnimate === true ) {
$tree.stop().css( { left: 18 - $tree.outerWidth() } );
} else {
$tree.stop().animate( { left: 18 - $tree.outerWidth() } );
};
};
};
$tree.hover( function () { shiftTree( true ); }, function () { shiftTree(); } );
$( window ).resize( function() {
shiftTree();
} );
this.fetchTree( document.location.pathname, function( path ) {
$tree.append( path.updateTreeHtml() );
$tree.show();
scrollpanel( $tree );
shiftTree( false, true );
$( "#tree" )
.append( path.updateTreeHtml() )
.scrollpanel()
.show();
h5ai.linkHoverStates();
pathCache.storeCache();
setTimeout( function () {
$( "#tree" ).get( 0 ).updateScrollbar();
}, 1 );
} );
};
@ -99,6 +80,11 @@ var Tree = function ( pathCache, h5ai ) {
};
var THIS = this;
var contentTypeRegEx = /^text\/html;h5ai=/;
var pathnameStatusCache = {};
this.fetchStatusAndContent = function ( pathname, includeParent, callback ) {
this.fetchStatus( pathname, function ( status ) {
@ -136,8 +122,6 @@ var Tree = function ( pathCache, h5ai ) {
};
var pathnameStatusCache = {};
this.fetchStatus = function ( pathname, callback ) {
if ( h5ai.config.folderStatus[ pathname ] !== undefined ) {
@ -161,127 +145,4 @@ var Tree = function ( pathCache, h5ai ) {
}
} );
};
var scrollpanel = function ( htmlElement ) {
var $element = $( htmlElement );
if ( $element.css( "position" ) === undefined || $element.css( "position" ) === "static" ) {
$element.css( "position", "relative" );
};
var $scrollbar = $( "<div class='scrollbar' />" );
var $drag = $( "<div class='drag' />" ).appendTo( $scrollbar );
$element
.wrapInner( "<div class='wrapper'><div class='content' /></div>" )
.append( $scrollbar );
var $wrapper = $element.find( "> .wrapper" );
var $content = $wrapper.find( "> .content" );
var mouseOffsetY = 0;
var updateId = undefined;
var update = function ( repeat ) {
if ( updateId !== undefined && !repeat ) {
clearInterval( updateId );
updateId = undefined;
} else if ( updateId === undefined && repeat ) {
updateId = setInterval( function() { update( true ); }, 50 );
};
$wrapper.css( "height", $element.height() );
var visibleHeight = $element.height();
var contentHeight = $content.outerHeight();
var scrollTop = $wrapper.scrollTop();
var scrollTopFrac = scrollTop / contentHeight;
var visVertFrac = Math.min( visibleHeight / contentHeight, 1 );
if ( visVertFrac < 1 ) {
$scrollbar
.fadeIn( 50 )
.css( {
height: $element.innerHeight() + $scrollbar.height() - $scrollbar.outerHeight( true )
} );
$drag
.css( {
top: $scrollbar.height() * scrollTopFrac,
height: $scrollbar.height() * visVertFrac
} );
} else {
$scrollbar.fadeOut( 50 );
};
};
var scroll = function ( event ) {
var clickFrac = ( event.pageY - $scrollbar.offset().top - mouseOffsetY ) / $scrollbar.height();
$wrapper.scrollTop( $content.outerHeight() * clickFrac );
update();
};
$element
.mousewheel( function ( event, delta) {
$wrapper.scrollTop( $wrapper.scrollTop() - 50 * delta );
update();
event.stopPropagation();
event.preventDefault();
} )
.scroll( update );
$element.get( 0 ).updateScrollbar = update;
$wrapper
.css( {
"padding-right": $scrollbar.outerWidth( true ),
height: $element.height(),
overflow: "hidden"
} );
$scrollbar
.css( {
position: "absolute",
top: 0,
right: 0,
overflow: "hidden"
} )
.mousedown( function ( event ) {
mouseOffsetY = $drag.outerHeight() / 2;
scroll( event );
$scrollbar.addClass( "dragOn" );
$( window )
.bind( "mousemove", scroll )
.one( "mouseup", function ( event ) {
$scrollbar.removeClass( "dragOn" );
$( window ).unbind( "mousemove", scroll );
scroll( event );
event.stopPropagation();
} );
event.stopPropagation();
} )
.attr( "unselectable", "on" )
.css( "-moz-user-select", "none" )
.each( function () {
this.onselectstart = function () {
return false;
};
} );
$drag
.css( {
position: "absolute",
left: 0,
width: "100%"
} )
.mousedown( function ( event ) {
mouseOffsetY = event.pageY - $drag.offset().top;
scroll( event );
$scrollbar.addClass( "dragOn" );
$( window )
.bind( "mousemove", scroll )
.one( "mouseup", function ( event ) {
$scrollbar.removeClass( "dragOn" );
$( window ).unbind( "mousemove", scroll );
scroll( event );
event.stopPropagation();
} );
event.stopPropagation();
} );
update();
};
};

44
src/h5ai/js/main-js.js Normal file
View file

@ -0,0 +1,44 @@
( function( $ ) {
// @include "inc/jquery.json.min.js"
// @include "inc/jquery.mousewheel.min.js"
// @include "inc/jquery.scrollpanel.js"
// @include "inc/jquery.utils.js"
// @include "inc/path.js"
// @include "inc/extended.js"
// @include "inc/h5ai.js"
// @include "inc/tree.js"
/*******************************
* create
*******************************/
$.timer.log( "start pathcache" );
var pathCache = new PathCache();
$.timer.log( "end pathcache" );
var extended = new Extended( pathCache );
var h5ai = new H5ai( h5aiOptions, h5aiLangs );
var tree = new Tree( pathCache, h5ai );
/*******************************
* register public api
*******************************/
$.h5ai = {
click: $.proxy( h5ai.pathClick, h5ai )
};
/*******************************
* init after dom load
*******************************/
$( function() {
extended.init();
tree.init();
h5ai.init();
} );
} )( jQuery );

36
src/h5ai/js/main-php.js Normal file
View file

@ -0,0 +1,36 @@
( function( $ ) {
// @include "inc/jquery.json.min.js"
// @include "inc/jquery.mousewheel.min.js"
// @include "inc/jquery.scrollpanel.js"
// @include "inc/jquery.utils.js"
// @include "inc/h5ai.js"
/*******************************
* create
*******************************/
var h5ai = new H5ai( h5aiOptions, h5aiLangs );
/*******************************
* register public api
*******************************/
$.h5ai = {
click: $.proxy( h5ai.pathClick, h5ai )
};
/*******************************
* init after dom load
*******************************/
$( function() {
h5ai.init();
$( "#tree" ).scrollpanel();
} );
} )( jQuery );

View file

@ -1,66 +0,0 @@
( function( $ ) {
// @include "inc/jquery.json.min.js"
// @include "inc/jquery.mousewheel.min.js"
// @include "inc/path.js"
// @include "inc/h5ai.js"
// @include "inc/tree.js"
// http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
$.log = function () {
$.log.history = $.log.history || [];
$.log.history.push( arguments );
if ( window.console ) {
window.console.log( Array.prototype.slice.call( arguments ) );
};
};
var Timer = function () {
this.start = new Date().getTime();;
this.last = this.start;
this.log = function ( label ) {
var now = new Date().getTime();
$.log( "timer", label, "+" + (now - this.last), "=" + (now - this.start) );
this.last = now;
};
};
$.timer = new Timer();
/*******************************
* create
*******************************/
$.timer.log( "start pathcache" );
var pathCache = new PathCache();
$.timer.log( "end pathcache" );
var h5ai = new H5ai( h5aiOptions, h5aiLangs, pathCache );
var tree = new Tree( pathCache, h5ai );
/*******************************
* register public api
*******************************/
$.h5ai = {
click: $.proxy( h5ai.pathClick, h5ai )
};
/*******************************
* init after dom load
*******************************/
$( function() {
h5ai.init();
tree.init();
// just for testing, resets the local cache /////////
$( ".l10n-footerUsing" ).click( function () {
pathCache.cache = {};
pathCache.objectCache = {};
pathCache.storeCache();
} );
/////////////////////////////////////////////////////
} );
} )( jQuery );

View file

@ -13,7 +13,7 @@ h5aiOptions = {
* The user selected view mode is also stored local in modern browsers
* so that it will be persistent.
*/
viewmodes: [ "details", "icons" ],
"viewmodes": [ "details", "icons" ],
/*
* Show a folder tree, boolean.
@ -22,7 +22,7 @@ h5aiOptions = {
* folderStatus below to avoid such requests.
* It might also affect performance significantly.
*/
showTree: true,
"showTree": true,
/*
* Associative array of folders and their HTTP status codes to
@ -34,7 +34,7 @@ h5aiOptions = {
* as a non auto indexed folder, that means a folder containing an
* appropriate default index file.
*/
folderStatus: {
"folderStatus": {
/*
* for example:
* "/some/folder/": 200
@ -44,132 +44,189 @@ h5aiOptions = {
/*
* Localization, for example "en", "de" etc. - see h5aiLangs below for
* possible values. Adjust it to your needs. If lang is not found in
* h5aiLangs the displayed labels stay unchanged.
* h5aiLangs it defaults to "en".
*/
lang: undefined,
"lang": null,
/*
* Try to use browser language, falls back to previous specified lang.
*/
useBrowserLang: true,
"useBrowserLang": true,
/*
* Set parent folder labels to real folder names.
*/
setParentFolderLabels: true,
"setParentFolderLabels": true,
/*
* Link the hover effects between crumb, extended view and tree.
*/
linkHoverStates: true
"linkHoverStates": true,
/*
* Only used in PHP implementation.
* Date format in PHP syntax, for example: "Y-m-d H:i:s"
* http://www.php.net/manual/en/function.date.php
*/
"dateFormat": "Y-m-d H:i",
/*
* Only used in PHP implementation.
* Files/folders that should never be listed. Specified
* by the complete filename or by a regular expression.
* http://www.php.net/manual/en/function.preg-match.php
*/
"ignore": [ "h5ai", "h5ai.header.html", "h5ai.footer.html" ],
"ignoreRE": [ "/^\\./" ]
};
/*
* Available translations.
* "en" is just an example - see it as a reference. Those values
* are "hardcoded" and will be displayed if all labels stay unchanged.
*/
*/
h5aiLangs = {
"en": {
viewDetails: "details",
viewIcons: "icons",
columnName: "Name",
columnLastModified: "Last modified",
columnSize: "Size",
footerUsing: "using",
parentDirectory: "Parent Directory",
empty: "empty"
"lang": "english",
"details": "details",
"icons": "icons",
"name": "Name",
"lastModified": "Last modified",
"size": "Size",
"parentDirectory": "Parent Directory",
"empty": "empty",
"folders": "folders",
"files": "files"
},
"de": {
viewDetails: "Details",
viewIcons: "Icons",
columnName: "Name",
columnLastModified: "Geändert",
columnSize: "Größe",
footerUsing: "nutzt",
parentDirectory: "Übergeordnetes Verzeichnis",
empty: "leer"
"lang": "deutsch",
"details": "Details",
"icons": "Icons",
"name": "Name",
"lastModified": "Geändert",
"size": "Größe",
"parentDirectory": "Übergeordnetes Verzeichnis",
"empty": "leer",
"folders": "Ordner",
"files": "Dateien"
},
"fr": {
viewDetails: "détails",
viewIcons: "icônes",
columnName: "Nom",
columnLastModified: "Dernière modification",
columnSize: "Taille",
footerUsing: "utilise",
parentDirectory: "Dossier parent",
empty: "vide"
"lang": "française",
"details": "détails",
"icons": "icônes",
"name": "Nom",
"lastModified": "Dernière modification",
"size": "Taille",
"parentDirectory": "Dossier parent",
"empty": "vide",
"folders": "[?folders?]",
"files": "[?files?]"
},
"nl": {
viewDetails: "details",
viewIcons: "iconen",
columnName: "Naam",
columnLastModified: "Laatste wijziging",
columnSize: "Grootte",
footerUsing: "gebruikt",
parentDirectory: "Bovenliggende map",
empty: "lege"
"lang": "nederlands",
"details": "details",
"icons": "iconen",
"name": "Naam",
"lastModified": "Laatste wijziging",
"size": "Grootte",
"parentDirectory": "Bovenliggende map",
"empty": "lege",
"folders": "[?folders?]",
"files": "[?files?]"
},
"sv": {
viewDetails: "detaljerad",
viewIcons: "ikoner",
columnName: "Filnamn",
columnLastModified: "Senast ändrad",
columnSize: "Filstorlek",
footerUsing: "använder",
parentDirectory: "Till överordnad mapp",
empty: "tom"
"lang": "svenska",
"details": "detaljerad",
"icons": "ikoner",
"name": "Filnamn",
"lastModified": "Senast ändrad",
"size": "Filstorlek",
"parentDirectory": "Till överordnad mapp",
"empty": "tom",
"folders": "[?folders?]",
"files": "[?files?]"
},
"cs": {
viewDetails: "podrobnosti",
viewIcons: "ikony",
columnName: "Název",
columnLastModified: "Upraveno",
columnSize: "Velikost",
footerUsing: "používá",
parentDirectory: "Nadřazený adresář",
empty: "prázdný"
"lang": "[?lang?]",
"details": "podrobnosti",
"icons": "ikony",
"name": "Název",
"lastModified": "Upraveno",
"size": "Velikost",
"parentDirectory": "Nadřazený adresář",
"empty": "prázdný",
"folders": "[?folders?]",
"files": "[?files?]"
},
"sk": {
viewDetails: "podrobnosti",
viewIcons: "ikony",
columnName: "Názov",
columnLastModified: "Upravené",
columnSize: "Velkosť",
footerUsing: "používá",
parentDirectory: "Nadriadený priečinok",
empty: "prázdny"
"lang": "[?lang?]",
"details": "podrobnosti",
"icons": "ikony",
"name": "Názov",
"lastModified": "Upravené",
"size": "Velkosť",
"parentDirectory": "Nadriadený priečinok",
"empty": "prázdny",
"folders": "[?folders?]",
"files": "[?files?]"
},
"es": {
viewDetails: "Detalles",
viewIcons: "Íconos",
columnName: "Nombre",
columnLastModified: "Última modificación",
columnSize: "Tamaño",
footerUsing: "usando",
parentDirectory: "Directorio superior",
empty: "vacío"
"lang": "español",
"details": "Detalles",
"icons": "Íconos",
"name": "Nombre",
"lastModified": "Última modificación",
"size": "Tamaño",
"parentDirectory": "Directorio superior",
"empty": "vacío",
"folders": "[?folders?]",
"files": "[?files?]"
},
"tr": {
viewDetails: "detaylar",
viewIcons: "ikonlar",
columnName: "İsim",
columnLastModified: "Son Düzenleme",
columnSize: "Boyut",
footerUsing: "kullanıyor",
parentDirectory: "Üst Dizin",
empty: "boş"
}
"lang": "türkçe",
"details": "detaylar",
"icons": "ikonlar",
"name": "İsim",
"lastModified": "Son Düzenleme",
"size": "Boyut",
"parentDirectory": "Üst Dizin",
"empty": "boş",
"folders": "[?folders?]",
"files": "[?files?]"
},
"pt": {
"lang": "português",
"details": "detalhes",
"icons": "ícones",
"name": "Nome",
"lastModified": "Última modificação",
"size": "Tamanho",
"parentDirectory": "Diretório superior",
"empty": "vazio",
"folders": "[?folders?]",
"files": "[?files?]"
},
"bg": {
"lang": "[?lang?]",
"details": "детайли",
"icons": "икони",
"name": "Име",
"lastModified": "Последна промяна",
"size": "Размер",
"parentDirectory": "Предходна директория",
"empty": "празно",
"folders": "[?folders?]",
"files": "[?files?]"
}
};

93
src/h5ai/php/cache.php Normal file
View file

@ -0,0 +1,93 @@
<?php
##############################################
# taken from here:
# http://www.jongales.com/blog/2009/02/18/simple-file-based-php-cache-class/
# with minor modifications
##############################################
class Cache {
private $dir;
function __construct( $dir ) {
$this->dir = $dir;
}
private function _name( $key ) {
return $this->dir . "/" . sha1( $key );
}
public function get( $key, $expiration = 3600 ) {
if ( !is_dir( $this->dir ) || !is_writable( $this->dir ) ) {
return false;
}
$cache_path = $this->_name( $key );
if ( !@file_exists( $cache_path ) ) {
return false;
}
if ( filemtime( $cache_path ) < ( time() - $expiration ) ) {
$this->clear( $key );
return false;
}
if ( !$fp = @fopen( $cache_path, "rb" ) ) {
return false;
}
flock( $fp, LOCK_SH );
$cache = "";
if ( filesize( $cache_path ) > 0 ) {
$cache = unserialize( fread( $fp, filesize( $cache_path ) ) );
} else {
$cache = null;
}
flock( $fp, LOCK_UN );
fclose( $fp );
return $cache;
}
public function set( $key, $data ) {
if ( !is_dir( $this->dir ) || !is_writable( $this->dir ) ) {
return false;
}
$cache_path = $this->_name( $key );
if ( ! $fp = fopen( $cache_path, "wb" ) ) {
return false;
}
if ( flock( $fp, LOCK_EX ) ) {
fwrite( $fp, serialize( $data ) );
flock( $fp, LOCK_UN );
} else {
return false;
}
fclose( $fp );
@chmod( $cache_path, 0777 );
return true;
}
public function clear( $key ) {
$cache_path = $this->_name( $key );
if ( file_exists( $cache_path ) ) {
unlink( $cache_path );
return true;
}
return false;
}
}
?>

52
src/h5ai/php/crumb.php Normal file
View file

@ -0,0 +1,52 @@
<?php
class Crumb {
private $h5ai, $parts;
public function __construct( $h5ai ) {
$this->h5ai = $h5ai;
$this->parts = array();
$href = $h5ai->getAbsHref();
while ( $href !== "/" && $href !== "//" ) {
$this->parts[] = $href;
$href = dirname( $href ) . "/";
}
$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 = "/h5ai/images/" . ( $idx === 1 ? "home.png" : "crumb.png" );
$label = $this->h5ai->getLabel( $href );
$hint = "";
$code = $this->h5ai->getHttpCode( $href );
$classes .= " checkedHttpCode";
if ( $code !== "h5ai" ) {
if ( $code === 200 ) {
$hint = "<img class='hint' src='/h5ai/images/page.png' 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='>' />" . $label . $hint . "\n";
$html .= "\t</a>\n";
$html .= "</li>\n";
}
return $html;
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
class Customize {
private $h5ai;
public function __construct( $h5ai ) {
$this->h5ai = $h5ai;
}
public function getHeader() {
return $this->getContent( $this->h5ai->getAbsPath() . "/" . "h5ai.header.html", "header" );
}
public function getFooter() {
return $this->getContent( $this->h5ai->getAbsPath() . "/" . "h5ai.footer.html", "footer" );
}
private function getContent( $file, $tag ) {
return file_exists( $file ) ? ( "<" . $tag . ">" . file_get_contents( $file ) . "</" . $tag . ">" ) : "";
}
}
?>

205
src/h5ai/php/extended.php Normal file
View file

@ -0,0 +1,205 @@
<?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;
}
function compare( $that, $sortOrder ) {
if ( $this->isFolder && !$that->isFolder ) {
return -1;
}
if ( !$this->isFolder && $that->isFolder ) {
return 1;
}
$res = 0;
if ( $sortOrder[ "column" ] === "name" ) {
$res = strcasecmp( $this->absPath, $that->absPath );
} else if ( $sortOrder[ "column" ] === "date" ) {
$res = $this->date - $that->date;
} else if ( $sortOrder[ "column" ] === "size" ) {
$res = $this->size - $that->size;
}
if ( ! $sortOrder[ "ascending" ] ) {
$res = -$res;
}
return $res;
}
public function toHtml( $dateFormat ) {
$classes = "entry " . $this->type;
$img = $this->type;
$hint = "";
$dateLabel = date( $dateFormat, $this->date );
if ( $this->isFolder && $this->type !== "folder-parent" ) {
$code = $this->h5ai->getHttpCode( $this->absHref );
$classes .= " checkedHttpCode";
if ( $code !== "h5ai" ) {
if ( $code === 200 ) {
$img = "folder-page";
} else {
$classes .= " error";
$hint = "<span class='hint'> " . $code . " </span>";
}
}
}
$html = "\t<li class='" . $classes . "'>\n";
$html .= "\t\t<a href='" . $this->absHref . "'>\n";
$html .= "\t\t\t<span class='icon small'><img src='/h5ai/icons/16x16/" . $img . ".png' alt='" . $img . "' /></span>\n";
$html .= "\t\t\t<span class='icon big'><img src='/h5ai/icons/48x48/" . $img . ".png' alt='" . $img . "' /></span>\n";
$html .= "\t\t\t<span class='label'>" . $this->label . $hint . "</span>\n";
$html .= "\t\t\t<span class='date'>" . $dateLabel . "</span>\n";
$html .= "\t\t\t<span class='size'>" . $this->formatSize( $this->size ) . "</span>\n";
$html .= "\t\t</a>\n";
$html .= "\t</li>\n";
return $html;
}
private function formatSize( $size ) {
$units = array( 'B', 'KB', 'MB', 'GB', 'TB' );
for ( $i = 0; $size >= 1024 && $i < 4; $i++ ) {
$size /= 1024;
}
return round( $size, 0 ) . " " . $units[$i];
}
}
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 = dirname( $this->h5ai->getAbsPath() );
$parentHref = dirname( $this->h5ai->getAbsHref() );
$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 );
}
$this->sort();
}
public function cmpEntries( $p1, $p2 ) {
return $p1->compare( $p2, $this->h5ai->getSortOrder() );
}
public function sort() {
uasort( $this->content, array( $this, "cmpEntries" ) );
}
public function getFolderCount() {
$count = 0;
foreach( $this->content as $entry ) {
if ( $entry->isFolder() ) {
$count++;
}
}
return $count;
}
public function getFileCount() {
$count = 0;
foreach( $this->content as $entry ) {
if ( !$entry->isFolder() ) {
$count++;
}
}
return $count;
}
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( $this->h5ai->getDateFormat() );
}
foreach( $this->content as $entry ) {
$html .= $entry->toHtml( $this->h5ai->getDateFormat() );
}
$html .= "</ul>\n";
if ( count( $this->content ) === 0 ) {
$html .= "<div class='empty l10n-empty'>empty</div>";
}
$html .="</section>";
return $html;
}
public function generateHeaders() {
$asc = "<img src='/h5ai/images/ascending.png' class='sort' alt='ascending' />";
$desc = "<img src='/h5ai/images/descending.png' class='sort' alt='descending' />";
$so = $this->h5ai->getSortOrder();
$order = $so["ascending"] ? $asc : $desc;
$nameHref = "?col=name" . ( $so["column"] === "name" && $so["ascending"] ? "&asc=false" : "&asc=true" );
$dateHref = "?col=date" . ( $so["column"] === "date" && $so["ascending"] ? "&asc=false" : "&asc=true" );
$sizeHref = "?col=size" . ( $so["column"] === "size" && $so["ascending"] ? "&asc=false" : "&asc=true" );
$nameSort = $so["column"] === "name" ? $order : "";
$dateSort = $so["column"] === "date" ? $order : "";
$sizeSort = $so["column"] === "size" ? $order : "";
$html = "\t<li class='header'>\n";
$html .= "\t\t<a class='icon'></a>\n";
$html .= "\t\t<a class='label' href='$nameHref'><span class='l10n-name'>Name</span>$nameSort</a>\n";
$html .= "\t\t<a class='date' href='$dateHref'>$dateSort<span class='l10n-lastModified'>Last modified</span></a>\n";
$html .= "\t\t<a class='size' href='$sizeHref'>$sizeSort<span class='l10n-size'>Size</span></a>\n";
$html .= "\t</li>\n";
return $html;
}
}
?>

263
src/h5ai/php/h5ai.php Normal file
View file

@ -0,0 +1,263 @@
<?php
require_once "cache.php";
class H5ai {
private static $SORT_ORDER = array( "column" => "name", "ascending" => true );
private static $VIEWMODES = array( "details", "icons" );
private $docRoot, $domain, $options, $types, $cache, $absHref, $absPath, $ignore, $ignoreRE, $sortOrder, $dateFormat, $view;
public function __construct() {
$this->docRoot = getenv( "DOCUMENT_ROOT" );
$this->domain = getenv( "HTTP_HOST" );
$this->options = $this->loadOptions( $this->docRoot . "/h5ai/options.js" );
$this->types = $this->loadTypes( $this->docRoot . "/h5ai/types.txt" );
$this->cache = new Cache( $this->docRoot . "/h5ai/cache" );
$this->absHref = $this->normalizePath( preg_replace( '/\\?.*/', '', getenv( "REQUEST_URI" ) ), true );
$this->absPath = $this->normalizePath( $this->docRoot . rawurldecode( $this->absHref ), false );
$this->ignore = $this->options["options"]["ignore"];
$this->ignoreRE = $this->options["options"]["ignoreRE"];
$this->sortOrder = array(
"column" => array_key_exists( "col", $_REQUEST ) ? $_REQUEST["col"] : H5ai::$SORT_ORDER["column"],
"ascending" => array_key_exists( "asc", $_REQUEST ) ? $_REQUEST["asc"] !== "false" : H5ai::$SORT_ORDER["ascending"]
);
$this->dateFormat = $this->options["options"]["dateFormat"];
$this->view = array_key_exists( "view", $_REQUEST ) ? $_REQUEST["view"] : $this->options["options"]["viewmodes"][0];
if ( !in_array( $this->view, H5ai::$VIEWMODES ) ) {
$this->view = H5ai::$VIEWMODES[0];
}
}
private function loadOptions( $file ) {
$str = file_exists( $file ) ? file_get_contents( $file ) : "";
$str = preg_replace( "/\/\*.*?\*\//s", "", $str );
$optstr = preg_replace( "/^.*h5aiOptions\s*=\s*/s", "", $str );
$optstr = preg_replace( "/;.*/s", "", $optstr );
$options = json_decode( $optstr, true );
$langstr = preg_replace( "/^.*h5aiLangs\s*=\s*/s", "", $str );
$langstr = preg_replace( "/;.*/s", "", $langstr );
$langs = json_decode( $langstr, true );
return array( "options" => $options, "langs" => $langs );
}
private function loadTypes( $file ) {
$lines = file( $file );
$types = array();
foreach( $lines as $line ) {
if ( substr( $line, 0, 1 ) === '#' ) {
continue;
}
$types[] = preg_split( "/\s+/", $line );
}
return $types;
}
public function getDocRoot() {
return $this->docRoot;
}
public function getDomain() {
return $this->domain;
}
public function getView() {
return $this->view;
}
public function getOptions() {
return $this->options["options"] ;
}
public function getLangs() {
return $this->options["langs"];
}
public function getAbsHref( $absPath = null, $endWithSlash = true ) {
if ( $absPath === null ) {
return $this->absHref;
}
return $this->normalizePath( rawurlencode( preg_replace( "!^" . $this->docRoot . "!", "", $absPath ) ), $endWithSlash );
}
public function getAbsPath( $absHref = null ) {
if ( $absHref === null ) {
return $this->absPath;
}
return $this->normalizePath( $this->docRoot . rawurldecode( $absHref ), false );
}
public function getSortOrder() {
return $this->sortOrder;
}
public function getDateFormat() {
return $this->dateFormat;
}
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 ) {
foreach( array_slice( $type, 1 ) as $pattern ) {
if ( $this->endsWith( $absPath, $pattern ) ) {
return $type[0];
}
}
}
return "unknown";
}
public function ignoreThisFile( $file ) {
# always ignore
if ( $file === "." || $file === ".." || $this->startsWith( $file, '.ht' ) ) {
return true;
}
if ( in_array( $file, $this->ignore ) ) {
return true;
}
foreach ( $this->ignoreRE as $re ) {
if ( preg_match( $re, $file ) ) {
return true;
}
}
return false;
}
public function readDir( $path ) {
$content = array();
if ( is_dir( $path ) ) {
if ( $dir = opendir( $path ) ) {
while ( ( $file = readdir( $dir ) ) !== false ) {
if ( ! $this->ignoreThisFile( $file ) ) {
$content[] = $file;
}
}
closedir( $dir );
}
}
return $content;
}
public function getLabel( $absHref ) {
return $absHref === "/" ? $this->domain : rawurldecode( basename( $absHref ) );
}
public function normalizePath( $path, $endWithSlash ) {
return ( $path === "/" ) ? "/" : ( preg_replace( '#/$#', '', $path ) . ( $endWithSlash ? "/" : "" ) );
}
public function startsWith( $sequence, $start ) {
return substr( $sequence, 0, strlen( $start ) ) === $start;
}
public function endsWith( $sequence, $end ) {
return substr( $sequence, -strlen( $end ) ) === $end;
}
public function getHttpCode( $absHref ) {
return $this->cachedHttpCode( $absHref );
#return $this->fetchHttpCode( $absHref );
#return $this->guessHttpCode( $absHref );
}
public function cachedHttpCode( $absHref ) {
$cached = $this->cache->get( $absHref );
if ( $cached === false ) {
$folderStatus = $this->options["options"]["folderStatus"];
if ( array_key_exists( $absHref, $folderStatus ) ) {
$code = $folderStatus[$absHref];
} else {
$code = $this->fetchHttpCode( $absHref );
}
$cached = array( "href" => $absHref, "code" => $code );
$this->cache->set( $absHref, $cached );
}
return $cached["code"];
}
public function fetchHttpCode( $absHref ) {
$contentType = "Content-Type:";
$h5aiContentType = "Content-Type: text/html;h5ai=";
$host = getenv( "HTTP_HOST" );
$port = getenv( "SERVER_PORT" );
$msg = "HEAD $absHref HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
$errno = "";
$errstr = "";
$socket = fsockopen( $host, $port, $errno, $errstr, 30 );
if( $socket === 0 ) {
return null;
}
fwrite( $socket, $msg );
$content = fgets( $socket );
$code = intval( trim( substr( $content, 9, 4 ) ) );
if ( $code === 200 ) {
while ( ! $this->startsWith( $content, $contentType ) ) {
$content = fgets( $socket );
}
if ( $this->startsWith( $content, $h5aiContentType ) ) {
$code = "h5ai";
}
}
fclose( $socket );
return $code;
}
public function guessHttpCode( $absHref ) {
$indexFiles = array( "index.html", "index.cgi", "index.pl", "index.php", "index.xhtml", "index.htm" );
$absPath = $this->getAbsPath( $absHref );
$files = $this->readDir( $absPath );
foreach ( $files as $file ) {
if ( in_array( $file, $indexFiles ) ) {
return 200;
}
}
return "h5ai";
}
}
?>

23
src/h5ai/php/httpcode.php Normal file
View file

@ -0,0 +1,23 @@
<?php
require_once "h5ai.php";
function getHttpCodes( $h5ai, $hrefs ) {
$codes = array();
foreach ( $hrefs as $href ) {
$href = trim( $href );
if ( strlen( $href ) > 0 ) {
$codes[$href] = $h5ai->getHttpCode( $href );
}
}
return $codes;
}
$h5ai = new H5ai();
$hrefs = preg_split( "/;/", array_key_exists( "hrefs", $_REQUEST ) ? $_REQUEST[ "hrefs" ] : "" );
$codes = getHttpCodes( $h5ai, $hrefs );
echo count( $codes ) === 0 ? "{}" : json_encode( $codes );
?>

15
src/h5ai/php/main.php Normal file
View file

@ -0,0 +1,15 @@
<?php
require_once "h5ai.php";
require_once "crumb.php";
require_once "customize.php";
require_once "extended.php";
require_once "tree.php";
$h5ai = new H5ai();
$crumb = new Crumb( $h5ai );
$customize = new Customize( $h5ai );
$extended = new Extended( $h5ai );
$tree = new Tree( $h5ai );
?>

147
src/h5ai/php/tree.php Normal file
View file

@ -0,0 +1,147 @@
<?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" : "" );
$img = $this->type;
if ( $this->absHref === "/" ) {
$img = "folder-home";
}
$hint = "";
$code = "h5ai";
if ( $this->isFolder ) {
$code = $this->h5ai->getHttpCode( $this->absHref );
$classes .= " checkedHttpCode";
if ( $code !== "h5ai" ) {
if ( $code === 200 ) {
$img = "folder-page";
$hint = "<span class='hint'><img src='/h5ai/images/page.png' 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='/h5ai/images/tree.png' alt='>' /></span>\n";
}
$html .= "<a href='" . $this->absHref . "'>\n";
$html .= "<span class='icon'><img src='/h5ai/icons/16x16/" . $img . ".png' alt='" . $img . "' /></span>\n";
$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, dirname( $this->absPath ), dirname( $this->absHref ) );
$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

@ -0,0 +1,20 @@
<?php
if ( ! array_key_exists( "href", $_REQUEST ) ) {
exit;
}
require_once "h5ai.php";
require_once "tree.php";
$h5ai = new H5ai();
$absHref = trim( $_REQUEST[ "href" ] );
$absPath = $h5ai->getAbsPath( $absHref );
$tree = new TreeEntry( $h5ai, $absPath, $absHref );
$tree->loadContent();
echo $tree->contentToHtml();
?>

63
src/h5ai/types.txt Normal file
View file

@ -0,0 +1,63 @@
archive .tar.gz .tgz .tar.bz2
audio .mp3 .wav .ogg
authors AUTHORS authors
bin .so .o .class
blank
bmp .bmp
c .c
calc
cd .iso .cue
copying COPYING copying LICENSE license
cpp .cpp
css .css .less
deb .deb
default
doc .doc
draw
eps
exe .exe
folder
folder-home
folder-open
folder-page
folder-parent
gif .gif
gzip .gz
h .h
hpp .hpp
html .html .htm .shtml
ico .ico
image .xpm
install INSTALL install
java .java
jpg .jpg .jpeg
js .js .json
log .log CHANGELOG changelog LOG log
makefile .pom pom.xml build.xml
package
pdf .pdf
php .php
playlist .m3u
png .png
pres
psd
py .py
rar .rar
rb .rb
readme README readme
rpm .rpm
rss .rss
rtf .rtf
script .conf .ini .sh .shar .csh .ksh .tcl
source
sql
tar .tar
tex .tex
text .txt .text .md .markdown
tiff .tiff
unknown
vcal .vcal
video
xml .xml
zip .zip .Z .z .jar .war .bz2

View file

@ -1,5 +1,5 @@
################################
# %BUILD_NAME% %BUILD_VERSION%
# %BUILD_NAME% %BUILD_VERSION% (js)
# customized .htaccess
################################
@ -8,23 +8,6 @@
# Options +FollowSymLinks
<IfModule headers_module>
################################
# cache images for 52 weeks
################################
<FilesMatch "\.png$">
Header set Cache-Control "max-age=31449600, public"
</FilesMatch>
</IfModule>
################################
# style auto index
################################
################################
# IMPORTANT FOR XAMPP
# if you're running XAMPP you might need to replace the
@ -33,13 +16,6 @@
################################
<IfModule autoindex_module>
################################
# uncomment the following line to force directory listing
# even for directories with valid index files
################################
# DirectoryIndex IGNORE-DEFAULT-INDEX-FILES
################################
# h5ai header and footer
@ -81,7 +57,7 @@
# icon mapping
################################
AddIcon /h5ai/icons/16x16/parent.png ..
AddIcon /h5ai/icons/16x16/folder-parent.png ..
AddIcon /h5ai/icons/16x16/folder.png ^^DIRECTORY^^
AddIcon /h5ai/icons/16x16/blank.png ^^BLANKICON^^
@ -144,3 +120,4 @@
</IfModule>

29
src/php.htaccess Normal file
View file

@ -0,0 +1,29 @@
################################
# %BUILD_NAME% %BUILD_VERSION% (php)
# customized .htaccess
################################
# Options +Indexes
# Options +FollowSymLinks
################################
# IMPORTANT FOR XAMPP
# if you're running XAMPP you might need to replace the
# following line with
# <IfModule autoindex_color_module>
################################
<IfModule autoindex_module>
HeaderName /h5ai/header.php
ReadmeName /h5ai/footer.php
IndexIgnore *
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions Charset=UTF-8
IndexOptions SuppressHTMLPreamble
</IfModule>