1
0
mirror of https://github.com/lrsjng/h5ai.git synced 2025-08-28 16:20:02 +02:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Lars Jung
a8f62f187c Added it translation. Switched to wepp. 2011-09-18 19:49:26 +02:00
Lars Jung
8e21a3c038 Fixed security issues. 2011-09-06 20:57:49 +02:00
Lars Jung
df30c67ade Added selection and zipped download. 2011-09-04 21:18:55 +02:00
Lars Jung
2d3b0eed4f Added selection and zipped download. 2011-09-04 21:18:19 +02:00
Lars Jung
a371ee2afd Minor additions. 2011-09-01 14:27:58 +02:00
Lars Jung
480c4aab79 Added thumbs and slide option. 2011-08-16 21:03:09 +02:00
Lars Jung
745bff09cb Changes in /h5ai/.htaccess 2011-08-12 19:04:14 +02:00
Lars Jung
7d6ced78da Fixes on PHP interpretation and tree display. 2011-08-12 15:58:03 +02:00
Lars Jung
b9835ebaad Added PHP implementation. For a full list of changes see README.md. 2011-08-06 13:26:44 +02:00
Lars Jung
8da046d550 Updated readme. 2011-07-30 13:45:26 +02:00
Lars Jung
e5b7ee6125 Added tr translation. 2011-07-30 13:19:28 +02:00
Lars Jung
e70d9029d2 Added es translation. 2011-07-30 12:35:51 +02:00
Lars Jung
b561082bca Updated build process and readme. 2011-07-29 13:52:51 +02:00
Lars Jung
ae464169a6 Updated readme. 2011-07-29 03:25:48 +02:00
Lars Jung
0f681930b3 Fixed unchecked use of console.log. 2011-07-29 02:36:53 +02:00
Lars Jung
5db74d054f Improved preformance for large directories. Changed build process. 2011-07-28 18:07:13 +02:00
209 changed files with 4956 additions and 2427 deletions

2
.gitignore vendored
View File

@@ -2,7 +2,7 @@
# Build folders to ignore
bin
build
#target
target
build.local.*

161
README.md
View File

@@ -1,42 +1,111 @@
# h5ai v0.11   ·   a beautified Apache index
# h5ai
h5ai tries to make browsing files on a Apache HTTP server more comfortable. It makes use of the
built-in autoindex module of Apache and adds styles and functionality to the page generated by
this module.
For installation instructions and documentation have a look at the [project page](http://larsjung.de/h5ai).
There is also a [sample folder](http://larsjung.de/h5ai/sample).
* Website with download, docs and demo: <http://larsjung.de/h5ai>
* Sources: <http://github.com/lrsjng/h5ai>
[h5ai](http://larsjung.de/h5ai) is provided under the terms of the MIT License.
It uses
[HTML5 Boilerplate](http://html5boilerplate.com),
[jQuery](http://jquery.com),
[Modernizr](http://www.modernizr.com) and
[Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228),
please respect their rights.
h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h5ai/blob/master/LICENSE.txt).
It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228) (GPL license).
## Changelog
### v0.11
*2011-07-27*
### v0.15.2 · *2011-09-18*
* added it translation by [Salvo Gentile](http://github.com/SalvoGentile) and [Marco Patriarca](http://github.com/Fexys)
* switched build process from scripp to wepp
### v0.15.1 · *2011-09-06*
* fixed security issues with the zipped download feature
* made zipped download optional (but enabled by default)
### v0.15 · *2011-09-04*
* added zipped download for selected files
* cleaned and refactored
### v0.14.1 · *2011-09-01*
* display meta information in bottom bar (icon view)
* added zh-cn translation by [Dongsheng Cai](http://github.com/dongsheng)
* added pl translation by Radosław Zając
* added ru translation by Богдан Илюхин
### v0.14 · *2011-08-16*
* added image thumbnails for PHP version
* new option `slideTree` to turn off auto slide in
### v0.13.2 · *2011-08-12*
* changes in `/h5ai/.htaccess` ... PHP configuration ...
### v0.13.1 · *2011-08-12*
* ~~hopefully fixed that PHP doesn't get interpreted~~ :/
* fixed initial tree display
* added sort order option
* added/fixed some translations
* added lv translation by Sandis Veinbergs
### v0.13 · *2011-08-06*
* 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.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*
* fixed unchecked use of console.log
### v0.12 · *2011-07-28*
* improved performance
### v0.11 · *2011-07-27*
* 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
### v0.10
*2011-07-24*
### v0.10 · *2011-07-24*
* fixed problems with XAMPP on Windows (see `dot.htaccess` comments for instructions)
* fixed tree fade-in-fade-out effect for small displays ([issue #6](http://github.com/lrsjng/h5ai/issues/6))
@@ -45,8 +114,7 @@ please respect their rights.
* added "empty" to localization (hope Google Translate did a good job here)
### v0.9
*2011-07-18*
### v0.9 · *2011-07-18*
* linked hover states between crumb, extended view and tree
* fixed size of tree view (now there's a ugly scrollbar, hopefully will be fixed)
@@ -57,8 +125,7 @@ please respect their rights.
* added sv translation by Oscar Carlsson
### v0.8
*2011-07-08*
### v0.8 · *2011-07-08*
* removed slashes from folder labels
* optionally rename parent folder entries to real folder names, see `options.js`
@@ -67,22 +134,19 @@ please respect their rights.
* refactored js a lot (again...)
### v0.7
*2011-07-07*
### v0.7 · *2011-07-07*
* removed shadows
* smarter tree side bar
### v0.6
*2011-07-05*
### v0.6 · *2011-07-05*
* refactored js
* 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`
@@ -90,28 +154,24 @@ please respect their rights.
* 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
### v0.5
*2011-07-01*
### v0.5 · *2011-07-01*
* added tree sidebar
* some refactorings
### v0.4
*2011-06-27*
### v0.4 · *2011-06-27*
* added better fallback, in case JavaScript is disabled
* rewrote js, fixed middle-button click etc. problems
@@ -120,23 +180,20 @@ please respect their rights.
* 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
* fixed .emtpy style
### v0.3
*2011-06-23*
### v0.3 · *2011-06-23*
* included build stuff, files previously found in the base directory are now located in folder `target`
* styles and scripts are now minified
@@ -144,23 +201,20 @@ please respect their rights.
* 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
@@ -168,8 +222,7 @@ please respect their rights.
* added changelog
### v0.2
*2011-06-15*
### v0.2 · *2011-06-15*
* added icon view

View File

@@ -1,19 +1,20 @@
custom = true
custom = true
# project
project.name = h5ai
project.version = 0.11
project.name = h5ai
project.version = 0.15.2
# src
src.dir = src
src.dir = src
# build
build.dir = target
build.dir = build
release.dir = release
# libs
lib.scripp.jar = tools/scripp.jar
# tools
wepp = tools/wepp

View File

@@ -1,59 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<project
name="h5ai"
basedir="."
default="build"
xmlns:scripp="antlib:de.larsjung.scripp.ant"
name="h5ai"
basedir="."
default="release"
>
<target name="init">
<property file="build.properties" />
<tstamp>
<format property="build.stamp" pattern="yyyy-MM-dd-HHmmss" />
</tstamp>
<property name="build.label" value="${project.name} ${project.version} b${build.stamp}" />
<echo>Build: ${build.label}</echo>
<taskdef
resource="de/larsjung/scripp/ant/antlib.xml"
uri="antlib:de.larsjung.scripp.ant"
classpath="${lib.scripp.jar}"
/>
</target>
<import file="tools/wepp.ant.xml" />
<target name="clean" depends="init">
<delete dir="${build.dir}" />
</target>
<target name="init">
<property file="build.properties" />
<tstamp>
<format property="build.stamp" pattern="yyyy-MM-dd-HHmmss" />
</tstamp>
<property name="build.label" value="${project.name} ${project.version} b${build.stamp}" />
<echo>Build: ${build.label}</echo>
</target>
<target name="clean" depends="init">
<delete dir="${build.dir}" />
<delete dir="${release.dir}" />
</target>
<target name="build" depends="clean">
<mkdir dir="${build.dir}" />
<copy todir="${build.dir}">
<fileset dir="${src.dir}" />
</copy>
<replace dir="${build.dir}">
<replacefilter token="%BUILD%" value="${build.label}" />
<replacefilter token="%BUILD_NAME%" value="${project.name}" />
<replacefilter token="%BUILD_VERSION%" value="${project.version}" />
<replacefilter token="%BUILD_STAMP%" value="${build.stamp}" />
</replace>
<target name="build-prepare" depends="clean">
<mkdir dir="${build.dir}" />
<copy todir="${build.dir}">
<fileset dir="${src.dir}" />
<fileset file="LICENSE.txt" />
<fileset file="README.md" />
</copy>
<replace dir="${build.dir}">
<replacefilter token="%BUILD%" value="${build.label}" />
<replacefilter token="%BUILD_NAME%" value="${project.name}" />
<replacefilter token="%BUILD_VERSION%" value="${project.version}" />
<replacefilter token="%BUILD_STAMP%" value="${build.stamp}" />
</replace>
</target>
<scripp.dir dir="${build.dir}/h5ai/css" />
<scripp.dir dir="${build.dir}/h5ai/js" />
</target>
<target name="build" depends="build-prepare">
<wepp.dir dir="${build.dir}/h5ai/css" />
<wepp.dir dir="${build.dir}/h5ai/js" />
</target>
<target name="build-uncompressed" depends="build-prepare">
<wepp.dir dir="${build.dir}/h5ai/css" args="--nc" />
<wepp.dir dir="${build.dir}/h5ai/js" args="--nc" />
</target>
<target name="release" depends="build">
<mkdir dir="${release.dir}" />
<zip destfile="${release.dir}/${project.name}-${project.version}.zip" basedir="${build.dir}" />
<tar destfile="${release.dir}/${project.name}-${project.version}.tar" basedir="${build.dir}"/>
<gzip destfile="${release.dir}/${project.name}-${project.version}.tar.gz" src="${release.dir}/${project.name}-${project.version}.tar"/>
<delete file="${release.dir}/${project.name}-${project.version}.tar" />
</target>
<macrodef name="scripp.dir">
<attribute name="dir" />
<sequential>
<scripp:process>
<fileset dir="@{dir}" includes="**/*.less,**/*.css,**/*.js" excludes="inc/**/*,**/*.min.css,**/*.min.js" />
<globmapper from="*.less" to="*.css" />
<globmapper from="*.css" to="*.css" />
<globmapper from="*.js" to="*.js" />
</scripp:process>
<delete dir="@{dir}/inc">
<fileset dir="@{dir}" includes="**/*.less" />
</delete>
</sequential>
</macrodef>
</project>

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

Binary file not shown.

BIN
release/h5ai-0.15.2.zip Normal file

Binary file not shown.

View File

@@ -1,146 +0,0 @@
################################
# %BUILD_NAME% %BUILD_VERSION%
# customized .htaccess
################################
# Options +Indexes
# 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
# following line with
# <IfModule autoindex_color_module>
################################
<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
################################
HeaderName /h5ai/header.html
ReadmeName /h5ai/footer.html
################################
# hide h5ai folder and config files from index
################################
IndexIgnore h5ai h5ai.header.html h5ai.footer.html
################################
# table options
################################
IndexOrderDefault Ascending Name
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions Charset=UTF-8
IndexOptions FancyIndexing
IndexOptions HTMLTable
IndexOptions XHTML
IndexOptions SuppressHTMLPreamble
IndexOptions SuppressRules
IndexOptions SuppressDescription
IndexOptions FoldersFirst
IndexOptions IgnoreCase
IndexOptions IconsAreLinks
IndexOptions VersionSort
IndexOptions NameWidth=*
################################
# icon mapping
################################
AddIcon /h5ai/icons/16x16/parent.png ..
AddIcon /h5ai/icons/16x16/folder.png ^^DIRECTORY^^
AddIcon /h5ai/icons/16x16/blank.png ^^BLANKICON^^
AddIcon /h5ai/icons/16x16/readme.png README
AddIcon /h5ai/icons/16x16/copying.png COPYING LICENSE
AddIcon /h5ai/icons/16x16/install.png INSTALL
AddIcon /h5ai/icons/16x16/authors.png AUTHORS
AddIcon /h5ai/icons/16x16/log.png LOG Log log
AddIcon /h5ai/icons/16x16/css.png .less
AddIcon /h5ai/icons/16x16/script.png .conf .ini .sh .shar .csh .ksh .tcl
AddIcon /h5ai/icons/16x16/makefile.png .pom pom.xml build.xml
AddIcon /h5ai/icons/16x16/bin.png .so .o
AddIcon /h5ai/icons/16x16/archive.png .tar.gz .tgz .tar.bz2
AddIcon /h5ai/icons/16x16/zip.png .zip .Z .z .jar .war .gz .bz2
AddIcon /h5ai/icons/16x16/tar.png .tar
AddIcon /h5ai/icons/16x16/pdf.png .pdf
AddIcon /h5ai/icons/16x16/deb.png .deb
AddIcon /h5ai/icons/16x16/rpm.png .rpm
AddIcon /h5ai/icons/16x16/cd.png .iso .cue
AddIconByType /h5ai/icons/16x16/png.png image/png
AddIconByType /h5ai/icons/16x16/jpg.png image/jpeg
AddIconByType /h5ai/icons/16x16/gif.png image/gif
AddIconByType /h5ai/icons/16x16/ico.png image/x-icon
AddIconByType /h5ai/icons/16x16/bmp.png image/x-ms-bmp
AddIconByType /h5ai/icons/16x16/html.png text/html
AddIconByType /h5ai/icons/16x16/css.png text/css
AddIconByType /h5ai/icons/16x16/xml.png application/xml
AddIconByType /h5ai/icons/16x16/js.png application/javascript application/json
AddIconByType /h5ai/icons/16x16/php.png application/x-httpd-php
AddIconByType /h5ai/icons/16x16/py.png text/x-python
AddIconByType /h5ai/icons/16x16/rb.png application/x-ruby
AddIconByType /h5ai/icons/16x16/java.png text/x-java
AddIconByType /h5ai/icons/16x16/cpp.png text/x-c++src
AddIconByType /h5ai/icons/16x16/hpp.png text/x-c++hdr
AddIconByType /h5ai/icons/16x16/c.png text/x-csrc
AddIconByType /h5ai/icons/16x16/h.png text/x-chdr
AddIconByType /h5ai/icons/16x16/pdf.png application/pdf
AddIconByType /h5ai/icons/16x16/rtf.png text/rtf application/rtf
AddIconByType /h5ai/icons/16x16/tex.png text/x-tex
AddIconByType /h5ai/icons/16x16/makefile.png text/x-makefile
AddIconByType /h5ai/icons/16x16/bin.png application/java-vm
AddIconByType /h5ai/icons/16x16/exe.png application/x-executable application/x-msdos-program
AddIconByType /h5ai/icons/16x16/text.png text/*
AddIconByType /h5ai/icons/16x16/image.png image/*
AddIconByType /h5ai/icons/16x16/audio.png audio/*
AddIconByType /h5ai/icons/16x16/video.png video/*
AddIconByEncoding /h5ai/icons/16x16/zip.png x-compress x-gzip x-bzip2
DefaultIcon /h5ai/icons/16x16/unknown.png
</IfModule>

35
src/h5ai/.htaccess Normal file
View File

@@ -0,0 +1,35 @@
AddType text/html .php
###########################################
# if php doesn't get interpreted try to
# uncomment one of the following lines
###########################################
#AddHandler application/x-httpd-php .php
#AddHandler application/x-httpd-php5 .php
#AddHandler application/x-httpd-php52 .php
#AddHandler application/x-httpd-php53 .php
#AddHandler php-script .php
#AddHandler php5-script .php
#AddHandler php52-script .php
#AddHandler php53-script .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>
<FilesMatch "thumb-.*\.jpg$">
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

@@ -1,209 +1,265 @@
#extended.details-view {
display: none;
display: none;
ul {
margin: 0;
padding: 0;
list-style: none;
ul {
margin: 0;
padding: 0;
list-style: none;
li {
position: relative;
white-space: nowrap;
clear: both;
li {
position: relative;
white-space: nowrap;
clear: both;
&.header {
a, a:active, a:visited {
padding-bottom: 18px;
color: #555;
text-decoration: none;
opacity: 0.4;
cursor: pointer;
.transition( all 0.2s ease-in-out );
&:hover {
color: #555;
opacity: 0.9;
}
img {
width: 12px;
height: 12px;
padding: 0 8px;
}
}
}
&.entry {
border-bottom: 1px solid #ddd;
&.header {
a, a:active, a:visited {
padding-bottom: 18px;
color: #555;
text-decoration: none;
opacity: 0.4;
cursor: pointer;
.transition(all 0.2s ease-in-out);
a, a:active, a:visited {
display: block;
color: #555;
text-decoration: none;
cursor: pointer;
&:hover, &.hover {
background-color: #f6f6f6;
color: #e80;
}
}
&.error {
a, a:active, a:visited {
color: #aaa;
.label {
.hint {
margin-left: 12px;
font-size: 0.9em;
color: #c55;
}
}
&:hover, &.hover {
opacity: 1;
background-color: #f6f6f6;
color: #e80;
}
}
}
}
.icon, .label, .date, .size {
padding: 6px;
}
.icon {
display: inline-block;
position: absolute;
left: 0;
top: 2px;
width: 16px;
&:hover {
color: #555;
opacity: 0.9;
}
img {
width: 12px;
height: 12px;
padding: 0 8px;
}
}
}
&.entry {
img {
width: 16px;
height: 16px;
}
}
.icon.big {
display: none;
}
.label {
display: block;
margin: 0 270px 0 24px;
overflow: hidden;
white-space: nowrap;
text-align: left;
}
.date {
position: absolute;
right: 100px;
top: 0;
text-align: right;
width: 160px;
white-space: nowrap;
}
.size {
position: absolute;
right: 0;
top: 0;
text-align: right;
width: 80px;
white-space: nowrap;
}
}
}
.empty {
text-align: center;
margin: 50px 0;
color: #ddd;
font-size: 5em;
font-weight: bold;
}
a, a:active, a:visited {
display: block;
color: #555;
text-decoration: none;
cursor: pointer;
border-bottom: 1px solid #ddd;
&:hover, &.hover {
background-color: #f6f6f6;
color: #e80;
}
&.selected {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
}
&.error {
a, a:active, a:visited {
color: #aaa;
.label {
.hint {
margin-left: 12px;
font-size: 0.9em;
color: #c55;
}
}
&:hover, &.hover {
opacity: 1;
background-color: #f6f6f6;
color: #e80;
}
}
}
&.folder-parent {
.date, .size {
display: none;
}
}
&.folder {
.size {
display: none;
}
}
}
.icon, .label, .date, .size {
padding: 6px;
}
.icon {
display: inline-block;
position: absolute;
left: 0;
top: 2px;
width: 16px;
img {
width: 16px;
height: 16px;
}
}
.icon.big {
display: none;
}
.label {
display: block;
margin: 0 270px 0 24px;
overflow: hidden;
white-space: nowrap;
text-align: left;
}
.date {
position: absolute;
right: 100px;
top: 0;
text-align: right;
width: 160px;
white-space: nowrap;
}
.size {
position: absolute;
right: 0;
top: 0;
text-align: right;
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 {
text-align: center;
margin: 50px 0;
color: #ddd;
font-size: 5em;
font-weight: bold;
}
}
#selection-rect {
display: none;
position: absolute;
left: 0;
top: 0;
z-index: 2;
border: 1px dashed rgba(240,100,0,0.5);
background-color: rgba(240,100,0,0.2);
}
#extended.icons-view {
display: none;
padding: 3px;
border: 1px solid #eee;
border-radius: 15px;
display: none;
padding: 3px;
border: 1px solid #eee;
border-radius: 15px;
ul {
margin: 0;
padding: 0;
list-style: none;
ul {
margin: 0;
padding: 0;
list-style: none;
li {
&.header {
display: none;
}
&.entry {
float: left;
li {
&.header {
display: none;
}
&.entry {
float: left;
a, a:active, a:visited {
display: block;
margin: 8px;
padding: 8px;
width: 100px;
height: 120px;
float: left;
text-align: center;
text-decoration: none;
overflow: hidden;
border-radius: 5px;
color: #555;
cursor: pointer;
border: 2px solid rgba(0,0,0,0);
&:hover, &.hover {
color: #e80;
border-color: #eee;
background-color: #f6f6f6;
}
.icon {
display: block;
a, a:active, a:visited {
display: block;
margin: 8px;
padding: 8px;
width: 100px;
height: 120px;
float: left;
text-align: center;
text-decoration: none;
overflow: hidden;
border-radius: 5px;
color: #555;
cursor: pointer;
border: 2px solid rgba(0,0,0,0);
img {
width: 48px;
height: 48px;
margin-bottom: 8px;
}
}
.icon.small {
display: none;
}
.label {
display: block;
word-wrap: break-word;
}
.date, .size {
display: none;
}
}
&.error {
a, a:active, a:visited {
color: #aaa;
text-decoration: none;
.label {
.hint {
padding: 0 6px;
font-size: 0.9em;
color: #c55;
}
}
&:hover, &.hover {
color: #e80;
border-color: #eee;
background-color: #f6f6f6;
}
}
}
}
}
}
.empty {
padding: 16px;
height: 120px;
text-align: center;
color: #ddd;
font-size: 5em;
font-weight: bold;
}
&:hover, &.hover {
color: #e80;
border-color: #eee;
background-color: #f6f6f6;
}
&.selected {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
.icon {
display: block;
img {
min-width: 48px;
min-height: 48px;
margin-bottom: 8px;
}
}
.icon.small {
display: none;
}
.label {
display: block;
word-wrap: break-word;
}
.date, .size {
display: none;
}
}
&.error {
a, a:active, a:visited {
color: #aaa;
text-decoration: none;
.label {
.hint {
padding: 0 6px;
font-size: 0.9em;
color: #c55;
}
}
&:hover, &.hover {
color: #e80;
border-color: #eee;
background-color: #f6f6f6;
}
}
}
}
&.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 {
padding: 16px;
height: 120px;
text-align: center;
color: #ddd;
font-size: 5em;
font-weight: bold;
}
}

View File

@@ -53,8 +53,8 @@ sup { top: -0.5em; }
sub { bottom: -0.25em; }
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; }
textarea { overflow: auto; }
.ie6 legend, .ie7 legend { margin-left: -7px; }
textarea { overflow: auto; }
.ie6 legend, .ie7 legend { margin-left: -7px; }
input[type="radio"] { vertical-align: text-bottom; }
input[type="checkbox"] { vertical-align: bottom; }
.ie7 input[type="checkbox"] { vertical-align: baseline; }
@@ -81,7 +81,7 @@ a:hover { color: #036; }
/**
* Primary styles
*
* Author:
* Author:
*/
@@ -117,20 +117,20 @@ a:hover { color: #036; }
}
@media screen and (max-device-width: 480px) {
/* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
}
@media print {
* { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important;
-ms-filter: none !important; }
-ms-filter: none !important; }
a, a:visited { color: #444 !important; text-decoration: underline; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
thead { display: table-header-group; }
thead { display: table-header-group; }
tr, img { page-break-inside: avoid; }
@page { margin: 0.5cm; }
p, h2, h3 { orphans: 3; widows: 3; }

210
src/h5ai/css/inc/main.less Normal file
View File

@@ -0,0 +1,210 @@
@import "html5reset";
@import "mixins";
html.js {
.hideOnJs {
display: none;
}
}
html.no-js {
.hideOnNoJs {
display: none;
}
}
body {
font-family: Ubuntu, sans-serif;
font-size: 16px;
color: #555;
margin: 80px 30px;
}
body > nav {
position: fixed;
z-index: 1;
width: 100%;
left: 0;
top: 0;
font-size: 0.85em;
background-color: rgb(241,241,241);
border-bottom: 2px solid rgb(210,210,210);
span.jsDisabledFallback {
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: #999;
}
a, a:active, a:visited {
color: #555;
cursor: pointer;
text-decoration: none;
opacity: 0.7;
.transition(all 0.2s ease-in-out);
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
&:hover, &.hover {
color: #e80;
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
}
.current a {
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
img {
width: 16px;
height: 16px;
vertical-align: bottom;
padding: 0 6px 6px 0;
}
.crumb {
float: left;
border-right: 1px solid rgb(231,231,231);
.hint {
margin-left: 8px;
font-style: italic;
color: #999;
}
img.hint {
width: 10px;
height: 10px;
vertical-align: baseline;
padding: 0px;
}
}
.view {
float: right;
border-left: 1px solid rgb(231,231,231);
}
#download {
display: none;
float: right;
border-left: 1px solid rgb(231,231,231);
}
}
#content {
max-width: 960px;
margin: 0 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;
}
}
@import "table";
@import "extended";
@import "tree";
body > footer {
position: fixed;
z-index: 1;
width: 100%;
left: 0;
bottom: 0;
padding: 6px 0 8px 0;
background-color: rgb(241,241,241);
border-top: 2px 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 300px;
}
.right {
display: block;
padding: 0 8px;
float: right
}
.status {
.sep {
display: inline-block;
padding: 0 6px;
}
&.default {
}
&.dynamic {
display: none;
}
}
#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);
}
}
}
}
}
}

View File

@@ -1,38 +1,38 @@
.border-radius ( @radius ) {
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
border-radius: @radius;
.border-radius (@radius) {
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
border-radius: @radius;
}
.box-shadow ( @shadow ) {
-moz-box-shadow: @shadow;
-webkit-box-shadow: @shadow;
box-shadow: @shadow;
.box-shadow (@shadow) {
-moz-box-shadow: @shadow;
-webkit-box-shadow: @shadow;
box-shadow: @shadow;
}
.transition ( @transition ) {
-moz-transition: @transition;
-ms-transition: @transition;
-o-transition: @transition;
-webkit-transition: @transition;
transition: @transition;
.transition (@transition) {
-moz-transition: @transition;
-ms-transition: @transition;
-o-transition: @transition;
-webkit-transition: @transition;
transition: @transition;
}
.transform ( @transform ) {
-moz-transform: @transform;
-o-transform: @transform;
-webkit-transform: @transform;
transform: @transform;
.transform (@transform) {
-moz-transform: @transform;
-o-transform: @transform;
-webkit-transform: @transform;
transform: @transform;
}
.background-size ( @size ) {
-moz-background-size: @size;
-webkit-background-size: @size;
background-size: @size;
.background-size (@size) {
-moz-background-size: @size;
-webkit-background-size: @size;
background-size: @size;
}

View File

@@ -1,68 +1,68 @@
#table {
table {
display: block;
width: 100%;
border-collapse: collapse;
table {
display: block;
width: 100%;
border-collapse: collapse;
th, td {
padding: 3px 6px;
text-align: left;
border: none;
}
th {
padding-bottom: 18px;
opacity: 0.4;
.transition( all 0.2s ease-in-out );
th, td {
padding: 3px 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;
&:hover, &:hover a {
color: #555;
cursor: pointer;
opacity: 0.9;
}
a, a:visited {
color: #555;
font-weight: normal;
img {
width: 12px;
height: 12px;
padding: 0 8px;
}
}
}
td {
border: 1px solid #ddd;
border-left: none;
border-right: none;
}
td:nth-child(1), th:nth-child(1) {
text-align: center;
width: 16px;
img {
width: 12px;
height: 12px;
padding: 0 8px;
}
}
}
td {
border: 1px solid #ddd;
border-left: none;
border-right: none;
}
td:nth-child(1), th:nth-child(1) {
text-align: center;
width: 16px;
img {
width: 16px;
height: 16px;
padding-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;
}
}
img {
width: 16px;
height: 16px;
padding-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

@@ -1,128 +1,129 @@
#tree {
position: fixed;
display: none;
left: 0;
top: 0;
overflow: auto;
font-size: 0.85em;
padding: 16px 16px 16px 16px;
background-color: rgb(241,241,241);
border: 2px solid rgb(210,210,210);
border-left: none;
.border-radius ( 0 15px 15px 0 );
display: none;
position: fixed;
left: 0;
top: 82px;
z-index: 1;
overflow: auto;
font-size: 0.85em;
padding: 16px 16px 16px 16px;
background-color: rgb(241,241,241);
border: 2px solid rgb(210,210,210);
border-left: none;
.border-radius (0 15px 15px 0);
> .scrollbar {
margin: 12px 12px 12px 0;
width: 6px;
background-color: rgb(210,210,210);
.border-radius( 3px );
.drag {
background-color: rgb(180,180,180);
.border-radius( 3px );
}
&.dragOn .drag {
background-color: rgb(150,150,150);
}
}
.entry {
.blank, .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;
top: 3px;
width: 12px;
height: 12px;
vertical-align: bottom;
.transition( all 0.2s ease-in-out );
}
&.open {
img {
.transform( rotate(90deg) );
}
}
&.unknown {
opacity: 0.3;
}
}
> a, > a:active, > a.visited {
margin-left: 16px;
padding: 4px 6px;
border: 1px solid rgba(0,0,0,0);
.border-radius( 5px );
display: block;
color: #555;
text-decoration: none;
opacity: 0.7;
> .scrollbar {
margin: 12px 12px 12px 0;
width: 6px;
background-color: rgb(210,210,210);
.border-radius(3px);
&:hover, &.hover {
color: #e80;
background-color: rgba(255,255,255,0.5);
opacity: 1;
}
.label {
display: inline-block;
}
.icon {
display: inline-block;
width: 20px;
img {
width: 16px;
height: 16px;
vertical-align: bottom;
}
}
.hint {
display: inline-block;
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);
background-color: rgba(255,255,255,0.5);
opacity: 1;
}
}
&.error {
> a, > a:active, > a:visited {
color: #999;
&:hover, &.hover {
color: #e80;
}
}
.hint {
color: #c55;
}
}
.content {
list-style: none;
margin-left: 20px;
}
}
.drag {
background-color: rgb(180,180,180);
.border-radius(3px);
}
&.dragOn .drag {
background-color: rgb(150,150,150);
}
}
.entry {
.blank, .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;
top: 3px;
width: 12px;
height: 12px;
vertical-align: bottom;
.transition(all 0.2s ease-in-out);
}
&.open {
img {
.transform(rotate(90deg));
}
}
&.unknown {
opacity: 0.3;
}
}
> a, > a:active, > a.visited {
margin-left: 16px;
padding: 4px 6px;
border: 1px solid rgba(0,0,0,0);
.border-radius(5px);
display: block;
color: #555;
text-decoration: none;
opacity: 0.7;
&:hover, &.hover {
color: #e80;
background-color: rgba(255,255,255,0.5);
opacity: 1;
}
.label {
display: inline-block;
}
.icon {
display: inline-block;
width: 20px;
img {
width: 16px;
height: 16px;
vertical-align: bottom;
}
}
.hint {
display: inline-block;
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);
background-color: rgba(255,255,255,0.5);
opacity: 1;
}
}
&.error {
> a, > a:active, > a:visited {
color: #999;
&:hover, &.hover {
color: #e80;
}
}
.hint {
color: #c55;
}
}
.content {
list-style: none;
margin-left: 20px;
}
}
}

View File

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

View File

@@ -0,0 +1,17 @@
@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

@@ -1,158 +0,0 @@
@import "inc/html5reset";
@import "inc/mixins";
html.js {
.jsDisabledFallback {
display: none;
}
}
html.no-js {
body > nav ul {
display: none;
}
}
body {
font-family: Ubuntu, sans-serif;
font-size: 16px;
color: #555;
margin: 80px 30px;
}
body > nav {
position: fixed;
z-index: 1;
width: 100%;
left: 0;
top: 0;
font-size: 0.85em;
background-color: rgb(241,241,241);
border-bottom: 2px solid rgb(210,210,210);
span.jsDisabledFallback {
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: #999;
}
a, a:active, a:visited {
color: #555;
cursor: pointer;
text-decoration: none;
opacity: 0.7;
.transition( all 0.2s ease-in-out );
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
&:hover, &.hover {
color: #e80;
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
}
.current a {
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
img {
width: 16px;
height: 16px;
vertical-align: bottom;
padding: 0 6px 6px 0;
}
.crumb {
float: left;
border-right: 1px solid rgb(231,231,231);
.hint {
margin-left: 8px;
font-style: italic;
color: #999;
}
img.hint {
width: 10px;
height: 10px;
vertical-align: baseline;
padding: 0px;
}
}
.view {
float: right;
border-left: 1px solid rgb(231,231,231);
}
}
#content {
max-width: 960px;
margin: 0 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;
}
}
@import "inc/table";
@import "inc/extended";
@import "inc/tree";
body > footer {
position: fixed;
z-index: 1;
width: 100%;
left: 0;
bottom: 0;
padding: 10px 0;
background-color: rgb(241,241,241);
border-top: 2px 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 );
&:hover {
color: #e80;
}
}
}
#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,23 +1,34 @@
<!-- generated code ends here -->
</section>
<section id="extended"></section>
<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>
<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/options.js"></script>
<script src="/h5ai/js/main.js"></script>
<!-- generated code ends here -->
</section>
<section id="extended" class="clearfix"></section>
<footer></footer>
</section>
<section id="tree"></section>
<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="status default">
<span class="folderCount"></span> <span class="l10n-folders">folders</span>
<span class='sep'>·</span>
<span class="fileCount"></span> <span class="l10n-files">files</span>
</span>
<span class="status dynamic">
</span>
</span>
</span>
</footer>
<script src="/h5ai/js/lib/jquery.min.js"></script>
<script src="/h5ai/options.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

@@ -1,35 +1,38 @@
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Directory index · styled with h5ai</title>
<meta name="h5ai-version" content="h5ai %BUILD_VERSION%">
<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">
<script src="/h5ai/js/lib/modernizr.min.js"></script>
<meta charset="utf-8">
<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="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-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>
<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>
</ul>
</nav>
<section id="content">
<header></header>
<section id="table" class="jsDisabledFallback">
<!--
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
removed via javascript. The actual page should render as perfect HTML 5, even if the produced
source is not valid HTML 5.
-->
<div id="selection-rect"></div>
<nav class="clearfix">
<ul>
<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>
<li id="download" class="hideOnNoJs">
<a href="#"><img src="/h5ai/images/download.png" alt="download" /><span class="l10n-download">download</span></a>
</li>
</ul>
</nav>
<section id="content">
<header></header>
<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
removed via javascript. The actual page should render as perfect HTML 5, even if the produced
source is not valid HTML 5.
-->

63
src/h5ai/header.php Normal file
View File

@@ -0,0 +1,63 @@
<!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>
<div id="selection-rect"></div>
<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>
<li id="download" class="hideOnNoJs">
<a href="#"><img src="/h5ai/images/download.png" alt="download" /><span class="l10n-download">download</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">
<span class="status default">
<?php echo $extended->getFolderCount(); ?> <span class="l10n-folders">folders</span>
<span class='sep'>·</span>
<?php echo $extended->getFileCount(); ?> <span class="l10n-files">files</span>
</span>
<span class="status dynamic">
</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

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

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

119
src/h5ai/js/inc/extended.js Normal file
View File

@@ -0,0 +1,119 @@
var Extended = function (pathCache, h5ai) {
"use strict";
/*global $*/
var settings = {
customHeader: "h5ai.header.html",
customFooter: "h5ai.footer.html"
},
initTitle = function () {
document.title = document.domain + document.location.pathname;
try {
document.title = decodeURI(document.title);
} catch (err) {}
},
initBreadcrumb = function () {
var idx, part,
$ul = $("body > nav ul"),
pathname = "/",
path = pathCache.getPath(pathname),
pathnameParts = document.location.pathname.split("/");
$ul.append(path.updateCrumbHtml());
for (idx in pathnameParts) {
part = pathnameParts[idx];
if (part !== "") {
pathname += part + "/";
$ul.append(pathCache.getPath(pathname).updateCrumbHtml());
}
}
},
initExtendedView = function () {
var $ths = $("#table th"),
$label = $ths.eq(1).find("a"),
$date = $ths.eq(2).find("a"),
$size = $ths.eq(3).find("a"),
sortquery = document.location.search,
order = {
column: (sortquery.indexOf("C=N") >= 0) ? "name" : (sortquery.indexOf("C=M") >= 0) ? "date" : (sortquery.indexOf("C=S") >= 0) ? "size" : h5ai.settings.sortorder.column,
ascending: (sortquery.indexOf("O=A") >= 0) ? true : (sortquery.indexOf("O=D") >= 0) ? false : h5ai.settings.sortorder.ascending
},
$icon, $ul, $li;
$ul = $("<ul/>");
$li = $("<li class='header' />")
.appendTo($ul)
.append($("<a class='icon'></a>"))
.append($("<a class='label' href='" + $label.attr("href") + "'><span class='l10n-name'>" + $label.text() + "</span></a>"))
.append($("<a class='date' href='" + $date.attr("href") + "'><span class='l10n-lastModified'>" + $date.text() + "</span></a>"))
.append($("<a class='size' href='" + $size.attr("href") + "'><span class='l10n-size'>" + $size.text() + "</span></a>"));
// header sort icons
if (order.ascending) {
$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.column === "date") {
$li.find("a.date").prepend($icon);
} else if (order.column === "size") {
$li.find("a.size").prepend($icon);
} else {
$li.find("a.label").append($icon);
}
// entries
$("#table td").closest("tr").each(function () {
var path = pathCache.getPath(document.location.pathname, this);
$ul.append(path.updateExtendedHtml());
});
$("#extended").append($ul);
// empty
if ($ul.children(".entry:not(.parentfolder)").size() === 0) {
$("#extended").append($("<div class='empty l10n-empty'>empty</div>"));
}
},
customize = function () {
$.ajax({
url: settings.customHeader,
dataType: "html",
success: function (data) {
$("#content > header").append($(data)).show();
}
});
$.ajax({
url: settings.customFooter,
dataType: "html",
success: function (data) {
$("#content > footer").prepend($(data)).show();
}
});
},
initCounts = function () {
$(".folderCount").text($("#extended .entry.folder:not(.parentfolder)").size());
$(".fileCount").text($("#extended .entry.file").size());
},
init = function () {
initTitle();
initBreadcrumb();
initExtendedView();
customize();
initCounts();
},
extended = {
init: init
};
return extended;
};

View File

@@ -1,319 +1,395 @@
var H5ai = function ( options, langs, pathCache ) {
/*******************************
* config
*******************************/
var defaults = {
defaultSortOrder: "C=N;O=A",
store: {
viewmode: "h5ai.viewmode"
},
customHeader: "h5ai.header.html",
customFooter: "h5ai.footer.html",
callbacks: {
pathClick: []
},
viewmodes: [ "details", "icons" ],
showTree: false,
folderStatus: {
},
lang: undefined,
useBrowserLang: true,
setParentFolderLabels: true,
linkHoverStates: true
};
this.config = $.extend( {}, defaults, options );
/*******************************
* public api
*******************************/
this.pathClick = function ( fn ) {
if ( $.isFunction( fn ) ) {
this.config.callbacks.pathClick.push( fn );
};
return this;
};
/*******************************
* init
*******************************/
this.init = function () {
document.title = decodeURI( document.domain + document.location.pathname );
this.applyViewmode();
this.initBreadcrumb();
this.initTopSpace();
this.initViews();
this.customize();
this.localize( langs, this.config.lang, this.config.useBrowserLang );
};
/*******************************
* callback triggers
*******************************/
this.triggerPathClick = function ( path, context ) {
for ( idx in this.config.callbacks.pathClick ) {
this.config.callbacks.pathClick[idx].call( window, path, context );
};
};
/*******************************
* local stored viewmode
*******************************/
this.getViewmode = function () {
var viewmode = localStorage.getItem( this.config.store.viewmode );
return $.inArray( viewmode, this.config.viewmodes ) >= 0 ? viewmode : this.config.viewmodes[0];
};
this.applyViewmode = function ( viewmode ) {
if ( viewmode !== undefined ) {
localStorage.setItem( this.config.store.viewmode, viewmode );
};
viewmode = this.getViewmode();
$( "body > nav li.view" ).hide().removeClass( "current" );
if ( this.config.viewmodes.length > 1 ) {
if ( $.inArray( "details", this.config.viewmodes ) >= 0 ) {
$( "#viewdetails" ).show();
};
if ( $.inArray( "icons", this.config.viewmodes ) >= 0 ) {
$( "#viewicons" ).show();
};
};
if ( viewmode === "details" ) {
$( "#viewdetails" ).closest( "li" ).addClass( "current" );
$( "#table" ).hide();
$( "#extended" ).addClass( "details-view" ).removeClass( "icons-view" ).show();
} else if ( viewmode === "icons" ) {
$( "#viewicons" ).closest( "li" ).addClass( "current" );
$( "#table" ).hide();
$( "#extended" ).removeClass( "details-view" ).addClass( "icons-view" ).show();
} else {
$( "#table" ).show();
$( "#extended" ).hide();
};
};
/*******************************
* 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
*******************************/
this.initTopSpace = function () {
function adjustTopSpace() {
var winHeight = $( window ).height();
var navHeight = $( "body > nav" ).outerHeight();
var footerHeight = $( "body > footer" ).outerHeight();
var contentSpacing = 50;
var treeSpacing = 50;
$( "body" )
.css( "margin-top", "" + ( navHeight + contentSpacing ) + "px" )
.css( "margin-bottom", "" + ( footerHeight + contentSpacing ) + "px" );
$( "#tree" )
.css( "top", "" + ( navHeight + treeSpacing ) + "px" )
.css( "height", "" + ( winHeight - navHeight - footerHeight - 36 - 2 * treeSpacing ) + "px" );
try {
$( "#tree" ).get( 0 ).updateScrollbar();
} catch ( err ) {};
};
$( window ).resize( function () {
adjustTopSpace();
} );
adjustTopSpace();
};
/*******************************
* table view
*******************************/
this.initTableView = function () {
$( "#table td" ).removeAttr( "align" ).removeAttr( "valign" );
};
/*******************************
* 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 );
};
// entries
$( "#table td" ).closest( "tr" ).each( function () {
var path = pathCache.getPathForTableRow( document.location.pathname, this );
$ul.append( path.updateExtendedHtml() );
} );
$( "#table" ).remove();
$( "#extended" ).append( $ul );
// 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.initTableView();
this.initExtendedView();
$( "#viewdetails" ).closest( "li" )
.click( $.proxy( function () {
this.applyViewmode( "details" );
}, this ) );
$( "#viewicons" ).closest( "li" )
.click( $.proxy( function () {
this.applyViewmode( "icons" );
}, this ) );
};
/*******************************
* 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();
}
} );
};
/*******************************
* localization
*******************************/
this.localize = function ( data, lang, useBrowserLang ) {
if ( useBrowserLang === true ) {
var browserLang = navigator.language;
if ( data[ browserLang ] !== undefined ) {
lang = browserLang;
} else if ( browserLang.length > 2 && data[ 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] );
};
};
};
var H5ai = function (options, langs) {
"use strict";
/*global $, window, localStorage*/
var defaults = {
store: {
viewmode: "h5ai.viewmode",
lang: "h5ai.lang"
},
callbacks: {
pathClick: []
},
viewmodes: ["details", "icons"],
sortorder: {
column: "name",
ascending: true
},
showTree: true,
slideTree: true,
folderStatus: {},
lang: null,
useBrowserLang: true,
setParentFolderLabels: true,
linkHoverStates: true,
dateFormat: "Y-m-d H:i",
ignore: ["h5ai", "h5ai.header.html", "h5ai.footer.html"],
ignoreRE: ["/^\\./"],
showThumbs: true,
zippedDownload: true
},
settings = $.extend({}, defaults, options),
pathClick = function (fn) {
if ($.isFunction(fn)) {
settings.callbacks.pathClick.push(fn);
}
},
triggerPathClick = function (path, context) {
var i, l, a = settings.callbacks.pathClick;
for (i = 0, l = a.length; i < l; i++) {
a[i].call(window, path, context);
}
},
getViewmode = function () {
var viewmode = localStorage.getItem(settings.store.viewmode);
return $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0];
},
applyViewmode = function (viewmode) {
if (viewmode) {
localStorage.setItem(settings.store.viewmode, viewmode);
}
viewmode = getViewmode();
$("#viewdetails,#viewicons").hide().removeClass("current");
if (settings.viewmodes.length > 1) {
if ($.inArray("details", settings.viewmodes) >= 0) {
$("#viewdetails").show();
}
if ($.inArray("icons", settings.viewmodes) >= 0) {
$("#viewicons").show();
}
}
if (viewmode === "details") {
$("#viewdetails").closest("li").addClass("current");
$("#extended").addClass("details-view").removeClass("icons-view").show();
} else if (viewmode === "icons") {
$("#viewicons").closest("li").addClass("current");
$("#extended").removeClass("details-view").addClass("icons-view").show();
} else {
$("#extended").hide();
}
},
initTopSpace = function () {
var adjustTopSpace = function () {
var winHeight = $(window).height(),
navHeight = $("body > nav").outerHeight(),
footerHeight = $("body > footer").outerHeight(),
contentSpacing = 50,
treeSpacing = 50;
$("body").css({
"margin-top": navHeight + contentSpacing,
"margin-bottom": footerHeight + contentSpacing
});
$("#tree").css({
top: navHeight + treeSpacing,
height: winHeight - navHeight - footerHeight - 36 - 2 * treeSpacing
});
try {
$("#tree").get(0).updateScrollbar();
} catch (err) {}
};
$(window).resize(function () {
adjustTopSpace();
});
adjustTopSpace();
},
initViews = function () {
$("#table").remove();
$("#viewdetails").closest("li")
.click(function () { applyViewmode("details"); });
$("#viewicons").closest("li")
.click(function () { applyViewmode("icons"); });
// status update
$("#extended .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);
},
linkHoverStates = function () {
if (settings.linkHoverStates) {
$("a[href^='/']:not(.linkedHoverStates)").each(function () {
var $a = $(this).addClass("linkedHoverStates"),
href = $a.attr("href");
$a.hover(
function () { $("a[href='" + href + "']").addClass("hover"); },
function () { $("a[href='" + href + "']").removeClass("hover"); }
);
});
}
},
localize = function (langs, lang, useBrowserLang) {
var storedLang = localStorage.getItem(settings.store.lang),
browserLang, selected, key;
if (langs[storedLang]) {
lang = storedLang;
} else if (useBrowserLang) {
browserLang = navigator.language;
if (langs[browserLang]) {
lang = browserLang;
} else if (browserLang.length > 2 && langs[browserLang.substr(0, 2)]) {
lang = browserLang.substr(0, 2);
}
}
if (!langs[lang]) {
lang = "en";
}
selected = langs[lang];
if (selected) {
for (key in selected) {
$(".l10n-" + key).text(selected[key]);
}
$(".lang").text(lang);
$(".langOption").removeClass("current");
$(".langOption." + lang).addClass("current");
}
},
initLangSelector = function (langs) {
var idx, lang,
sortedLangsKeys = [],
$ul;
for (lang in langs) {
sortedLangsKeys.push(lang);
}
sortedLangsKeys.sort();
$ul = $("<ul />");
for (idx in sortedLangsKeys) {
(function (lang) {
$("<li class='langOption' />")
.addClass(lang)
.text(lang + " - " + langs[lang].lang)
.appendTo($ul)
.click(function () {
localStorage.setItem(settings.store.lang, lang);
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();
}
);
},
initIndicators = function () {
$("#tree .entry.folder:not(.initiatedIndicator)").each(function () {
var $entry = $(this).addClass("initiatedIndicator"),
$indicator = $entry.find("> .indicator");
$indicator.click(function (event) {
var $content;
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();
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();
});
}
});
});
},
initZippedDownload = function () {
var x = 0,
y = 0,
$window = $(window),
selected = function (hrefs) {
var query, idx;
for (idx in hrefs) {
query = query ? query + ":" + hrefs[idx] : hrefs[idx];
}
query = "/h5ai/php/zipcontent.php?hrefs=" + query;
$("#download").show().find("a").attr("href", query);
},
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),
sel;
event.preventDefault();
$("#selection-rect").css({left: l, top: t, width: w, height: h});
sel = $("#selection-rect").fracs("rect");
$("#extended a").removeClass("selected").each(function () {
var $a = $(this),
rect = $a.fracs("rect"),
inter = sel.intersection(rect);
if (inter && !$a.closest(".entry").hasClass("folder-parent")) {
$a.addClass("selected");
}
});
},
selectionEnd = function (event) {
event.preventDefault();
$("#selection-rect").hide().css({left: 0, top: 0, width: 0, height: 0});
$window.unbind("mousemove", selectionUpdate);
var hrefs = [];
$("#extended a.selected").each(function () {
hrefs.push($(this).attr("href"));
});
if (hrefs.length > 0) {
selected(hrefs);
}
},
selectionStart = function (event) {
event.preventDefault();
x = event.pageX;
y = event.pageY;
$("#download").hide().find("a").attr("href", "#");
$("#extended a").removeClass("selected");
$("#selection-rect").show().css({left: x, top: y, width: 0, height: 0});
$window
.bind("mousemove", selectionUpdate)
.one("mouseup", selectionEnd);
},
noSelection = function (event) {
event.stopPropagation();
return false;
};
if (settings.zippedDownload) {
$("body>nav,body>footer,#tree,#extended a").bind("mousedown", noSelection);
$("#extended a").live("mousedown", noSelection);
$window.bind("mousedown", selectionStart);
}
},
init = function () {
applyViewmode();
initTopSpace();
initViews();
initTree();
linkHoverStates();
initLangSelector(langs);
localize(langs, settings.lang, settings.useBrowserLang);
initIndicators();
initZippedDownload();
},
h5ai = {
settings: settings,
shiftTree: shiftTree,
linkHoverStates: linkHoverStates,
pathClick: pathClick,
triggerPathClick: triggerPathClick,
init: init
};
return h5ai;
};

View File

@@ -0,0 +1,871 @@
/*
* jQuery.fracs 0.10
* http://larsjung.de/fracs
*
* provided under the terms of the MIT License
*/
/*
* ModPlug 0.4
* http://larsjung.de/modplug
*
* provided under the terms of the MIT License
*/
(function ($) {
"use strict";
/*globals jQuery */
/*jslint confusion: true */
var reference = "_mp_api";
$.ModPlug = $.ModPlug || {
plugin: function (namespace, options) {
if (!namespace || $[namespace] || $.fn[namespace]) {
// $.error("No namespace specified, or a plugin already exists on 'jQuery." + namespace + "'");
return !namespace ? 1 : ($[namespace] ? 2 : 3);
}
var defaults = {
statics: {},
methods: {},
defaultStatic: undefined,
defaultMethod: undefined
},
settings = $.extend({}, defaults, options),
staticPlug = function () {
var args, defaultMethod;
args = Array.prototype.slice.call(arguments);
defaultMethod = settings.defaultStatic instanceof Function ? settings.defaultStatic.apply(this, args) : settings.defaultStatic;
if (staticPlug[defaultMethod] instanceof Function) {
return staticPlug[defaultMethod].apply(this, args);
}
$.error("Static method defaulted to '" + defaultMethod + "' does not exist on 'jQuery." + namespace + "'");
},
methods = {},
methodPlug = function (method) {
var args, defaultMethod;
if (methods[method] instanceof Function) {
args = Array.prototype.slice.call(arguments, 1);
return methods[method].apply(this, args);
}
args = Array.prototype.slice.call(arguments);
defaultMethod = settings.defaultMethod instanceof Function ? settings.defaultMethod.apply(this, args) : settings.defaultMethod;
if (methods[defaultMethod] instanceof Function) {
return methods[defaultMethod].apply(this, args);
}
$.error("Method '" + method + "' defaulted to '" + defaultMethod + "' does not exist on 'jQuery." + namespace + "'");
},
api = {
addStatics: function (newStatics) {
$.extend(staticPlug, newStatics);
staticPlug[reference] = api;
return this;
},
addMethods: function (newMethods) {
$.extend(methods, newMethods);
return this;
}
};
api.addStatics(settings.statics).addMethods(settings.methods);
$[namespace] = staticPlug;
$.fn[namespace] = methodPlug;
return 0;
},
module: function (namespace, options) {
if (!$[namespace] || !$[namespace][reference]) {
// $.error("No ModPlug plugin exists on 'jQuery." + namespace + "'");
return !$[namespace] ? 1 : 2;
}
var defaults = {
statics: {},
methods: {}
},
settings = $.extend({}, defaults, options);
$[namespace][reference].addStatics(settings.statics).addMethods(settings.methods);
return 0;
}
};
}(jQuery));
/*
* jQuery.fracs - Core API
*/
(function ($) {
"use strict";
/*globals jQuery, HTMLElement */
/*jslint browser: true, vars: true */
var FracsData = function (htmlElementOrRect) {
var target = htmlElementOrRect,
callbacks = [],
prevFracs;
this.size = function () {
return callbacks.length;
};
this.bind = function (callback) {
if (callback instanceof Function && $.inArray(callback, callbacks) === -1) {
callbacks.push(callback);
}
};
this.unbind = function (callback) {
if (callback instanceof Function) {
var idx = $.inArray(callback, callbacks);
if (idx >= 0) {
callbacks.splice(idx, 1);
}
} else {
callbacks = [];
}
};
this.check = function () {
var rect = target instanceof HTMLElement ? $.fracs.rect(target) : target,
fracs = $.fracs.fracs(rect, $.fracs.viewport());
if (!prevFracs || !prevFracs.equals(fracs)) {
$.each(callbacks, function (idx, callback) {
callback.call(target, fracs, prevFracs);
});
prevFracs = fracs;
}
};
};
var Rect = function (left, top, width, height) {
var fracsData;
this.left = Math.round(left);
this.top = Math.round(top);
this.width = Math.round(width);
this.height = Math.round(height);
this.right = this.left + this.width;
this.bottom = this.top + this.height;
this.equals = function (that) {
return this.left === that.left && this.top === that.top && this.width === that.width && this.height === that.height;
};
this.area = function () {
return this.width * this.height;
};
this.intersection = function (rect) {
var left = Math.max(this.left, rect.left),
right = Math.min(this.right, rect.right),
top = Math.max(this.top, rect.top),
bottom = Math.min(this.bottom, rect.bottom),
width = right - left,
height = bottom - top;
return (width >= 0 && height >= 0) ? new Rect(left, top, width, height) : undefined;
};
this.envelope = function (rect) {
var left = Math.min(this.left, rect.left),
right = Math.max(this.right, rect.right),
top = Math.min(this.top, rect.top),
bottom = Math.max(this.bottom, rect.bottom),
width = right - left,
height = bottom - top;
return new Rect(left, top, width, height);
};
this.bind = function (callback) {
if (!fracsData) {
fracsData = new FracsData(this);
$(window).bind("scroll resize", fracsData.check);
}
fracsData.bind(callback);
};
this.unbind = function (callback) {
if (fracsData) {
fracsData.unbind(callback);
if (fracsData.size() === 0) {
$(window).unbind("scroll resize", fracsData.check);
fracsData = undefined;
}
}
};
this.check = function () {
if (fracsData) {
fracsData.check();
}
};
this.fracs = function () {
$.fracs.fracs(this);
};
};
var FracsResult = function (rectDocument, rectElement, rectViewport, visible, viewport, possible) {
/*jslint confusion: true */
if (!rectDocument || !rectElement || !rectViewport || !visible || !viewport || !possible) {
this.rects = undefined;
this.visible = 0;
this.viewport = 0;
this.possible = 0;
} else {
this.rects = {
document: rectDocument,
element: rectElement,
viewport: rectViewport
};
this.visible = visible;
this.viewport = viewport;
this.possible = possible;
}
this.equals = function (that) {
return this.fracsEqual(that) && this.rectsEqual(that);
};
this.fracsEqual = function (that) {
return this.visible === that.visible && this.viewport === that.viewport && this.possible === that.possible;
};
this.rectsEqual = function (that) {
if (!this.rects || !that.rects) {
return this.rects === that.rects;
}
return this.rects.document.equals(that.rects.document)
&& this.rects.element.equals(that.rects.element)
&& this.rects.viewport.equals(that.rects.viewport);
};
};
var ScrollState = function () {
var document = $.fracs.document(),
viewport = $.fracs.viewport(),
width = document.width - viewport.width,
height = document.height - viewport.height;
this.width = width <= 0 ? undefined : viewport.left / width;
this.height = height <= 0 ? undefined : viewport.top / height;
this.left = viewport.left;
this.top = viewport.top;
this.right = document.right - viewport.right;
this.bottom = document.bottom - viewport.bottom;
this.equals = function (that) {
return this.width === that.width && this.height === that.height
&& this.left === that.left && this.top === that.top
&& this.right === that.right && this.bottom === that.bottom;
};
};
var ScrollStateTracker = function () {
var prevState,
callbacks = [],
check = function () {
var state = new ScrollState();
if (!prevState || !prevState.equals(state)) {
$.each(callbacks, function (idx, callback) {
callback.call(window, state, prevState);
});
prevState = state;
}
};
$(window).bind("resize scroll load", check);
this.bind = function (callback) {
callbacks.push(callback);
};
};
// @beta
var FracsElement = function (htmlElement, fracs) {
this.element = htmlElement;
this.fracs = fracs;
this.update = function () {
var fracs = $.fracs.fracs(this.element),
changed = !this.fracs || !this.fracs.equals(fracs);
this.fracs = fracs;
return changed;
};
};
// @beta
var FracsGroup = function (htmlElements, property, callback) {
var THIS = this,
targets = [],
prevBest = null;
$.each(htmlElements, function (idx, element) {
if (element instanceof HTMLElement) {
targets.push(new FracsElement(element));
}
});
this.check = function () {
var best,
viewport = $.fracs.viewport();
$.each(targets, function (idx, target) {
target.update();
if (!best || target.fracs[property] > best.fracs[property]) {
best = target;
}
});
if (best && best.fracs[property] === 0) {
best = null;
}
if (prevBest !== best) {
callback.call(THIS, best, prevBest);
prevBest = best;
}
};
};
var $document = $(document),
$window = $(window),
$htmlBody = $("html,body"),
scrollStateTracker,
dataNs = "fracs",
statics = {
document: function () {
/*jslint confusion: true */
return new Rect(0, 0, $document.width(), $document.height());
},
viewport: function () {
/*jslint confusion: true */
return new Rect($window.scrollLeft(), $window.scrollTop(), $window.width(), $window.height());
},
rect: function (htmlElement) {
var $target = $(htmlElement),
offset = $target.offset();
if (!$target.is(":visible")) {
return new Rect(0, 0, 0, 0);
}
return new Rect(offset.left, offset.top, $target.outerWidth(), $target.outerHeight());
},
fracs: function (rect, viewport) {
var intersection, intersectionElementSpace, intersectionViewportSpace, intersectionArea, possibleArea;
rect = rect instanceof HTMLElement ? statics.rect(rect) : rect;
viewport = viewport || statics.viewport();
intersection = rect.intersection(viewport);
if (!intersection) {
return new FracsResult();
}
intersectionElementSpace = new Rect(intersection.left - rect.left, intersection.top - rect.top, intersection.width, intersection.height);
intersectionViewportSpace = new Rect(intersection.left - viewport.left, intersection.top - viewport.top, intersection.width, intersection.height);
intersectionArea = intersection.area();
possibleArea = Math.min(rect.width, viewport.width) * Math.min(rect.height, viewport.height);
return new FracsResult(
intersection,
intersectionElementSpace,
intersectionViewportSpace,
intersectionArea / rect.area(),
intersectionArea / viewport.area(),
intersectionArea / possibleArea
);
},
round: function (value, decs) {
if (isNaN(decs) || decs <= 0) {
return Math.round(value);
}
return Math.round(value * Math.pow(10, decs)) / Math.pow(10, decs);
},
scrollTo: function (left, top, duration) {
duration = isNaN(duration) ? 1000 : duration;
$htmlBody.stop(true).animate({ scrollLeft: left, scrollTop: top }, duration);
},
scroll: function (left, top, duration) {
duration = isNaN(duration) ? 1000 : duration;
$htmlBody.stop(true).animate({ scrollLeft: $window.scrollLeft() + left, scrollTop: $window.scrollTop() + top }, duration);
},
scrollState: function (callback) {
if (callback instanceof Function) {
scrollStateTracker = scrollStateTracker || new ScrollStateTracker();
scrollStateTracker.bind(callback);
} else {
return new ScrollState();
}
}
},
methods = {
bind: function (callback) {
return this.each(function () {
var $this = $(this),
data = $this.data(dataNs);
if (!data) {
data = new FracsData(this);
$this.data(dataNs, data);
$window.bind("scroll resize", data.check);
}
data.bind(callback);
});
},
unbind: function (callback) {
return this.each(function () {
var $this = $(this),
data = $this.data(dataNs);
if (data) {
data.unbind(callback);
if (data.size() === 0) {
$this.removeData(dataNs);
$window.unbind("scroll resize", data.check);
}
}
});
},
check: function () {
return this.each(function () {
var data = $(this).data(dataNs);
if (data) {
data.check();
}
});
},
fracs: function () {
return statics.fracs(statics.rect(this.get(0)), statics.viewport());
},
rect: function () {
return statics.rect(this.get(0));
},
max: function (property, callback) {
if (callback instanceof Function) {
var data = new FracsGroup(this, property, callback);
$window.bind("scroll resize", data.check);
data.check();
return this;
} else {
var obj, elements, maxValue;
if ($.inArray(property, [ "possible", "visible", "viewport" ]) >= 0) {
obj = "fracs";
} else if ($.inArray(property, [ "width", "height", "left", "right", "top", "bottom" ]) >= 0) {
obj = "rect";
} else {
return this;
}
this.each(function () {
var fracs = statics[obj](this);
if (!maxValue || fracs[property] > maxValue) {
elements = [ this ];
maxValue = fracs[property];
} else if (fracs[property] === maxValue) {
elements.push(this);
}
});
return $(elements);
}
},
min: function (property) {
var obj, elements, minValue;
if ($.inArray(property, [ "possible", "visible", "viewport" ]) >= 0) {
obj = "fracs";
} else if ($.inArray(property, [ "width", "height", "left", "right", "top", "bottom" ]) >= 0) {
obj = "rect";
} else {
return this;
}
this.each(function () {
var fracs = statics[obj](this);
if (!minValue || fracs[property] < minValue) {
elements = [ this ];
minValue = fracs[property];
} else if (fracs[property] === minValue) {
elements.push(this);
}
});
return $(elements);
},
envelope: function () {
var envelope, rect;
this.each(function () {
rect = statics.rect(this);
envelope = !envelope ? rect : envelope.envelope(rect);
});
return envelope;
},
scrollTo: function (paddingLeft, paddingTop, duration) {
var rect;
paddingLeft = paddingLeft || 0;
paddingTop = paddingTop || 0;
rect = statics.rect(this.get(0));
statics.scrollTo(rect.left - paddingLeft, rect.top - paddingTop, duration);
return this;
},
softLink: function (paddingLeft, paddingTop, duration) {
return this.filter("a[href^=#]").each(function () {
var $a = $(this),
href = $a.attr("href");
$a.click(function () {
$(href).fracs("scrollTo", paddingLeft, paddingTop, duration);
});
});
}
},
defaultStatic = function () {
return "fracs";
},
defaultMethod = function () {
if (arguments.length === 0) {
return "fracs";
} else if (arguments[0] instanceof Function) {
return "bind";
}
};
$.ModPlug.plugin("fracs", {
statics: statics,
methods: methods,
defaultStatic: defaultStatic,
defaultMethod: defaultMethod
});
}(jQuery));
/*
* jQuery.fracs - Outline API
*/
(function ($) {
"use strict";
/*globals jQuery */
/*jslint browser: true, vars: true */
var Outline = function (canvas, options) {
if (!(canvas instanceof HTMLElement && canvas.nodeName.toLowerCase() === "canvas")) {
return undefined;
}
var defaults = {
crop: false,
duration: 0,
focusWidth: 0.5,
focusHeight: 0.5,
autoFocus: true,
styles: [ {
selector: "header,footer,section,article",
fillStyle: "rgb(230,230,230)"
}, {
selector: "h1",
fillStyle: "rgb(240,140,060)"
}, {
selector: "h2",
fillStyle: "rgb(200,100,100)"
}, {
selector: "h3",
fillStyle: "rgb(100,200,100)"
}, {
selector: "h4",
fillStyle: "rgb(100,100,200)"
} ],
viewportStyle: {
fillStyle: "rgba(228,77,38,0.3)"
},
viewportDragStyle: {
fillStyle: "rgba(228,77,38,0.6)"
},
invertViewport: false
},
settings = $.extend({}, defaults, options),
$window = $(window),
$htmlBody = $("html,body"),
$canvas = $(canvas),
width = $canvas.attr("width"),
height = $canvas.attr("height"),
context = canvas.getContext("2d"),
docRect,
vpRect,
scale,
drag = false,
focusWidth,
focusHeight,
scroll = function (event) {
var r, x, y;
r = $canvas.fracs("rect");
x = event.pageX - r.left;
y = event.pageY - r.top;
$.fracs.scrollTo(x / scale - vpRect.width * focusWidth, y / scale - vpRect.height * focusHeight, settings.duration);
},
drawRect = function (context, rect, strokeWidth, strokeStyle, fillStyle, invert) {
if (strokeWidth !== undefined && scale) {
strokeWidth = strokeWidth > 0.2 / scale ? strokeWidth : 0.2 / scale;
}
if (strokeStyle || fillStyle) {
if (invert !== true) {
context.beginPath();
context.rect(rect.left, rect.top, rect.width, rect.height);
if (fillStyle) {
context.fillStyle = fillStyle;
context.fill();
}
if (strokeStyle) {
context.lineWidth = strokeWidth;
context.strokeStyle = strokeStyle;
context.stroke();
}
} else {
if (fillStyle) {
context.beginPath();
context.rect(0, 0, docRect.width, rect.top);
context.rect(0, rect.top, rect.left, rect.height);
context.rect(rect.right, rect.top, docRect.right - rect.right, rect.height);
context.rect(0, rect.bottom, docRect.width, docRect.bottom - rect.bottom);
context.fillStyle = fillStyle;
context.fill();
}
if (strokeStyle) {
context.beginPath();
context.rect(rect.left, rect.top, rect.width, rect.height);
context.lineWidth = strokeWidth;
context.strokeStyle = strokeStyle;
context.stroke();
}
}
}
},
drawElement = function (context, htmlElement, strokeWidth, strokeStyle, fillStyle) {
var $element = $(htmlElement),
rect = $element.fracs("rect");
if ($element.css("visibility") === "hidden") {
return;
}
strokeWidth = strokeWidth === "auto" ? $element.css("border-top-width") : strokeWidth;
strokeStyle = strokeStyle === "auto" ? $element.css("border-top-color") : strokeStyle;
fillStyle = fillStyle === "auto" ? $element.css("background-color") : fillStyle;
drawRect(context, rect, strokeWidth, strokeStyle, fillStyle);
},
drawViewport = function () {
var strokeWidth, strokeStyle, fillStyle;
if (drag && settings.viewportDragStyle) {
strokeWidth = settings.viewportDragStyle.storkeWidth;
strokeStyle = settings.viewportDragStyle.strokeStyle;
fillStyle = settings.viewportDragStyle.fillStyle;
} else {
strokeWidth = settings.viewportStyle.storkeWidth;
strokeStyle = settings.viewportStyle.strokeStyle;
fillStyle = settings.viewportStyle.fillStyle;
}
drawRect(context, vpRect, strokeWidth, strokeStyle, fillStyle, settings.invertViewport);
},
applyStyles = function (context) {
$.each(settings.styles, function (idx, style) {
$(style.selector).each(function () {
drawElement(context, this, style.strokeWidth, style.strokeStyle, style.fillStyle);
});
});
},
draw = function () {
/*jslint confusion: true */
var scaleX, scaleY;
docRect = $.fracs.document();
vpRect = $.fracs.viewport();
scaleX = width / docRect.width;
scaleY = height / docRect.height;
scale = scaleX < scaleY ? scaleX : scaleY;
if (settings.crop) {
$canvas.attr("width", docRect.width * scale).attr("height", docRect.height * scale);
}
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.scale(scale, scale);
applyStyles(context);
drawViewport();
context.scale(1 / scale, 1 / scale);
},
init = function () {
$canvas
.css("cursor", "pointer")
.mousedown(function (event) {
var r;
event.preventDefault();
drag = true;
if (settings.autoFocus) {
r = $canvas.fracs("rect");
focusWidth = (((event.pageX - r.left) / scale) - vpRect.left) / vpRect.width;
focusHeight = (((event.pageY - r.top) / scale) - vpRect.top) / vpRect.height;
}
if (!settings.autoFocus || focusWidth < 0 || focusWidth > 1 || focusHeight < 0 || focusHeight > 1) {
focusWidth = settings.focusWidth;
focusHeight = settings.focusHeight;
}
scroll(event);
$canvas.css("cursor", "crosshair").addClass("dragOn");
$htmlBody.css("cursor", "crosshair");
$window
.bind("mousemove", scroll)
.one("mouseup", function (event) {
event.preventDefault();
$canvas.css("cursor", "pointer").removeClass("dragOn");
$htmlBody.css("cursor", "auto");
$window.unbind("mousemove", scroll);
drag = false;
draw();
});
});
canvas.onselectstart = function () {
return false;
};
$window.bind("load resize scroll", draw);
draw();
};
init();
this.draw = draw;
};
var dataNs = "outline",
methods = {
outline: function (options) {
return this.each(function () {
var outline;
if (options === "redraw") {
outline = $(this).data(dataNs);
if (outline) {
outline.draw();
}
} else {
outline = new Outline(this, options);
if (outline) {
$(this).data(dataNs, outline);
}
}
});
}
};
$.ModPlug.module("fracs", {
methods: methods
});
}(jQuery));

View File

@@ -1,31 +0,0 @@
// v2.2
(function($){$.toJSON=function(o)
{if(typeof(JSON)=='object'&&JSON.stringify)
return JSON.stringify(o);var type=typeof(o);if(o===null)
return"null";if(type=="undefined")
return undefined;if(type=="number"||type=="boolean")
return o+"";if(type=="string")
return $.quoteString(o);if(type=='object')
{if(typeof o.toJSON=="function")
return $.toJSON(o.toJSON());if(o.constructor===Date)
{var month=o.getUTCMonth()+1;if(month<10)month='0'+month;var day=o.getUTCDate();if(day<10)day='0'+day;var year=o.getUTCFullYear();var hours=o.getUTCHours();if(hours<10)hours='0'+hours;var minutes=o.getUTCMinutes();if(minutes<10)minutes='0'+minutes;var seconds=o.getUTCSeconds();if(seconds<10)seconds='0'+seconds;var milli=o.getUTCMilliseconds();if(milli<100)milli='0'+milli;if(milli<10)milli='0'+milli;return'"'+year+'-'+month+'-'+day+'T'+
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
if(o.constructor===Array)
{var ret=[];for(var i=0;i<o.length;i++)
ret.push($.toJSON(o[i])||"null");return"["+ret.join(",")+"]";}
var pairs=[];for(var k in o){var name;var type=typeof k;if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;if(typeof o[k]=="function")
continue;var val=$.toJSON(o[k]);pairs.push(name+":"+val);}
return"{"+pairs.join(", ")+"}";}};$.evalJSON=function(src)
{if(typeof(JSON)=='object'&&JSON.parse)
return JSON.parse(src);return eval("("+src+")");};$.secureEvalJSON=function(src)
{if(typeof(JSON)=='object'&&JSON.parse)
return JSON.parse(src);var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};$.quoteString=function(string)
{if(string.match(_escapeable))
{return'"'+string.replace(_escapeable,function(a)
{var c=_meta[a];if(typeof c==='string')return c;c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};var _escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var _meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};})(jQuery);

View File

@@ -0,0 +1,147 @@
(function ($) {
var init = function (htmlElement) {
var $element = $(htmlElement),
$scrollbar, $drag, $wrapper, $content, mouseOffsetY, updateId,
update, scroll;
if (!$element.css("position") || $element.css("position") === "static") {
$element.css("position", "relative");
}
$scrollbar = $("<div class='scrollbar' />");
$drag = $("<div class='drag' />").appendTo($scrollbar);
$element
.wrapInner("<div class='wrapper'><div class='content' /></div>")
.append($scrollbar);
$wrapper = $element.find("> .wrapper");
$content = $wrapper.find("> .content");
mouseOffsetY = 0;
update = function (repeat) {
var visibleHeight, contentHeight, scrollTop, scrollTopFrac, visVertFrac;
if (updateId && !repeat) {
clearInterval(updateId);
updateId = undefined;
} else if (!updateId && repeat) {
updateId = setInterval(function() { update(true); }, 50);
}
$wrapper.css("height", $element.height());
visibleHeight = $element.height();
contentHeight = $content.outerHeight();
scrollTop = $wrapper.scrollTop();
scrollTopFrac = scrollTop / contentHeight;
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);
}
};
scroll = function (event) {
var clickFrac = (event.pageY - $scrollbar.offset().top - mouseOffsetY) / $scrollbar.height();
$wrapper.scrollTop($content.outerHeight() * clickFrac);
update();
event.preventDefault();
};
$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",
cursor: "pointer"
})
.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.preventDefault();
})
.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,29 @@
(function ($) {
"use strict";
/*global jQuery, window*/
// 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));
}
};
$.timer = (function () {
var start = $.now(),
last = start,
timer = {
log: function (label) {
var now = $.now();
$.log("timer", label, "+" + (now - last), "=" + (now - start));
last = now;
}
};
return timer;
}());
})(jQuery);

View File

@@ -1,411 +1,404 @@
var Path = function (pathCache, folder, tableRow) {
"use strict";
/*global $, h5ai, tree*/
var path,
checkedDecodeUri = function (uri) {
try { return decodeURI(uri); } catch (err) {}
return uri;
},
isEmpty = function () {
return path.content === undefined || $.isEmptyObject(path.content);
},
onClick = function (context) {
h5ai.triggerPathClick(path, context);
},
updateHtml = function () {
path.updateCrumbHtml();
path.updateExtendedHtml();
path.updateTreeHtml();
},
updateCrumbHtml = function () {
var $html, $a;
if (path.html.$crumb && path.html.$crumb.data("status") === path.status) {
return path.html.$crumb;
}
$html = $("<li class='crumb' />")
.data("path", path)
.addClass(path.isFolder ? "folder" : "file");
if (path.status) {
$html.data("status", path.status);
}
$a = $("<a><img src='/h5ai/images/crumb.png' alt='>' />" + path.label + "</a>")
.appendTo($html)
.attr("href", path.absHref)
.click(function() { onClick("crumb"); });
if (path.isDomain) {
$html.addClass("domain");
$a.find("img").attr("src", "/h5ai/images/home.png");
}
if (path.isCurrentFolder) {
$html.addClass("current");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$("<img class='hint' src='/h5ai/images/page.png' alt='not listable' />").appendTo($a);
} else {
$("<span class='hint'>(" + path.status + ")</span>").appendTo($a);
}
}
if (path.html.$crumb) {
path.html.$cpathreplaceWith($html);
}
path.html.$crumb = $html;
return $html;
},
updateExtendedHtml = function () {
var $html, $a, $label;
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);
}
$label = $("<span class='label'>" + path.label + "</span>");
$a = $("<a />")
.attr("href", path.absHref)
.click(function() { onClick("extended"); })
.appendTo($html)
.append($("<span class='icon small'><img src='" + path.icon16 + "' alt='" + path.alt + "' /></span>"))
.append($("<span class='icon big'><img src='" + path.icon48 + "' alt='" + path.alt + "' /></span>"))
.append($label)
.append($("<span class='date'>" + path.date + "</span>"))
.append($("<span class='size'>" + 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 (!h5ai.settings.setParentFolderLabels) {
$label.addClass("l10n-parentDirectory");
}
$html.addClass("parentfolder");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$html.addClass("page");
$a.find(".icon.small img").attr("src", "/h5ai/icons/16x16/folder-page.png");
$a.find(".icon.big img").attr("src", "/h5ai/icons/48x48/folder-page.png");
} else {
$html.addClass("error");
$label.append($("<span class='hint'> " + path.status + " </span>"));
}
}
if (path.html.$extended) {
path.html.$extended.replaceWith($html);
}
path.html.$extended = $html;
return $html;
},
updateTreeHtml = function () {
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() { path.onClick("tree"); })
.appendTo($html)
.append($("<span class='icon'><img src='" + path.icon16 + "' /></span>"))
.append($("<span class='label'>" + path.label + "</span>"));
if (path.isFolder) {
// indicator
if (path.status === undefined || !path.isEmpty()) {
$indicator = $("<span class='indicator'><img src='/h5ai/images/tree.png' /></span>");
if (path.status === undefined) {
$indicator.addClass("unknown");
} else if (path.treeOpen) {
$indicator.addClass("open");
}
$indicator.click(function(event) {
if ($indicator.hasClass("unknown")) {
tree.fetchStatusAndContent(path.absHref, false, function (status, content) {
path.status = status;
path.content = content;
path.treeOpen = true;
$("#tree").get(0).updateScrollbar(true);
path.updateTreeHtml(function() {
$("#tree").get(0).updateScrollbar();
});
});
} else if ($indicator.hasClass("open")) {
path.treeOpen = false;
$indicator.removeClass("open");
$("#tree").get(0).updateScrollbar(true);
$html.find("> ul.content").slideUp(function() {
$("#tree").get(0).updateScrollbar();
});
} else {
path.treeOpen = true;
$indicator.addClass("open");
$("#tree").get(0).updateScrollbar(true);
$html.find("> ul.content").slideDown(function() {
$("#tree").get(0).updateScrollbar();
});
}
});
$html.addClass("initiatedIndicator");
$blank.replaceWith($indicator);
}
// is path the domain?
if (path.isDomain) {
$html.addClass("domain");
$a.find(".icon img").attr("src", "/h5ai/icons/16x16/folder-home.png");
}
// is path the current folder?
if (path.isCurrentFolder) {
$html.addClass("current");
$a.find(".icon img").attr("src", "/h5ai/icons/16x16/folder-open.png");
}
// does it have subfolders?
if (!path.isEmpty()) {
$ul = $("<ul class='content' />").appendTo($html);
for (idx in path.content) {
$("<li />").append(path.content[idx].updateTreeHtml()).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", "/h5ai/icons/16x16/folder-page.png");
$a.append($("<span class='hint'><img src='/h5ai/images/page.png' /></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;
},
init = function () {
var $tds, $img, $a, splits;
path = {
// parentFolder: undefined,
// label: undefined,
// date: undefined,
// size: undefined,
// href: undefined,
// absHref: undefined,
// alt: undefined,
// icon16: undefined,
// icon48: undefined,
// isFolder: undefined,
// isParentFolder: undefined,
// isCurrentFolder: undefined,
// isDomain: undefined,
status: undefined, // undefined, "h5ai" or HTTP response code
content: undefined, // associative array path.absHref -> path
html: {
$crumb: undefined,
$extended: undefined,
$tree: undefined
},
treeOpen: false,
isEmpty: isEmpty,
onClick: onClick,
updateHtml: updateHtml,
updateCrumbHtml: updateCrumbHtml,
updateExtendedHtml: updateExtendedHtml,
updateTreeHtml: updateTreeHtml
};
if (!pathCache.pathEndsWithSlash(folder)) {
folder += "/";
}
if (tableRow) {
$tds = $(tableRow).find("td");
$img = $tds.eq(0).find("img");
$a = $tds.eq(1).find("a");
path.parentFolder = folder;
path.label = $a.text();
path.date = $tds.eq(2).text();
path.size = $tds.eq(3).text();
path.href = $a.attr("href");
path.alt = $img.attr("alt");
path.icon16 = $img.attr("src");
} else {
splits = pathCache.splitPathname(folder);
path.parentFolder = splits[0];
path.label = checkedDecodeUri(splits[1]);
if (path.label === "/") {
path.label = checkedDecodeUri(document.domain) + "/";
}
path.date = "";
path.size = "";
path.href = splits[1];
path.alt = "[DIR]";
path.icon16 = "/h5ai/icons/16x16/folder.png";
}
if (pathCache.pathEndsWithSlash(path.label)) {
path.label = path.label.slice(0, -1);
}
path.icon48 = path.icon16.replace("16x16", "48x48");
path.isFolder = (path.alt === "[DIR]");
path.isParentFolder = (path.isFolder && path.label === "Parent Directory");
path.absHref = path.isParentFolder ? path.href : path.parentFolder + path.href;
path.isCurrentFolder = (path.absHref === document.location.pathname);
path.isDomain = (path.absHref === "/");
if (path.isParentFolder && h5ai.settings.setParentFolderLabels) {
if (path.isDomain) {
path.label = checkedDecodeUri(document.domain);
} else {
path.label = checkedDecodeUri(pathCache.splitPathname(pathCache.splitPathname(path.parentFolder)[0])[1].slice(0, -1));
}
}
};
init();
return path;
};
var PathCache = function () {
"use strict";
/*global $*/
var pathnameRegEx = /^(\/(.*\/)*)([^\/]+\/?)$/;
var pathCache,
cache = {},
rePathnameSplit = /^(\/(.*\/)*)([^\/]+\/?)$/,
rePathEndsWithSlash = /\/$/,
splitPathname = function (pathname) {
this.splitPathname = function ( pathname ) {
if ( pathname === "/" ) {
return [ "", "/" ];
};
var match = pathnameRegEx.exec( pathname );
return [ match[1], match[3] ];
};
var match;
if (pathname === "/") {
return ["", "/"];
}
match = rePathnameSplit.exec(pathname);
return [match[1], match[3]];
},
pathEndsWithSlash = function (pathname) {
this.cache = {};
return rePathEndsWithSlash.test(pathname);
},
getAbsHref = function (folder, tableRow) {
var $a, isParentFolder, href;
this.loadCache = function () {
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;
},
getPath = function (folder, tableRow) {
var json = localStorage.getItem( "h5ai.cache" );
var objs = $.evalJSON( json );
var cache = {};
for ( idx in objs ) {
var obj = objs[idx];
var path = this.objectToPath( obj );
cache[path.absHref] = path;
};
return cache;
};
var absHref = getAbsHref(folder, tableRow),
path = cache[absHref];
if (!path) {
path = new Path(pathCache, folder, tableRow);
if (!path.isParentFolder) {
cache[path.absHref] = path;
}
}
this.storeCache = function () {
return path;
};
var objs = [];
for ( ref in this.cache ) {
var path = this.cache[ref];
if ( path.isFolder ) {
objs.push( this.pathToObject( path ) );
};
};
var json = $.toJSON( objs );
localStorage.setItem( "h5ai.cache", json );
};
this.pathToObject = function ( path ) {
var object = {
r: path.absHref,
s: path.status,
c: [],
o: path.treeOpen
};
if ( path.content !== undefined ) {
for ( ref in path.content ) {
object.c.push( ref );
};
};
return object;
};
this.objectToPath = function ( obj ) {
var path = this.getPathForFolder( obj.r );
path.status = obj.s;
path.content = {};
path.treeOpen = obj.o;
for ( idx in obj.c ) {
var href = obj.c[idx];
path.content[href] = this.getPathForFolder( href );
};
return path;
};
this.getPathForFolder = function ( folder ) {
return this.getCachedPath( new Path( this, folder ) );
};
this.getPathForTableRow = function ( parentFolder, tableRow ) {
return this.getCachedPath( new Path( this, parentFolder, tableRow ) );
};
this.getCachedPath = function ( path ) {
if ( path.isParentFolder ) {
return path;
};
var cachedPath = this.cache[path.absHref];
if ( cachedPath !== undefined ) {
return cachedPath;
};
this.cache[path.absHref] = path;
this.storeCache();
return path;
};
this.cache = this.loadCache();
pathCache = {
splitPathname: splitPathname,
pathEndsWithSlash: pathEndsWithSlash,
getPath: getPath
};
};
var Path = function ( pathCache, folder, tableRow ) {
if ( ! /\/$/.test( folder ) ) {
folder += "/";
};
if ( tableRow !== undefined ) {
var $tds = $( tableRow ).find( "td" );
var $img = $tds.eq( 0 ).find( "img" );
var $a= $tds.eq( 1 ).find( "a" );
this.parentFolder = folder;
this.icon16 = $img.attr( "src" );
this.alt = $img.attr( "alt" );
this.label = $a.text();
this.href = $a.attr("href"); //decodeURI( $a.attr("href") );
this.date = $tds.eq( 2 ).text();
this.size = $tds.eq( 3 ).text();
} else {
var splits = pathCache.splitPathname( folder );
this.parentFolder = splits[0];
this.href = splits[1];
this.label = decodeURI( splits[1] );
this.icon16 = "/h5ai/icons/16x16/folder.png";
this.alt = "[DIR]";
this.date = "";
this.size = "";
if ( this.label === "/" ) {
this.label = decodeURI( document.domain ) + "/";
};
};
if ( /\/$/.test( this.label ) ) {
this.label = this.label.slice( 0, -1 );
};
this.icon48 = this.icon16.replace( "16x16", "48x48" );
this.isFolder = ( this.alt === "[DIR]" );
this.isParentFolder = ( this.isFolder && this.label === "Parent Directory" );
this.absHref = this.isParentFolder ? this.href : this.parentFolder + this.href;
this.isCurrentFolder = ( this.absHref === document.location.pathname );
this.isDomain = ( this.absHref === "/" );
if ( this.isParentFolder && h5ai.config.setParentFolderLabels ) {
if ( this.isDomain ) {
this.label = decodeURI( document.domain );
} else {
this.label = decodeURI( pathCache.splitPathname( pathCache.splitPathname( this.parentFolder )[0] )[1].slice( 0, -1 ) );
};
};
this.status = undefined; // undefined, "h5ai" or HTTP response code
this.content = undefined; // associative array path.absHref -> path
this.html = {
$crumb: undefined,
$extended: undefined,
$tree: undefined
};
this.treeOpen = false;
this.isEmpty = function() {
return this.content === undefined || $.isEmptyObject( this.content );
};
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();
this.updateExtendedHtml();
this.updateTreeHtml();
};
this.updateCrumbHtml = function () {
var $html = $( "<li class='crumb' />" ).data( "path", this );
try {
$html.addClass( this.isFolder ? "folder" : "file" );
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 ) {
$html.addClass( "domain" );
$a.find( "img" ).attr( "src", "/h5ai/images/home.png" );
};
if ( this.isCurrentFolder ) {
$html.addClass( "current" );
};
if ( !isNaN( this.status ) ) {
if ( this.status === 200 ) {
$( "<img class='hint' src='/h5ai/images/page.png' alt='not listable' />" ).appendTo( $a );
} else {
$( "<span class='hint'>(" + this.status + ")</span>" ).appendTo( $a );
};
};
} catch( err ) {
$( "<span class='fail'>failed</span>" ).appendTo( $html );
};
if ( this.html.$crumb !== undefined ) {
this.html.$crumb.replaceWith( $html );
};
this.html.$crumb = $html;
return $html;
};
this.updateExtendedHtml = function () {
var $html = $( "<li class='entry' />" ).data( "path", this );
try {
$html.addClass( this.isFolder ? "folder" : "file" );
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 );
var $label = $( "<span class='label'>" + this.label + "</span>" ).appendTo( $a );
$( "<span class='date'>" + this.date + "</span>" ).appendTo( $a );
$( "<span class='size'>" + this.size + "</span>" ).appendTo( $a );
if ( this.isParentFolder ) {
if ( !h5ai.config.setParentFolderLabels ) {
$label.addClass( "l10n-parentDirectory" );
};
$html.addClass( "parentfolder" );
};
if ( !isNaN( this.status ) ) {
if ( this.status === 200 ) {
$html.addClass( "page" );
$a.find( ".icon.small img" ).attr( "src", "/h5ai/icons/16x16/folder-page.png" );
$a.find( ".icon.big img" ).attr( "src", "/h5ai/icons/48x48/folder-page.png" );
} else {
$html.addClass( "error" );
$label.append( $( "<span class='hint'> " + this.status + " </span>" ) );
};
};
} catch( err ) {
$( "<span class='fail'>failed</span>" ).appendTo( $html );
};
if ( this.html.$extended !== undefined ) {
this.html.$extended.replaceWith( $html );
};
this.html.$extended = $html;
return $html;
};
this.updateTreeHtml = function () {
var $html = $( "<div class='entry' />" ).data( "path", this );
var $blank = $( "<span class='blank' />" ).appendTo( $html );
try {
$html.addClass( this.isFolder ? "folder" : "file" );
var $a = $( "<a />" )
.appendTo( $html )
.append( $( "<span class='icon'><img src='" + this.icon16 + "' /></span>" ) )
.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
if ( this.status === undefined || !this.isEmpty() ) {
var $indicator = $( "<span class='indicator'><img src='/h5ai/images/tree.png' /></span>" );
if ( this.status === undefined ) {
$indicator.addClass( "unknown" );
} else if ( this.treeOpen ) {
$indicator.addClass( "open" );
};
$indicator.click( $.proxy( function( event ) {
if ( $indicator.hasClass( "unknown" ) ) {
tree.fetchStatusAndContent( this.absHref, false, $.proxy( function ( status, content ) {
this.status = status;
this.content = content;
this.treeOpen = true;
$( "#tree" ).get( 0 ).updateScrollbar( true );
this.updateTreeHtml( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
} );
}, this ) );
} else if ( $indicator.hasClass( "open" ) ) {
this.treeOpen = false;
$indicator.removeClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$html.find( "> ul.content" ).slideUp( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
} );
} else {
this.treeOpen = true;
$indicator.addClass( "open" );
$( "#tree" ).get( 0 ).updateScrollbar( true );
$html.find( "> ul.content" ).slideDown( function() {
$( "#tree" ).get( 0 ).updateScrollbar();
} );
};
}, this ) );
$blank.replaceWith( $indicator );
};
// is this the domain?
if ( this.isDomain ) {
$html.addClass( "domain" );
$a.find( ".icon img" ).attr( "src", "/h5ai/icons/16x16/folder-home.png" );
};
// is this the current folder?
if ( this.isCurrentFolder ) {
$html.addClass( "current" );
$a.find( ".icon img" ).attr( "src", "/h5ai/icons/16x16/folder-open.png" );
};
// does it have subfolders?
if ( !this.isEmpty() ) {
var $ul = $( "<ul class='content' />" ).appendTo( $html );
for ( idx in this.content ) {
$( "<li />" ).append( this.content[idx].updateTreeHtml() ).appendTo( $ul );
};
if ( this.status === undefined || !this.treeOpen ) {
$ul.hide();
};
};
// reflect folder status
if ( !isNaN( this.status ) ) {
if ( this.status === 200 ) {
$a.find( ".icon img" ).attr( "src", "/h5ai/icons/16x16/folder-page.png" );
$a.append( $( "<span class='hint'><img src='/h5ai/images/page.png' /></span>" ) );
} else {
$html.addClass( "error" );
$a.append( $( "<span class='hint'>" + this.status + "</span>" ) );
};
};
};
} catch( err ) {
$( "<span class='fail'>failed</span>" ).appendTo( $html );
};
if ( this.html.$tree !== undefined ) {
this.html.$tree.replaceWith( $html );
};
this.html.$tree = $html;
return $html;
};
return pathCache;
};

View File

@@ -1,287 +1,147 @@
var Tree = function ( pathCache, h5ai ) {
var Tree = function (pathCache, h5ai) {
"use strict";
/*global $*/
var THIS = this;
var contentTypeRegEx = /^text\/html;h5ai=/;
var contentTypeRegEx = /^text\/html;h5ai=/,
pathnameStatusCache = {},
fetchStatus = function (pathname, callback) {
this.init = function () {
if (h5ai.settings.folderStatus[pathname]) {
callback(h5ai.settings.folderStatus[pathname]);
return;
} else if (pathnameStatusCache[pathname]) {
callback(pathnameStatusCache[pathname]);
return;
}
if ( h5ai.config.showTree ) {
this.updatePaths();
this.populateTree();
};
};
$.ajax({
url: pathname,
type: "HEAD",
complete: function (xhr) {
var status = xhr.status;
this.updatePath = function ( path ) {
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 ) {
this.fetchStatus( path.absHref, function ( status ) {
if ( status !== "h5ai" ) {
path.status = status;
};
path.updateHtml();
} );
};
};
if (path.isFolder && !path.isParentFolder && path.status === undefined) {
fetchStatus(path.absHref, function (status) {
if (status !== "h5ai") {
path.status = status;
}
path.updateHtml();
h5ai.linkHoverStates();
});
}
},
updatePaths = function () {
this.updatePaths = function () {
var ref;
for ( var ref in pathCache.cache ) {
this.updatePath( pathCache.cache[ref] );
};
};
for (ref in pathCache.cache) {
updatePath(pathCache.cache[ref]);
}
},
fetchStatusAndContent = function (pathname, includeParent, callback) {
fetchStatus(pathname, function (status) {
this.populateTree = function () {
if (status !== "h5ai") {
callback(status, {});
return;
}
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() } );
};
};
};
$.ajax({
url: pathname,
type: "GET",
dataType: "html",
error: function (xhr) {
$tree.hover( function () { shiftTree( true ); }, function () { shiftTree(); } );
$( window ).resize( function() {
shiftTree();
} );
callback(xhr.status, {}); // since it was checked before this should never happen
},
success: function (html, status, xhr) {
this.fetchTree( document.location.pathname, function( path ) {
$tree.append( path.updateTreeHtml() );
$tree.show();
scrollpanel( $tree );
shiftTree( false, true );
} );
};
var content = {};
if (!contentTypeRegEx.test(xhr.getResponseHeader("Content-Type"))) {
callback(xhr.status, {}); // since it was checked before this should never happen
return;
}
this.fetchTree = function ( pathname, callback, childPath ) {
$(html).find("#table td").closest("tr").each(function () {
this.fetchPath( pathname, $.proxy( function ( path ) {
path.treeOpen = true;
if ( childPath !== undefined ) {
path.content[ childPath.absHref ] = childPath;
};
var path = pathCache.getPath(pathname, this);
var parent = pathCache.splitPathname( pathname )[0];
if ( parent === "" ) {
callback( path );
} else {
this.fetchTree( parent, callback, path );
};
}, this ) );
};
if (path.isFolder && (!path.isParentFolder || includeParent)) {
content[path.absHref] = path;
updatePath(path);
}
});
callback("h5ai", content);
}
});
});
},
fetchPath = function (pathname, callback) {
fetchStatusAndContent(pathname, false, function (status, content) {
this.fetchPath = function ( pathname, callback ) {
var path = pathCache.getPath(pathname);
this.fetchStatusAndContent( pathname, false, function ( status, content ) {
var path = pathCache.getPathForFolder( pathname );
path.status = status;
path.content = content;
callback( path );
} );
};
path.status = status;
path.content = content;
callback(path);
});
},
fetchTree = function (pathname, callback, childPath) {
fetchPath(pathname, function (path) {
this.fetchStatusAndContent = function ( pathname, includeParent, callback ) {
var parent = pathCache.splitPathname(pathname)[0];
this.fetchStatus( pathname, function ( status ) {
path.treeOpen = true;
if (childPath) {
path.content[childPath.absHref] = childPath;
}
if (parent === "") {
callback(path);
} else {
fetchTree(parent, callback, path);
}
});
},
populateTree = function () {
if ( status !== "h5ai" ) {
callback( status, {} );
return;
};
fetchTree(document.location.pathname, function (path) {
$("#tree")
.append(path.updateTreeHtml())
.scrollpanel()
.show();
h5ai.shiftTree(false, true);
h5ai.linkHoverStates();
setTimeout(function () { $("#tree").get(0).updateScrollbar(); }, 1);
});
},
init = function () {
$.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 ) {
if ( !contentTypeRegEx.test( xhr.getResponseHeader( "Content-Type" ) ) ) {
callback( xhr.status, {} ); // since it was checked before this should never happen
return;
};
var content = {};
$( html ).find( "#table td" ).closest( "tr" ).each( function () {
var path = pathCache.getPathForTableRow( pathname, this );
if ( path.isFolder && ( !path.isParentFolder || includeParent ) ) {
content[path.absHref] = path;
THIS.updatePath( path );
};
} );
callback( "h5ai", content );
}
} );
} );
};
var pathnameStatusCache = {};
this.fetchStatus = function ( pathname, callback ) {
if ( h5ai.config.folderStatus[ pathname ] !== undefined ) {
callback( h5ai.config.folderStatus[ pathname ] );
return;
} else if ( pathnameStatusCache[ pathname ] !== undefined ) {
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 );
}
} );
};
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();
};
if (h5ai.settings.showTree) {
updatePaths();
populateTree();
}
},
tree = {
fetchStatusAndContent: fetchStatusAndContent,
init: init
};
return tree;
};

30
src/h5ai/js/main-js.js Normal file
View File

@@ -0,0 +1,30 @@
(function($) {
"use strict";
/*global jQuery, h5aiOptions, h5aiLangs*/
// @include "inc/jquery.mousewheel.min.js"
// @include "inc/jquery.scrollpanel.js"
// @include "inc/jquery.utils.js"
// @include "inc/jquery.fracs.js"
// @include "inc/path.js"
// @include "inc/h5ai.js"
// @include "inc/extended.js"
// @include "inc/tree.js"
var pathCache = new PathCache(),
h5ai = new H5ai(h5aiOptions, h5aiLangs),
extended = new Extended(pathCache, h5ai),
tree = new Tree(pathCache, h5ai);
$.h5ai = {
click: $.proxy(h5ai.pathClick, h5ai)
};
$(function () {
extended.init();
tree.init();
h5ai.init();
});
})(jQuery);

24
src/h5ai/js/main-php.js Normal file
View File

@@ -0,0 +1,24 @@
(function($) {
"use strict";
/*global jQuery, h5aiOptions, h5aiLangs*/
// @include "inc/jquery.mousewheel.min.js"
// @include "inc/jquery.scrollpanel.js"
// @include "inc/jquery.utils.js"
// @include "inc/jquery.fracs.js"
// @include "inc/h5ai.js"
var h5ai = new H5ai(h5aiOptions, h5aiLangs);
$.h5ai = {
click: $.proxy(h5ai.pathClick, h5ai)
};
$(function () {
h5ai.init();
$("#tree").scrollpanel();
h5ai.shiftTree(false, true);
});
})(jQuery);

View File

@@ -1,43 +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"
/*******************************
* create
*******************************/
var pathCache = new 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.storeCache();
} );
/////////////////////////////////////////////////////
} );
} )( jQuery );

View File

@@ -1,153 +1,339 @@
/*
* h5ai %BUILD_VERSION%
* Options and localization
* Options and localization
*/
h5aiOptions = {
/*
* An array of view modes the user may choose from. Currently there
* are two possible values: "details" and "icons". The first value
* indicates the default view mode. If only one value is given the
* 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.
*/
viewmodes: [ "details", "icons" ],
/*
* An array of view modes the user may choose from. Currently there
* are two possible values: "details" and "icons". The first value
* indicates the default view mode. If only one value is given the
* 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.
*/
"viewmodes": ["details", "icons"],
/*
* 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.
*/
showTree: true,
/*
* Default sort order. Valid values for column are "name", "date" and
* "size".
* If you are using the JavaScript version please make sure to change
* IndexOrderDefault in js.htaccess as well.
*/
"sortorder": {
"column": "name",
"ascending": 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: {
/*
* for example:
* "/some/folder/": 200
*/
},
/*
* 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.
*/
"showTree": true,
/*
* 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.
*/
lang: undefined,
/*
* Slide tree bar into viewport if there is enough space, boolean.
*/
"slideTree": true,
/*
* 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
/*
* 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": null,
/*
* 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,
/*
* 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",
/*
* IMPORTANT: PHP implementation doesn't care about Apache's
* ignores, so you have to specify this here.
*
* 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": ["/^\\./"],
/*
* Only used in PHP implementation.
* Show thumbnails in Icons view.
*/
"showThumbs": true,
/*
* Enable zipped download of selected entries. Requieres
* PHP on the server.
*/
"zippedDownload": true
};
/*
* 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"
},
"en": {
"lang": "english",
"details": "details",
"icons": "icons",
"name": "Name",
"lastModified": "Last modified",
"size": "Size",
"parentDirectory": "Parent Directory",
"empty": "empty",
"folders": "folders",
"files": "files",
"download": "download"
},
"de": {
viewDetails: "Details",
viewIcons: "Icons",
columnName: "Name",
columnLastModified: "Geändert",
columnSize: "Größe",
footerUsing: "nutzt",
parentDirectory: "Übergeordnetes Verzeichnis",
empty: "leer"
},
"fr": {
viewDetails: "détails",
viewIcons: "icônes",
columnName: "Nom",
columnLastModified: "Dernière modification",
columnSize: "Taille",
footerUsing: "utilise",
parentDirectory: "Dossier parent",
empty: "vide"
},
"de": {
"lang": "deutsch",
"details": "Details",
"icons": "Icons",
"name": "Name",
"lastModified": "Geändert",
"size": "Größe",
"parentDirectory": "Übergeordnetes Verzeichnis",
"empty": "leer",
"folders": "Ordner",
"files": "Dateien",
"download": "Download"
},
"nl": {
viewDetails: "details",
viewIcons: "iconen",
columnName: "Naam",
columnLastModified: "Laatste wijziging",
columnSize: "Grootte",
footerUsing: "gebruikt",
parentDirectory: "Bovenliggende map",
empty: "lege"
},
"fr": {
"lang": "français",
"details": "détails",
"icons": "icônes",
"name": "Nom",
"lastModified": "Dernière modification",
"size": "Taille",
"parentDirectory": "Dossier parent",
"empty": "vide",
"folders": "Répertoires",
"files": "Fichiers",
"download": "download"
},
"sv": {
viewDetails: "detaljerad",
viewIcons: "ikoner",
columnName: "Filnamn",
columnLastModified: "Senast ändrad",
columnSize: "Filstorlek",
footerUsing: "använder",
parentDirectory: "Till överordnad mapp",
empty: "tom"
},
"nl": {
"lang": "nederlands",
"details": "details",
"icons": "iconen",
"name": "Naam",
"lastModified": "Laatste wijziging",
"size": "Grootte",
"parentDirectory": "Bovenliggende map",
"empty": "lege",
"folders": "folders",
"files": "files",
"download": "download"
},
"cs": {
viewDetails: "podrobnosti",
viewIcons: "ikony",
columnName: "Název",
columnLastModified: "Upraveno",
columnSize: "Velikost",
footerUsing: "používá",
parentDirectory: "Nadřazený adresář",
empty: "prázdný"
},
"sv": {
"lang": "svenska",
"details": "detaljerad",
"icons": "ikoner",
"name": "Filnamn",
"lastModified": "Senast ändrad",
"size": "Filstorlek",
"parentDirectory": "Till överordnad mapp",
"empty": "tom",
"folders": "folders",
"files": "files",
"download": "download"
},
"sk": {
viewDetails: "podrobnosti",
viewIcons: "ikony",
columnName: "Názov",
columnLastModified: "Upravené",
columnSize: "Velkosť",
footerUsing: "používá",
parentDirectory: "Nadriadený priečinok",
empty: "prázdny"
}
"cs": {
"lang": "čeština",
"details": "podrobnosti",
"icons": "ikony",
"name": "Název",
"lastModified": "Upraveno",
"size": "Velikost",
"parentDirectory": "Nadřazený adresář",
"empty": "prázdný",
"folders": "složek",
"files": "souborů",
"download": "download"
},
"sk": {
"lang": "slovenčina",
"details": "podrobnosti",
"icons": "ikony",
"name": "Názov",
"lastModified": "Upravené",
"size": "Velkosť",
"parentDirectory": "Nadriadený priečinok",
"empty": "prázdny",
"folders": "priečinkov",
"files": "súborov",
"download": "download"
},
"es": {
"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",
"download": "download"
},
"tr": {
"lang": "türkçe",
"details": "detaylar",
"icons": "ikonlar",
"name": "İsim",
"lastModified": "Son Düzenleme",
"size": "Boyut",
"parentDirectory": "Üst Dizin",
"empty": "boş",
"folders": "klasörler",
"files": "dosyalar",
"download": "indir"
},
"pt": {
"lang": "português",
"details": "detalhes",
"icons": "ícones",
"name": "Nome",
"lastModified": "Última modificação",
"size": "Tamanho",
"parentDirectory": "Diretório superior",
"empty": "vazio",
"folders": "pastas",
"files": "arquivos",
"download": "download"
},
"bg": {
"lang": "български",
"details": "детайли",
"icons": "икони",
"name": "Име",
"lastModified": "Последна промяна",
"size": "Размер",
"parentDirectory": "Предходна директория",
"empty": "празно",
"folders": "папки",
"files": "файлове",
"download": "download"
},
"lv": {
"lang": "latviešu",
"details": "detaļas",
"icons": "ikonas",
"name": "Nosaukums",
"lastModified": "Pēdējoreiz modificēts",
"size": "Izmērs",
"parentDirectory": "Vecākdirektorijs",
"empty": "tukšs",
"folders": "mapes",
"files": "faili",
"download": "lejupielādēt"
},
"zh-cn": {
"lang": "简体中文",
"details": "详情",
"icons": "图标",
"name": "文件名",
"lastModified": "上次修改",
"size": "大小",
"parentDirectory": "上层文件夹",
"empty": "空文件夹",
"folders": "文件夹",
"files": "文件",
"download": "download"
},
"pl": {
"lang": "polski",
"details": "szczegóły",
"icons": "ikony",
"name": "Nazwa",
"lastModified": "Ostatnia modyfikacja",
"size": "Rozmiar",
"parentDirectory": "Katalog nadrzędny",
"empty": "pusty",
"folders": "foldery",
"files": "pliki",
"download": "download"
},
"ru": {
"lang": "русский",
"details": "детали",
"icons": "иконки",
"name": "Имя",
"lastModified": "Последние изменения",
"size": "Размер",
"parentDirectory": "Главная директория",
"empty": "пусто",
"folders": "папки",
"files": "файлы",
"download": "download"
},
"it": {
"lang": "italiano",
"details": "dettagli",
"icons": "icone",
"name": "Nome",
"lastModified": "Ultima modifica",
"size": "Dimensione",
"parentDirectory": "Cartella Superiore",
"empty": "vuota",
"folders": "cartelle",
"files": "file",
"download": "download"
}
};

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 . ">") : "";
}
}
?>

223
src/h5ai/php/extended.php Normal file
View File

@@ -0,0 +1,223 @@
<?php
require_once "thumbnail.php";
class Entry {
private $h5ai, $label, $absPath, $absHref, $date, $isFolder, $type, $size, $thumbTypes;
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);
}
$this->thumbTypes = array("bmp", "gif", "ico", "image", "jpg", "png", "tiff");
}
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;
$smallImg = "/h5ai/icons/16x16/" . $this->type . ".png";
$bigImg = "/h5ai/icons/48x48/" . $this->type . ".png";
$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";
$smallImg = "/h5ai/icons/16x16/folder-page.png";
$bigImg = "/h5ai/icons/48x48/folder-page.png";
} else {
$classes .= " error";
$hint = "<span class='hint'> " . $code . " </span>";
}
}
}
if ($this->h5ai->showThumbs() && in_array($this->type, $this->thumbTypes)) {
$classes .= " thumb";
$thumbnail = new Thumbnail($this->absPath, "square", 16, 16);
$thumbnail->create();
$smallImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref();
$thumbnail = new Thumbnail($this->absPath, "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 src='" . $smallImg . "' alt='" . $img . "' /></span>\n";
$html .= "\t\t\t<span class='icon big'><img 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'>" . $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;
}
}
?>

277
src/h5ai/php/h5ai.php Normal file
View File

@@ -0,0 +1,277 @@
<?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"];
$defaultSortOrder = $this->options["options"]["sortorder"];
$this->sortOrder = array(
"column" => array_key_exists("col", $_REQUEST) ? $_REQUEST["col"] : $defaultSortOrder["column"],
"ascending" => array_key_exists("asc", $_REQUEST) ? $_REQUEST["asc"] !== "false" : $defaultSortOrder["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;
}
$absHref = preg_replace("!^" . $this->docRoot . "!", "", $absPath);
$parts = explode("/", $absHref);
$encodedParts = array();
foreach ($parts as $part) {
$encodedParts[] = rawurlencode($part);
}
$endodedAbsHref = implode("/", $encodedParts);
return $this->normalizePath($endodedAbsHref, $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 showThumbs() {
return $this->options["options"]["showThumbs"] === true;
}
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 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);
#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);
?>

202
src/h5ai/php/image.php Normal file
View File

@@ -0,0 +1,202 @@
<?php
class Image {
private $sourceFile;
private $source;
private $width;
private $height;
private $type;
private $dest;
public static function isUsable() {
return GD_VERSION != "GD_VERSION";
}
public function __construct($filename = null) {
$this->sourceFile = null;
$this->source = null;
$this->width = null;
$this->height = null;
$this->type = null;
$this->dest = null;
$this->setSource($filename);
}
public function __destruct() {
$this->releaseSource();
$this->releaseDest();
}
public function setSource($filename) {
$this->releaseSource();
$this->releaseDest();
if (is_null($filename))
return;
$this->sourceFile = $filename;
list($this->width, $this->height, $this->type) = getimagesize($this->sourceFile);
$this->source = imagecreatefromstring(file_get_contents($this->sourceFile));
}
public function showDest() {
if (!is_null($this->dest)) {
header("Content-type: image/jpeg");
imagejpeg($this->dest, null, 100);
}
}
public function saveDest($filename) {
if (!is_null($this->dest)) {
@imagejpeg($this->dest, $filename, 90);
@chmod($filename, 0775);
}
}
public function releaseDest() {
if (!is_null($this->dest)) {
imagedestroy($this->dest);
$this->dest = null;
}
}
public function releaseSource() {
if (!is_null($this->source)) {
imagedestroy($this->source);
$this->sourceFile = null;
$this->source = null;
$this->width = null;
$this->height = null;
$this->type = null;
}
}
public static function showImage($filename) {
$image = file_get_contents($filename);
header("content-type: image");
echo $image;
}
private function magic($destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight, $canWidth = null, $canHeight = null, $color = null) {
if (!is_null($canWidth) && !is_null($canHeight)) {
$this->dest = imagecreatetruecolor($canWidth, $canHeight);
} else {
$this->dest = imagecreatetruecolor($destWidth, $destHeight);
}
if (is_null($color)) {
$color = array(255, 255, 255);
}
$icol = imagecolorallocate($this->dest, $color[0], $color[1], $color[2]);
imagefill($this->dest, 0, 0, $icol);
imagecopyresampled($this->dest, $this->source, $destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight);
}
public function thumb($mode, $width, $height = null, $color = null) {
if ($height === null) {
$height = $width;
}
if ($mode === "square") {
$this->squareThumb($width);
} elseif ($mode === "rational") {
$this->rationalThumb($width, $height);
} elseif ($mode === "center") {
$this->centerThumb($width, $height, $color);
} else {
$this->freeThumb($width, $height);
}
}
public function squareThumb($width) {
$a = min($this->width, $this->height);
$x = intval(($this->width - $a) / 2);
$y = intval(($this->height - $a) / 2);
$this->magic(0, 0, $x, $y, $width, $width, $a, $a);
}
public function rationalThumb($width, $height) {
$r = 1.0 * $this->width / $this->height;
$h = $height;
$w = $r * $h;
if ($w > $width) {
$w = $width;
$h = 1.0 / $r * $w;
}
$w = intval($w);
$h = intval($h);
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
}
public function centerThumb($width, $height, $color = null) {
$r = 1.0 * $this->width / $this->height;
$h = $height;
$w = $r * $h;
if ($w > $width) {
$w = $width;
$h = 1.0 / $r * $w;
}
$w = intval($w);
$h = intval($h);
$x = intval(($width - $w) / 2);
$y = intval(($height - $h) / 2);
$this->magic($x, $y, 0, 0, $w, $h, $this->width, $this->height, $width, $height, $color);
}
public function freeThumb($width, $height) {
$w = intval($width);
$h = intval($height);
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
}
}
?>

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);
?>

26
src/h5ai/php/thumb.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
require_once "thumbnail.php";
$src = $_REQUEST["src"];
$width = $_REQUEST["width"];
$height = $_REQUEST["height"];
$mode = $_REQUEST["mode"];
if (!Thumbnail::isUsable()) {
Image::showImage($src);
exit;
}
$thumbnail = new Thumbnail($src, $mode, $width, $height);
$thumbnail->create(1);
if (file_exists($thumbnail->getPath())) {
Image::showImage($thumbnail->getPath());
} else {
$image = new Image();
$image->setSource($src);
$image->thumb($mode, $width, $height);
$image->showDest();
}
?>

View File

@@ -0,0 +1,56 @@
<?php
require_once "image.php";
class Thumbnail {
private $src, $width, $height, $name, $href, $path;
public static function isUsable() {
return Image::isUsable();
}
public function __construct($src, $mode, $width, $height) {
$this->src = $src;
$this->width = $width;
$this->height = $height;
$this->mode = $mode;
$this->name = sha1("$this->src-$this->width-$this->height-$this->mode");
$this->href = "/h5ai/cache/thumb-" . $this->name . ".jpg";
$this->path = getenv("DOCUMENT_ROOT") . $this->href;
$this->liveHref = "/h5ai/php/thumb.php?src=" . $this->src . "&width=" . $this->width . "&height=" . $this->height . "&mode=" . $this->mode;
}
public function create($force = 0) {
if (
$force === 2
|| ($force === 1 && !file_exists($this->path))
|| (file_exists($this->path) && filemtime($this->src) >= filemtime($this->path))
) {
$image = new Image();
$image->setSource($this->src);
$image->thumb($this->mode, $this->width, $this->height);
$image->saveDest($this->path);
}
}
public function getHref() {
return $this->href;
}
public function getPath() {
return $this->path;
}
public function getLiveHref() {
return $this->liveHref;
}
}
?>

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();
?>

View File

@@ -0,0 +1,28 @@
<?php
if (!array_key_exists("hrefs", $_REQUEST)) {
echo "failed";
exit;
}
require_once "h5ai.php";
require_once "zipit.php";
$h5ai = new H5ai();
$zipit = new ZipIt($h5ai);
$hrefs = explode(":", trim($_REQUEST["hrefs"]));
$zipFile = $zipit->zip($hrefs);
if ($zipFile !== false) {
header("Content-Disposition: attachment; filename=\"h5ai-selection.zip\"");
header("Content-Type: application/force-download");
header("Content-Length: " . filesize($zipFile));
header("Connection: close");
readfile($zipFile);
} else {
echo "sorry, something went wrong while building the zip.";
}
?>

63
src/h5ai/php/zipit.php Normal file
View File

@@ -0,0 +1,63 @@
<?php
class ZipIt {
private $h5ai;
public function __construct($h5ai) {
$this->h5ai = $h5ai;
}
public function zip($hrefs) {
$zipFile = tempnam("/tmp", "h5ai-download");
$zip = new ZipArchive();
if (!$zip->open($zipFile, ZIPARCHIVE::CREATE)) {
return false;
}
foreach ($hrefs as $href) {
$d = dirname($href);
$n = basename($href);
if ($this->h5ai->getHttpCode($this->h5ai->getAbsHref($d)) === "h5ai" && !$this->h5ai->ignoreThisFile($n)) {
$localFile = $this->h5ai->getAbsPath($href);
$file = preg_replace("!^" . $this->h5ai->getDocRoot() . "!", "", $localFile);
if (is_dir($localFile)) {
$this->zipDir($zip, $localFile, $file);
} else {
$this->zipFile($zip, $localFile, $file);
}
}
}
$zip->close();
return $zipFile;
}
private function zipFile($zip, $localFile, $file) {
if (is_readable($localFile)) {
$zip->addFile($localFile, $file);
}
}
private function zipDir($zip, $localDir, $dir) {
if ($this->h5ai->getHttpCode($this->h5ai->getAbsHref($localDir)) === "h5ai") {
$zip->addEmptyDir($dir);
$files = $this->h5ai->readDir($localDir);
foreach ($files as $file) {
$localFile = $localDir . "/" . $file;
$file = $dir . "/" . $file;
if (is_dir($localFile)) {
$this->zipDir($zip, $localFile, $file);
} else {
$this->zipFile($zip, $localFile, $file);
}
}
}
}
}
?>

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

113
src/js.htaccess Normal file
View File

@@ -0,0 +1,113 @@
################################
# %BUILD_NAME% %BUILD_VERSION% (js)
# customized .htaccess
################################
# Options +Indexes
# Options +FollowSymLinks
################################
# h5ai header and footer
################################
HeaderName /h5ai/header.html
ReadmeName /h5ai/footer.html
################################
# hide h5ai folder and config files from index
################################
IndexIgnore h5ai h5ai.header.html h5ai.footer.html
################################
# table options
################################
# syntax for default sort order is: IndexOrderDefault Ascending|Descending Name|Date|Size
IndexOrderDefault Ascending Name
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions Charset=UTF-8
IndexOptions FancyIndexing
IndexOptions HTMLTable
IndexOptions XHTML
IndexOptions SuppressHTMLPreamble
IndexOptions SuppressRules
IndexOptions SuppressDescription
IndexOptions FoldersFirst
IndexOptions IgnoreCase
IndexOptions IconsAreLinks
IndexOptions VersionSort
IndexOptions NameWidth=*
################################
# icon mapping
################################
AddIcon /h5ai/icons/16x16/folder-parent.png ..
AddIcon /h5ai/icons/16x16/folder.png ^^DIRECTORY^^
AddIcon /h5ai/icons/16x16/blank.png ^^BLANKICON^^
AddIcon /h5ai/icons/16x16/readme.png README
AddIcon /h5ai/icons/16x16/copying.png COPYING LICENSE
AddIcon /h5ai/icons/16x16/install.png INSTALL
AddIcon /h5ai/icons/16x16/authors.png AUTHORS
AddIcon /h5ai/icons/16x16/log.png LOG Log log
AddIcon /h5ai/icons/16x16/css.png .less
AddIcon /h5ai/icons/16x16/script.png .conf .ini .sh .shar .csh .ksh .tcl
AddIcon /h5ai/icons/16x16/makefile.png .pom pom.xml build.xml
AddIcon /h5ai/icons/16x16/bin.png .so .o
AddIcon /h5ai/icons/16x16/archive.png .tar.gz .tgz .tar.bz2
AddIcon /h5ai/icons/16x16/zip.png .zip .Z .z .jar .war .gz .bz2
AddIcon /h5ai/icons/16x16/tar.png .tar
AddIcon /h5ai/icons/16x16/pdf.png .pdf
AddIcon /h5ai/icons/16x16/deb.png .deb
AddIcon /h5ai/icons/16x16/rpm.png .rpm
AddIcon /h5ai/icons/16x16/cd.png .iso .cue
AddIconByType /h5ai/icons/16x16/png.png image/png
AddIconByType /h5ai/icons/16x16/jpg.png image/jpeg
AddIconByType /h5ai/icons/16x16/gif.png image/gif
AddIconByType /h5ai/icons/16x16/ico.png image/x-icon
AddIconByType /h5ai/icons/16x16/bmp.png image/x-ms-bmp
AddIconByType /h5ai/icons/16x16/html.png text/html
AddIconByType /h5ai/icons/16x16/css.png text/css
AddIconByType /h5ai/icons/16x16/xml.png application/xml
AddIconByType /h5ai/icons/16x16/js.png application/javascript application/json
AddIconByType /h5ai/icons/16x16/php.png application/x-httpd-php
AddIconByType /h5ai/icons/16x16/py.png text/x-python
AddIconByType /h5ai/icons/16x16/rb.png application/x-ruby
AddIconByType /h5ai/icons/16x16/java.png text/x-java
AddIconByType /h5ai/icons/16x16/cpp.png text/x-c++src
AddIconByType /h5ai/icons/16x16/hpp.png text/x-c++hdr
AddIconByType /h5ai/icons/16x16/c.png text/x-csrc
AddIconByType /h5ai/icons/16x16/h.png text/x-chdr
AddIconByType /h5ai/icons/16x16/pdf.png application/pdf
AddIconByType /h5ai/icons/16x16/rtf.png text/rtf application/rtf
AddIconByType /h5ai/icons/16x16/tex.png text/x-tex
AddIconByType /h5ai/icons/16x16/makefile.png text/x-makefile
AddIconByType /h5ai/icons/16x16/bin.png application/java-vm
AddIconByType /h5ai/icons/16x16/exe.png application/x-executable application/x-msdos-program
AddIconByType /h5ai/icons/16x16/text.png text/*
AddIconByType /h5ai/icons/16x16/image.png image/*
AddIconByType /h5ai/icons/16x16/audio.png audio/*
AddIconByType /h5ai/icons/16x16/video.png video/*
AddIconByEncoding /h5ai/icons/16x16/zip.png x-compress x-gzip x-bzip2
DefaultIcon /h5ai/icons/16x16/unknown.png

19
src/php.htaccess Normal file
View File

@@ -0,0 +1,19 @@
################################
# %BUILD_NAME% %BUILD_VERSION% (php)
# customized .htaccess
################################
# Options +Indexes
# Options +FollowSymLinks
HeaderName /h5ai/header.php
ReadmeName /h5ai/footer.php
IndexIgnore *
IndexOptions Type=text/html;h5ai=%BUILD_VERSION%
IndexOptions Charset=UTF-8
IndexOptions SuppressHTMLPreamble

View File

@@ -1,146 +0,0 @@
################################
# h5ai 0.11
# customized .htaccess
################################
# Options +Indexes
# 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
# following line with
# <IfModule autoindex_color_module>
################################
<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
################################
HeaderName /h5ai/header.html
ReadmeName /h5ai/footer.html
################################
# hide h5ai folder and config files from index
################################
IndexIgnore h5ai h5ai.header.html h5ai.footer.html
################################
# table options
################################
IndexOrderDefault Ascending Name
IndexOptions Type=text/html;h5ai=0.11
IndexOptions Charset=UTF-8
IndexOptions FancyIndexing
IndexOptions HTMLTable
IndexOptions XHTML
IndexOptions SuppressHTMLPreamble
IndexOptions SuppressRules
IndexOptions SuppressDescription
IndexOptions FoldersFirst
IndexOptions IgnoreCase
IndexOptions IconsAreLinks
IndexOptions VersionSort
IndexOptions NameWidth=*
################################
# icon mapping
################################
AddIcon /h5ai/icons/16x16/parent.png ..
AddIcon /h5ai/icons/16x16/folder.png ^^DIRECTORY^^
AddIcon /h5ai/icons/16x16/blank.png ^^BLANKICON^^
AddIcon /h5ai/icons/16x16/readme.png README
AddIcon /h5ai/icons/16x16/copying.png COPYING LICENSE
AddIcon /h5ai/icons/16x16/install.png INSTALL
AddIcon /h5ai/icons/16x16/authors.png AUTHORS
AddIcon /h5ai/icons/16x16/log.png LOG Log log
AddIcon /h5ai/icons/16x16/css.png .less
AddIcon /h5ai/icons/16x16/script.png .conf .ini .sh .shar .csh .ksh .tcl
AddIcon /h5ai/icons/16x16/makefile.png .pom pom.xml build.xml
AddIcon /h5ai/icons/16x16/bin.png .so .o
AddIcon /h5ai/icons/16x16/archive.png .tar.gz .tgz .tar.bz2
AddIcon /h5ai/icons/16x16/zip.png .zip .Z .z .jar .war .gz .bz2
AddIcon /h5ai/icons/16x16/tar.png .tar
AddIcon /h5ai/icons/16x16/pdf.png .pdf
AddIcon /h5ai/icons/16x16/deb.png .deb
AddIcon /h5ai/icons/16x16/rpm.png .rpm
AddIcon /h5ai/icons/16x16/cd.png .iso .cue
AddIconByType /h5ai/icons/16x16/png.png image/png
AddIconByType /h5ai/icons/16x16/jpg.png image/jpeg
AddIconByType /h5ai/icons/16x16/gif.png image/gif
AddIconByType /h5ai/icons/16x16/ico.png image/x-icon
AddIconByType /h5ai/icons/16x16/bmp.png image/x-ms-bmp
AddIconByType /h5ai/icons/16x16/html.png text/html
AddIconByType /h5ai/icons/16x16/css.png text/css
AddIconByType /h5ai/icons/16x16/xml.png application/xml
AddIconByType /h5ai/icons/16x16/js.png application/javascript application/json
AddIconByType /h5ai/icons/16x16/php.png application/x-httpd-php
AddIconByType /h5ai/icons/16x16/py.png text/x-python
AddIconByType /h5ai/icons/16x16/rb.png application/x-ruby
AddIconByType /h5ai/icons/16x16/java.png text/x-java
AddIconByType /h5ai/icons/16x16/cpp.png text/x-c++src
AddIconByType /h5ai/icons/16x16/hpp.png text/x-c++hdr
AddIconByType /h5ai/icons/16x16/c.png text/x-csrc
AddIconByType /h5ai/icons/16x16/h.png text/x-chdr
AddIconByType /h5ai/icons/16x16/pdf.png application/pdf
AddIconByType /h5ai/icons/16x16/rtf.png text/rtf application/rtf
AddIconByType /h5ai/icons/16x16/tex.png text/x-tex
AddIconByType /h5ai/icons/16x16/makefile.png text/x-makefile
AddIconByType /h5ai/icons/16x16/bin.png application/java-vm
AddIconByType /h5ai/icons/16x16/exe.png application/x-executable application/x-msdos-program
AddIconByType /h5ai/icons/16x16/text.png text/*
AddIconByType /h5ai/icons/16x16/image.png image/*
AddIconByType /h5ai/icons/16x16/audio.png audio/*
AddIconByType /h5ai/icons/16x16/video.png video/*
AddIconByEncoding /h5ai/icons/16x16/zip.png x-compress x-gzip x-bzip2
DefaultIcon /h5ai/icons/16x16/unknown.png
</IfModule>

File diff suppressed because one or more lines are too long

View File

@@ -1,23 +0,0 @@
<!-- generated code ends here -->
</section>
<section id="extended"></section>
<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 0.11</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>
<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/options.js"></script>
<script src="/h5ai/js/main.js"></script>
</body>
</html>

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Directory index · styled with h5ai</title>
<meta name="h5ai-version" content="h5ai 0.11">
<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">
<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>
<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>
</ul>
</nav>
<section id="content">
<header></header>
<section id="table" class="jsDisabledFallback">
<!--
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
removed via javascript. The actual page should render as perfect HTML 5, even if the produced
source is not valid HTML 5.
-->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Some files were not shown because too many files have changed in this diff Show More