Merge branch 'develop'

This commit is contained in:
Lars Jung 2012-04-19 01:04:03 +02:00
commit faf1ce0bcf
104 changed files with 4539 additions and 3373 deletions

View File

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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
Options -Indexes
AddType text/html .php
@ -9,6 +8,7 @@ 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
@ -19,19 +19,19 @@ AddType text/html .php
#AddHandler php53-script .php
# cache images, css and js for 52 weeks
# cache images, css and js for 7 days
<IfModule headers_module>
<FilesMatch "\.png$">
Header set Cache-Control "max-age=31449600, public"
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
<FilesMatch "\.css$">
Header set Cache-Control "max-age=31449600, public"
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
<FilesMatch "\.js$">
Header set Cache-Control "max-age=31449600, public"
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
<FilesMatch "thumb-.*\.jpg$">
Header set Cache-Control "max-age=31449600, public"
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>

View File

@ -17,16 +17,17 @@ var H5AI_CONFIG = {
"h5aiAbsHref": "/_h5ai/",
/*
* Filenames of customized header and footer files to look for
* in each folder. For Example:
*
* "customHeader": "_h5ai.header.html",
* "customFooter": "_h5ai.footer.html",
*
* This is disabled by default.
* Spacing of the main content.
* Left and right will be added to a minimum of 30px. Top and bottom
* are calculated relative to the top and bottom bar heights.
*/
"customHeader": null,
"customFooter": null,
"spacing": {
"maxWidth": 960,
"top": 50,
"right": "auto",
"bottom": 50,
"left": "auto"
},
/*
* An array of view modes the user may choose from. Currently there
@ -35,8 +36,111 @@ var H5AI_CONFIG = {
* view mode is fixed and the selector buttons are hidden.
* The user selected view mode is also stored local in modern browsers
* so that it will be persistent.
*
* Set parent folder labels to real folder names.
*/
"viewmodes": ["details", "icons"],
"view": {
"modes": ["details", "icons"],
"setParentFolderLabels": true
},
/*
* Extensions in alphabetical order.
*/
/*
* Show a clickable breadcrumb.
*/
"crumb": {
"enabled": true
},
/*
* Filenames of customized header and footer files to look for
* in each folder.
*/
"custom": {
"enabled": false,
"header": "_h5ai.header.html",
"footer": "_h5ai.footer.html"
},
/*
* EXPLICITLY: USE "shell" ON YOUR OWN RISK.
*
* Requires PHP on the server.
* Enable packaged download of selected entries.
* Execution: "php", "shell".
* Supported formats: "tar", "zip".
*/
"download": {
"enabled": false,
"execution": "shell",
"format": "zip"
},
/*
* Allow filtering the displayed files and folders.
* Note: filters will be treated as JavaScript regular expressions
* if you prefix them with "re:".
*/
"filter": {
"enabled": true
},
/*
* Associative array of folders and their HTTP status codes to
* avoid HEAD requests to that folders. The key (folder) must start
* and end with a slash (/).
* For example
* "/some/folder/": 200
* will always return HTTP status 200 (OK), which will be interpreted
* as a non auto indexed folder, that means a folder containing an
* appropriate default index file.
*/
"folderstatus": {
"enabled": false,
"folders": {}
},
/*
* Localization, for example "en", "de" etc. - see "langs" below for
* possible values. Adjust it to your needs. If lang is not found in
* "langs" it defaults to "en".
*
* Optionally try to use browser language, falls back to previous
* specified language.
*/
"l10n": {
"enabled": true,
"lang": "en",
"useBrowserLang": true
},
/*
* Link the hover effects between crumb, main view and tree.
*/
"link-hover-states": {
"enabled": true
},
/*
* Show QRCodes on hovering files.
*/
"qrcode": {
"enabled": false,
"size": 150
},
/*
* Make entries selectable. At the moment only needed for packaged download.
*/
"select": {
"enabled": true
},
/*
* Default sort order is a two letter code. The first letter specifies
@ -44,162 +148,126 @@ var H5AI_CONFIG = {
* second letter specifies the sort order: "a" for "ascending" or "d"
* for "descending".
*/
"sortorder": "na",
"sort": {
"enabled": true,
"order": "na"
},
/*
* Show a folder tree, boolean.
* Show additional info in a statusbar.
*/
"statusbar": {
"enabled": true
},
/*
* Requires PHP on the server.
* Show thumbnails for image files. Needs the "/_h5ai/cache" folder to be
* writable for the Apache Server.
*/
"thumbnails": {
"enabled": true,
"types": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
"delay": 1000
},
/*
* Replace window title with current breadcrumb.
*/
"title": {
"enabled": true
},
/*
* Show a folder tree.
* Note that this tree might have side effects as it sends HEAD requests
* to the folders, and therefore will invoke index.php scripts. Use
* folderStatus below to avoid such requests.
* "folderstatus" above to avoid such requests.
* It might also affect performance significantly.
*
* Slide tree bar into viewport if there is enough space.
*/
"showTree": true,
/*
* Slide tree bar into viewport if there is enough space, boolean.
*/
"slideTree": true,
/*
* Associative array of folders and their HTTP status codes to
* avoid HEAD requests to that folders. The key (folder) must start
* and end with a slash (/).
* For example:
* "/some/folder/": 200
* will always return HTTP status 200 (OK), which will be interpreted
* as a non auto indexed folder, that means a folder containing an
* appropriate default index file.
*/
"folderStatus": {},
/*
* Localization, for example "en", "de" etc. - see h5aiLangs below for
* possible values. Adjust it to your needs. If lang is not found in
* h5aiLangs it defaults to "en".
*/
"lang": "en",
/*
* Try to use browser language, falls back to previous specified lang.
*/
"useBrowserLang": true,
/*
* Set parent folder labels to real folder names.
*/
"setParentFolderLabels": true,
/*
* Link the hover effects between crumb, extended view and tree.
*/
"linkHoverStates": true,
/*
* Date format in detailed view, for example: "yyyy-MM-dd HH:mm:ss"
* Syntax as specified by date.js
* http://code.google.com/p/datejs/wiki/FormatSpecifiers
*/
"dateFormat": "yyyy-MM-dd HH:mm",
/*
* Requires PHP on the server.
* Show thumbnails for image files.
*/
"showThumbs": true,
"thumbTypes": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
/*
* Requires PHP on the server.
* Enable zipped download of selected entries.
*/
"zippedDownload": false,
/*
* Show QRCodes on hovering files.
* Set this to the desired size in pixel or null to not display QRCodes.
* A good size to start with might be 150.
*/
"qrCodesSize": null,
/*
* Allow filtering the displayed files and folders.
* Filters are ment to be JavaScript regular expressions.
*/
"showFilter": false
"tree": {
"enabled": true,
"slide": true
}
},
/*
* File types mapped to file extensions.
* File types mapped to file extensions. In alphabetical order.
*/
"types": {
"archive": [".tar.bz2", ".tar.gz", ".tgz"],
"audio": [".aif", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"],
"authors": ["authors"],
"bin": [".class", ".o", ".so"],
"blank": [],
"bmp": [".bmp"],
"c": [".c"],
"calc": [".ods", ".ots", ".xlr", ".xls", ".xlsx"],
"cd": [".cue", ".iso"],
"copying": ["copying", "license"],
"cpp": [".cpp"],
"css": [".css", ".less"],
"deb": [".deb"],
"default": [],
"doc": [".doc", ".docx", ".odm", ".odt", ".ott"],
"draw": [".drw"],
"eps": [".eps"],
"exe": [".exe"],
"folder": [],
"folder-home": [],
"folder-open": [],
"folder-page": [],
"folder-parent": [],
"gif": [".gif"],
"gzip": [".gz"],
"h": [".h"],
"hpp": [".hpp"],
"html": [".htm", ".html", ".shtml"],
"ico": [".ico"],
"image": [".xpm"],
"install": ["install"],
"java": [".java"],
"jpg": [".jpg", ".jpeg"],
"js": [".js", ".json"],
"log": [".log", "changelog"],
"makefile": [".pom", "build.xml", "pom.xml"],
"package": [],
"pdf": [".pdf"],
"php": [".php"],
"playlist": [".m3u"],
"png": [".png"],
"pres": [".odp", ".otp", ".pps", ".ppt", ".pptx"],
"psd": [".psd"],
"py": [".py"],
"rar": [".rar"],
"rb": [".rb"],
"readme": ["readme"],
"rpm": [".rpm"],
"rss": [".rss"],
"rtf": [".rtf"],
"script": [".conf", ".csh", ".ini", ".ksh", ".sh", ".shar", ".tcl"],
"source": [],
"sql": [],
"tar": [".tar"],
"tex": [".tex"],
"text": [".markdown", ".md", ".text", ".txt"],
"tiff": [".tiff"],
"unknown": [],
"vcal": [".vcal"],
"video": [".avi", ".flv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"],
"xml": [".xml"],
"zip": [".bz2", ".jar", ".war", ".z", ".Z", ".zip"]
"archive": [".tar.bz2", ".tar.gz", ".tgz"],
"audio": [".aif", ".flac", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"],
"authors": ["authors"],
"bin": [".class", ".o", ".so"],
"blank": [],
"bmp": [".bmp"],
"c": [".c"],
"calc": [".ods", ".ots", ".xlr", ".xls", ".xlsx"],
"cd": [".cue", ".iso"],
"copying": ["copying", "license"],
"cpp": [".cpp"],
"css": [".css", ".less"],
"deb": [".deb"],
"default": [],
"doc": [".doc", ".docx", ".odm", ".odt", ".ott"],
"draw": [".drw"],
"eps": [".eps"],
"exe": [".bat", ".cmd", ".exe"],
"folder": [],
"folder-home": [],
"folder-open": [],
"folder-page": [],
"folder-parent": [],
"gif": [".gif"],
"gzip": [".gz"],
"h": [".h"],
"hpp": [".hpp"],
"html": [".htm", ".html", ".shtml"],
"ico": [".ico"],
"image": [".xpm"],
"install": ["install"],
"java": [".java"],
"jpg": [".jpg", ".jpeg"],
"js": [".js", ".json"],
"log": [".log", "changelog"],
"makefile": [".pom", "build.xml", "pom.xml"],
"package": [],
"pdf": [".pdf"],
"php": [".php"],
"playlist": [".m3u", ".m3u8", ".pls"],
"png": [".png"],
"pres": [".odp", ".otp", ".pps", ".ppt", ".pptx"],
"psd": [".psd"],
"py": [".py"],
"rar": [".rar"],
"rb": [".rb"],
"readme": ["readme"],
"rpm": [".rpm"],
"rss": [".rss"],
"rtf": [".rtf"],
"script": [".conf", ".csh", ".ini", ".ksh", ".sh", ".shar", ".tcl"],
"source": [],
"sql": [],
"tar": [".tar"],
"tex": [".tex"],
"text": [".diff", ".markdown", ".md", ".patch", ".text", ".txt"],
"tiff": [".tiff"],
"unknown": [],
"vcal": [".vcal"],
"video": [".avi", ".flv", ".mkv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"],
"xml": [".xml"],
"zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"]
},
/*
* Available translations.
* Available translations. "en" in first place as a reference, otherwise in alphabetical order.
*
* Date format is used in detailed view, for example: "YYYY-MM-DD HH:mm:ss"
* Syntax as specified by Moment.js (http://momentjs.com)
*/
"langs": {
@ -215,7 +283,8 @@ var H5AI_CONFIG = {
"folders": "folders",
"files": "files",
"download": "download",
"noMatch": "no match"
"noMatch": "no match",
"dateFormat": "YYYY-MM-DD HH:mm"
},
"bg": {
@ -228,9 +297,7 @@ var H5AI_CONFIG = {
"parentDirectory": "Предходна директория",
"empty": "празно",
"folders": "папки",
"files": "файлове",
"download": "download",
"noMatch": "no match"
"files": "файлове"
},
"cs": {
@ -243,9 +310,7 @@ var H5AI_CONFIG = {
"parentDirectory": "Nadřazený adresář",
"empty": "prázdný",
"folders": "složek",
"files": "souborů",
"download": "download",
"noMatch": "no match"
"files": "souborů"
},
"de": {
@ -260,7 +325,8 @@ var H5AI_CONFIG = {
"folders": "Ordner",
"files": "Dateien",
"download": "Download",
"noMatch": "keine Treffer"
"noMatch": "keine Treffer",
"dateFormat": "DD.MM.YYYY HH:mm"
},
"es": {
@ -274,8 +340,7 @@ var H5AI_CONFIG = {
"empty": "vacío",
"folders": "Directorios",
"files": "Archivos",
"download": "Descargar",
"noMatch": "no match"
"download": "Descargar"
},
"fr": {
@ -290,7 +355,22 @@ var H5AI_CONFIG = {
"folders": "Répertoires",
"files": "Fichiers",
"download": "télécharger",
"noMatch": "no match"
"noMatch": "rien trouvé"
},
"gr": {
"lang": "ελληνικά",
"details": "Λεπτομέρειες",
"icons": "Εικονίδια",
"name": "Όνομα",
"lastModified": "Τελευταία Τροποποίηση",
"size": "Μέγεθος",
"parentDirectory": "Προηγούμενος Κατάλογος",
"empty": "κενό",
"folders": "Φάκελοι",
"files": "Αρχεία",
"download": "Μεταμόρφωση",
"noMatch": "Κανένα Ταίριασμα"
},
"it": {
@ -303,10 +383,23 @@ var H5AI_CONFIG = {
"parentDirectory": "Cartella Superiore",
"empty": "vuota",
"folders": "cartelle",
"files": "file",
"download": "download",
"noMatch": "no match"
},
"files": "file"
},
"ja": {
"lang": "日本語",
"details": "詳細",
"icons": "アイコン",
"name": "名前",
"lastModified": "変更日",
"size": "サイズ",
"parentDirectory": "親フォルダ",
"empty": "項目なし",
"folders": "フォルダ",
"files": "ファイル",
"download": "ダウンロード",
"noMatch": "一致なし"
},
"lv": {
"lang": "latviešu",
@ -320,7 +413,22 @@ var H5AI_CONFIG = {
"folders": "mapes",
"files": "faili",
"download": "lejupielādēt",
"noMatch": "no match"
"noMatch": "nav sakritības"
},
"nb": {
"lang": "norwegian",
"details": "detaljer",
"icons": "ikoner",
"name": "Navn",
"lastModified": "Sist endret",
"size": "Størrelse",
"parentDirectory": "Overordnet mappe",
"empty": "tom",
"folders": "mapper",
"files": "filer",
"download": "last ned",
"noMatch": "ingen treff"
},
"nl": {
@ -331,11 +439,7 @@ var H5AI_CONFIG = {
"lastModified": "Laatste wijziging",
"size": "Grootte",
"parentDirectory": "Bovenliggende map",
"empty": "lege",
"folders": "folders",
"files": "files",
"download": "download",
"noMatch": "no match"
"empty": "lege"
},
"pl": {
@ -348,9 +452,7 @@ var H5AI_CONFIG = {
"parentDirectory": "Katalog nadrzędny",
"empty": "pusty",
"folders": "foldery",
"files": "pliki",
"download": "download",
"noMatch": "no match"
"files": "pliki"
},
"pt": {
@ -363,9 +465,22 @@ var H5AI_CONFIG = {
"parentDirectory": "Diretório superior",
"empty": "vazio",
"folders": "pastas",
"files": "arquivos",
"download": "download",
"noMatch": "no match"
"files": "arquivos"
},
"ro": {
"lang": "română",
"details": "detalii",
"icons": "pictograme",
"name": "nume",
"lastModified": "ultima modificare",
"size": "mărime",
"parentDirectory": "dosar părinte",
"empty": "gol",
"folders": "dosar",
"files": "fişiere",
"download": "descarcă",
"noMatch": "0 rezultate"
},
"ru": {
@ -378,9 +493,7 @@ var H5AI_CONFIG = {
"parentDirectory": "Главная директория",
"empty": "пусто",
"folders": "папки",
"files": "файлы",
"download": "download",
"noMatch": "no match"
"files": "файлы"
},
"sk": {
@ -393,9 +506,22 @@ var H5AI_CONFIG = {
"parentDirectory": "Nadriadený priečinok",
"empty": "prázdny",
"folders": "priečinkov",
"files": "súborov",
"files": "súborov"
},
"sr": {
"lang": "srpski",
"details": "detalji",
"icons": "ikone",
"name": "Ime",
"lastModified": "Poslednja modifikacija",
"size": "Veličina",
"parentDirectory": "Roditeljski direktorijum",
"empty": "prazno",
"folders": "direktorijum",
"files": "fajlovi",
"download": "download",
"noMatch": "no match"
"noMatch": "bez poklapanja"
},
"sv": {
@ -406,11 +532,7 @@ var H5AI_CONFIG = {
"lastModified": "Senast ändrad",
"size": "Filstorlek",
"parentDirectory": "Till överordnad mapp",
"empty": "tom",
"folders": "folders",
"files": "files",
"download": "download",
"noMatch": "no match"
"empty": "tom"
},
"tr": {
@ -424,8 +546,7 @@ var H5AI_CONFIG = {
"empty": "boş",
"folders": "klasörler",
"files": "dosyalar",
"download": "indir",
"noMatch": "no match"
"download": "indir"
},
"zh-cn": {
@ -439,8 +560,7 @@ var H5AI_CONFIG = {
"empty": "空文件夹",
"folders": "文件夹",
"files": "文件",
"download": "下载",
"noMatch": "no match"
"download": "下载"
},
"zh-tw": {
@ -454,8 +574,7 @@ var H5AI_CONFIG = {
"empty": "空資料夾",
"folders": "資料夾",
"files": "檔案",
"download": "下載",
"noMatch": "no match"
"download": "下載"
}
}
};

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
#download {
display: none;
.topbar-right;
.transition(all 0.2s ease-in-out);
&.failed {
background-color: rgba(255,0,0,0.5);
}
}
#download-auth {
display: none;
position: fixed;
z-index: 5;
left: 0;
top: 0;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border: 1px solid rgb(210,210,210);
input {
display: block;
margin: 4px 6px;
border: 1px solid rgb(210,210,210);
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(255,255,255,1);
width: 100px;
}
}

View File

@ -13,6 +13,8 @@
clear: both;
&.header {
font-size: 13px;
a, a:active, a:visited {
padding-bottom: 18px;
color: #555;
@ -42,7 +44,6 @@
}
}
&.entry {
a, a:active, a:visited {
display: block;
color: #555;
@ -54,10 +55,10 @@
background-color: #f6f6f6;
color: #e80;
}
&.selected:not(.selecting), &.selecting:not(.selected) {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
}
&.selected:not(.selecting) a, &.selecting:not(.selected) a {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
&.error {
a, a:active, a:visited {
@ -102,7 +103,7 @@
width: 16px;
height: 16px;
&.thumb {
border: 1px solid #eee;
// border: 1px solid #ddd;
}
}
}
@ -132,18 +133,6 @@
width: 80px;
white-space: nowrap;
}
&.entry.thumb .icon.small {
overflow: hidden;
padding: 5px;
img {
background-color: #eee;
width: 16px;
height: 16px;
border: 1px solid #ddd;
overflow: hidden;
}
}
}
}
.empty, .no-match {
@ -206,19 +195,15 @@
border-color: #eee;
background-color: #f6f6f6;
}
&.selected:not(.selecting), &.selecting:not(.selected) {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
.icon {
display: block;
img {
min-width: 48px;
min-height: 48px;
max-width: 100px;
height: 48px;
margin-bottom: 8px;
&.thumb {
border: 1px solid #eee;
// border: 1px solid #ddd;
}
}
}
@ -233,6 +218,10 @@
display: none;
}
}
&.selected:not(.selecting) a, &.selecting:not(.selected) a {
border-color: rgba(240,100,0,0.2);
background-color: rgba(240,100,0,0.2);
}
&.error {
a, a:active, a:visited {
color: #aaa;
@ -253,21 +242,6 @@
}
}
}
&.entry.thumb .icon.big {
width: 100px;
height: 58px;
overflow: hidden;
img {
background-color: #eee;
min-width: 46px;
min-height: 46px;
min-width: 12px;
min-height: 12px;
border: 1px solid #ddd;
overflow: hidden;
}
}
}
}
.empty, .no-match {

View File

@ -0,0 +1,19 @@
#filter {
.topbar-right;
input {
display: none;
border: none;
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(0,0,0,0);
width: 100px;
}
&.current {
input {
display: inline;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,135 +0,0 @@
.nav-highlight {
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
.nav-hover {
.nav-highlight;
color: #e80;
}
@nav-sep-border: 1px solid rgba(0,0,0,0.05);
.nav-left {
float: left;
border-right: @nav-sep-border;
}
.nav-right {
float: right;
border-left: @nav-sep-border;
}
body > nav {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
top: 0;
font-size: 0.85em;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-bottom: 1px solid rgb(210,210,210);
span.jsDisabledFallback {
display: block;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: #999;
}
a, a:active, a:visited, span.element {
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 {
.nav-hover;
}
}
.current {
a, span.element {
.nav-highlight;
}
}
img {
position: relative;
top: -2px;
width: 16px;
height: 16px;
}
img + span, img + input {
margin-left: 6px;
}
.crumb {
.nav-left;
.hint {
margin-left: 8px;
font-style: italic;
color: #999;
}
img.hint {
width: 10px;
height: 10px;
}
}
.view {
.nav-right;
}
#download {
display: none;
.nav-right;
.transition(all 0.2s ease-in-out);
&.failed {
background-color: rgba(255,0,0,0.5);
}
}
#filter {
.nav-right;
input {
display: none;
border: none;
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(0,0,0,0);
width: 100px;
}
&.current {
input {
display: inline;
}
}
}
}
#download-auth {
display: none;
position: fixed;
z-index: 5;
left: 0;
top: 0;
font-size: 0.85em;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border: 1px solid rgb(210,210,210);
input {
display: block;
margin: 4px 6px;
border: 1px solid rgb(210,210,210);
font-family: Ubuntu, sans-serif;
color: #555;
background-color: rgba(255,255,255,1);
width: 100px;
}
}

View File

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

View File

@ -0,0 +1,88 @@
#topbar {
position: fixed;
z-index: 5;
width: 100%;
left: 0;
top: 0;
.vert-gradient(rgb(241,241,241), rgb(228,228,228));
border-bottom: 1px solid rgb(210,210,210);
}
.topbar-highlight {
background-color: rgba(255,255,255,0.5);
opacity: 1.0;
}
.topbar-hover {
.topbar-highlight;
color: #e80;
}
@topbar-sep-border: 1px solid rgba(0,0,0,0.05);
.topbar-left {
float: left;
border-right: @topbar-sep-border;
}
.topbar-right {
float: right;
border-left: @topbar-sep-border;
}
#navbar {
list-style: none;
list-style-image: none;
margin: 0;
padding: 0;
a, a:active, a:visited, span.element {
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 {
.topbar-hover;
}
}
.current {
a, span.element {
.topbar-highlight;
}
}
img {
position: relative;
top: -2px;
width: 16px;
height: 16px;
}
img + span, img + input {
margin-left: 6px;
}
.crumb {
.topbar-left;
.hint {
margin-left: 8px;
font-style: italic;
color: #999;
}
img.hint {
width: 14px;
height: 14px;
opacity: 0.8;
}
}
.view {
.topbar-right;
}
}

View File

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

View File

@ -1,58 +0,0 @@
@import "inc/h5bp-norm";
@import "inc/mixins";
body {
font-family: Ubuntu, sans-serif;
font-size: 16px;
color: #555;
background-color: #fff;
margin: 80px 30px;
}
@import "inc/nav";
@import "inc/content";
@import "inc/table";
@import "inc/extended";
@import "inc/tree";
@import "inc/context";
@import "inc/footer";
@import "inc/responsive";
html.js {
.hideOnJs {
display: none;
}
}
html.no-js {
.hideOnNoJs {
display: none;
}
}
html.h5ai-js {
#h5ai-reference:after {
content: " (js)";
}
}
html.h5ai-php {
#h5ai-reference:after {
content: " (php)";
}
#table {
display: none;
}
#tree, #content > header, #content > footer {
display: block;
}
html.no-js {
#extended.details-view, #extended.icons-view {
display: block;
}
}
}

47
src/_h5ai/css/styles.less Normal file
View File

@ -0,0 +1,47 @@
@import "inc/h5bp-norm";
@import "inc/mixins";
::-moz-selection { background: #68A9FF; color: #fff; text-shadow: none; }
::selection { background: #68A9FF; color: #fff; text-shadow: none; }
body {
font-family: Ubuntu, sans-serif;
font-size: 13px;
color: #555;
background-color: #fff;
margin: 30px;
}
@import "inc/topbar";
@import "inc/download";
@import "inc/filter";
@import "inc/content";
@import "inc/extended";
@import "inc/bottombar";
@import "inc/l10n";
@import "inc/tree";
@import "inc/context";
@import "inc/apache-autoindex-table";
@import "inc/responsive";
@import "inc/h5ai-info";
html.js .hideOnJs, html.no-js .hideOnNoJs {
display: none;
}
html.oldie {
.oldBrowser {
display: inline !important;
}
#tree {
display: none !important;
}
}

View File

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

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

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/_h5ai/images/html5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

After

Width:  |  Height:  |  Size: 564 B

43
src/_h5ai/index.html Normal file
View File

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

View File

@ -1,115 +0,0 @@
(function ($, H5AI) {
H5AI.connector = (function () {
var cache = {},
pathnameStatusCache = {},
contentTypeRegEx = /^text\/html;h5ai=/,
getPath = function (folder, tableRow) {
var absHref = H5AI.util.getAbsHref(folder, tableRow),
path = cache[absHref];
if (!path) {
path = H5AI.Path(folder, tableRow);
if (!path.isParentFolder) {
cache[path.absHref] = path;
}
}
return path;
},
fetchStatus = function (pathname, callback) {
if (H5AI.core.settings.folderStatus[pathname]) {
callback(H5AI.core.settings.folderStatus[pathname]);
return;
} else if (pathnameStatusCache[pathname]) {
callback(pathnameStatusCache[pathname]);
return;
}
$.ajax({
url: pathname,
type: "HEAD",
complete: function (xhr) {
var status = xhr.status;
if (status === 200 && contentTypeRegEx.test(xhr.getResponseHeader("Content-Type"))) {
status = "h5ai";
}
pathnameStatusCache[pathname] = status;
callback(status);
}
});
},
updatePath = function (path) {
if (path.isFolder && !path.isParentFolder && path.status === undefined) {
fetchStatus(path.absHref, function (status) {
if (status !== "h5ai") {
path.status = status;
}
H5AI.html.updateHtml(path);
H5AI.core.linkHoverStates();
});
}
},
updatePaths = function () {
$.each(cache, function (ref, cached) {
updatePath(cached);
});
},
fetchStatusAndContent = function (pathname, includeParent, callback) {
fetchStatus(pathname, function (status) {
if (status !== "h5ai") {
callback(status, {});
return;
}
$.ajax({
url: pathname,
type: "GET",
dataType: "html",
error: function (xhr) {
callback(xhr.status, {}); // since it was checked before this should never happen
},
success: function (html, status, xhr) {
var content = {};
if (!contentTypeRegEx.test(xhr.getResponseHeader("Content-Type"))) {
callback(xhr.status, {}); // since it was checked before this should never happen
return;
}
$(html).find("#table td").closest("tr").each(function () {
var path = getPath(pathname, this);
if (path.isFolder && (!path.isParentFolder || includeParent)) {
content[path.absHref] = path;
updatePath(path);
}
});
callback("h5ai", content);
}
});
});
};
return {
getPath: getPath,
updatePaths: updatePaths,
fetchStatusAndContent: fetchStatusAndContent
};
}());
}(jQuery, H5AI));

View File

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

View File

@ -1,439 +0,0 @@
(function (window, $, H5AI, config) {
H5AI.core = (function () {
var $window = $(window),
defaults = {
store: {
viewmode: "h5ai.pref.viewmode",
lang: "h5ai.pref.lang"
},
callbacks: {
pathClick: []
},
rootAbsHref: "/",
h5aiAbsHref: "/_h5ai/",
customHeader: null,
customFooter: null,
viewmodes: ["details", "icons"],
sortorder: "na",
showTree: true,
slideTree: true,
folderStatus: {},
lang: "en",
useBrowserLang: true,
setParentFolderLabels: true,
linkHoverStates: true,
dateFormat: "yyyy-MM-dd HH:mm",
showThumbs: false,
thumbTypes: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
zippedDownload: false,
qrCodesSize: null,
showFilter: false
},
settings = $.extend({}, defaults, config.options),
currentDateFormat = settings.dateFormat,
extToFileType = (function (types) {
var map = {};
$.each(types, function (type, exts) {
$.each(exts, function (idx, ext) {
map[ext] = type;
});
});
return map;
}(config.types)),
hash = function (obj) {
if ($.isPlainObject(obj)) {
var hashStr = '';
$.each($.extend({}, hash(), obj), function (key, value) {
if (value) {
hashStr += '/' + encodeURIComponent(key) + '=' + encodeURIComponent(value);
}
});
hashStr = '#!' + hashStr;
window.location.hash = hashStr;
return hashStr;
} else {
var result = {},
parts = document.location.hash.split('/');
if (parts.length >= 2 || parts[0] === '#!') {
parts.shift();
$.each(parts, function (idx, part) {
var match = /^([^=]*)=(.*?)$/.exec(part);
if (match) {
result[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
});
}
return typeof obj === 'string' ? result[obj] : result;
}
},
api = function () {
return settings.h5aiAbsHref + "php/api.php";
},
image = function (id, noPngExt) {
return settings.h5aiAbsHref + "images/" + id + (noPngExt ? "" : ".png");
},
icon = function (id, big) {
return settings.h5aiAbsHref + "icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png";
},
viewmode = function (viewmode) {
var $viewDetails = $("#viewdetails"),
$viewIcons = $("#viewicons"),
$extended = $("#extended");
if (viewmode) {
amplify.store(settings.store.viewmode, viewmode);
} else {
viewmode = amplify.store(settings.store.viewmode);
}
viewmode = $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0];
H5AI.core.hash({view: viewmode});
$viewDetails.add($viewIcons).removeClass("current");
if (viewmode === "details") {
$viewDetails.addClass("current");
$extended.addClass("details-view").removeClass("icons-view").show();
} else if (viewmode === "icons") {
$viewIcons.addClass("current");
$extended.removeClass("details-view").addClass("icons-view").show();
} else {
$extended.hide();
}
},
initTopSpace = function () {
var $body = $("body"),
$tree = $("#tree"),
adjustTopSpace = function () {
var winHeight = $window.height(),
navHeight = $("body > nav").outerHeight(),
footerHeight = $("body > footer").outerHeight(),
contentSpacing = 50,
treeSpacing = 0;
$body.css({
"margin-top": navHeight + contentSpacing,
"margin-bottom": footerHeight + contentSpacing
});
$tree.css({
top: navHeight + treeSpacing,
height: winHeight - navHeight - footerHeight - 16 - 2 * treeSpacing
});
try {
$tree.get(0).updateScrollbar();
} catch (err) {}
};
$window.resize(function () {
adjustTopSpace();
});
adjustTopSpace();
},
initViews = function () {
var $navbar = $("#navbar"),
$extended = $("#extended");
$("#table").remove();
if (settings.viewmodes.length > 1) {
if ($.inArray("icons", settings.viewmodes) >= 0) {
$("<li id='viewicons' class='view'><a href='#'><img alt='view-icons' /><span class='l10n-icons'>icons</span></a></li>")
.find("img").attr("src", image("view-icons")).end()
.find("a").click(function (event) {
viewmode("icons");
event.preventDefault();
}).end()
.appendTo($navbar);
}
if ($.inArray("details", settings.viewmodes) >= 0) {
$("<li id='viewdetails' class='view'><a href='#'><img alt='view-details' /><span class='l10n-details'>details</span></a></li>")
.find("img").attr("src", image("view-details")).end()
.find("a").click(function (event) {
viewmode("details");
event.preventDefault();
}).end()
.appendTo($navbar);
}
}
// status update
$extended.find(".entry a").hover(
function () {
if ($extended.hasClass("icons-view")) {
var $this = $(this);
$(".status.default").hide();
$(".status.dynamic")
.empty()
.append($this.find(".label").clone())
.append($("<span class='sep'>·</span>"))
.append($this.find(".date").clone())
.show();
if (!$this.closest(".entry").hasClass("folder")) {
$(".status.dynamic")
.append($("<span class='sep'>·</span>"))
.append($this.find(".size").clone());
}
}
},
function () {
$(".status.default").show();
$(".status.dynamic").empty().hide();
}
);
},
shiftTree = function (forceVisible, dontAnimate) {
var $tree = $("#tree"),
$extended = $("#extended");
if ((settings.slideTree && $tree.outerWidth() < $extended.offset().left) || forceVisible) {
if (dontAnimate) {
$tree.stop().css({ left: 0 });
} else {
$tree.stop().animate({ left: 0 });
}
} else {
if (dontAnimate) {
$tree.stop().css({ left: 18 - $tree.outerWidth() });
} else {
$tree.stop().animate({ left: 18 - $tree.outerWidth() });
}
}
},
initTree = function () {
$("#tree").hover(
function () { shiftTree(true); },
function () { shiftTree(); }
);
$window.resize(function () { shiftTree(); });
shiftTree(false, true);
},
selectLinks = function (href) {
var elements = [];
$("a[href^='/']").each(function () {
if ($(this).attr("href") === href) {
elements.push(this);
}
});
return $(elements);
},
linkHoverStates = function () {
if (settings.linkHoverStates) {
$("a[href^='/']:not(.linkedHoverStates)").each(function () {
var $a = $(this).addClass("linkedHoverStates"),
href = $a.attr("href");
$a.hover(
function () { selectLinks(href).addClass("hover"); },
function () { selectLinks(href).removeClass("hover"); }
);
});
}
},
formatDates = function (dateFormat) {
if (dateFormat) {
currentDateFormat = dateFormat;
}
$("#extended .entry .date").each(function () {
var $this = $(this),
time = $this.data("time"),
formattedDate = time ? new Date(time).toString(currentDateFormat) : "";
$this.text(formattedDate);
});
},
localize = function (langs, lang, useBrowserLang) {
var storedLang = amplify.store(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) {
$.each(selected, function (key, value) {
$(".l10n-" + key).text(value);
});
$(".lang").text(lang);
$(".langOption").removeClass("current");
$(".langOption." + lang).addClass("current");
H5AI.core.hash({lang: lang});
}
formatDates(selected.dateFormat || settings.dateFormat);
},
initLangSelector = function (langs) {
var $langOptions = $("#langSelector .langOptions"),
sortedLangsKeys = [],
$ul;
$.each(langs, function (lang) {
sortedLangsKeys.push(lang);
});
sortedLangsKeys.sort();
$ul = $("<ul />");
$.each(sortedLangsKeys, function (idx, lang) {
$("<li class='langOption' />")
.addClass(lang)
.text(lang + " - " + langs[lang].lang)
.appendTo($ul)
.click(function () {
amplify.store(settings.store.lang, lang);
localize(langs, lang, false);
});
});
$langOptions
.append($ul)
.scrollpanel();
$("#langSelector").hover(
function () {
$langOptions
.css("top", "-" + $langOptions.outerHeight() + "px")
.stop(true, true)
.fadeIn();
$langOptions.get(0).updateScrollbar();
},
function () {
$langOptions
.stop(true, true)
.fadeOut();
}
);
},
onIndicatorClick = function (event) {
var $indicator = $(this),
$entry = $indicator.closest(".entry"),
updateTreeScrollbar = $("#tree").get(0).updateScrollbar;
if ($indicator.hasClass("unknown")) {
$.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) {
var $content = $(html);
$indicator.removeClass("unknown");
if ($content.find("> li").size() === 0) {
$indicator.replaceWith($("<span class='blank' />"));
} else {
$indicator.addClass("open");
$entry.find("> .content").replaceWith($content);
updateTreeScrollbar();
$content.find(".indicator:not(.initiated)")
.click(onIndicatorClick)
.addClass("initiated");
}
});
} else if ($indicator.hasClass("open")) {
$indicator.removeClass("open");
updateTreeScrollbar(true);
$entry.find("> .content").slideUp(function () {
updateTreeScrollbar();
});
} else {
$indicator.addClass("open");
updateTreeScrollbar(true);
$entry.find("> .content").slideDown(function () {
updateTreeScrollbar();
});
}
},
initIndicators = function () {
$("#tree .entry.folder .indicator:not(.initiated)")
.click(onIndicatorClick)
.addClass("initiated");
},
getFileType = function (filename) {
var dotidx = filename.lastIndexOf('.'),
ext = dotidx >= 0 ? filename.substr(dotidx) : filename;
return extToFileType[ext.toLowerCase()] || "unknown";
},
formatSizes = function () {
$("#extended .entry .size").each(function () {
var $this = $(this),
bytes = $this.data("bytes"),
formattedSize = bytes >= 0 ? H5AI.util.formatSize(bytes) : "";
$this.text(formattedSize);
});
},
setTotals = function () {
var $extended = $("#extended");
$(".folderTotal").text($extended.find(".entry.folder:not(.folder-parent)").length);
$(".fileTotal").text($extended.find(".entry.file").length);
},
init = function () {
initViews();
viewmode();
initTopSpace();
initTree();
linkHoverStates();
initLangSelector(config.langs);
localize(config.langs, settings.lang, settings.useBrowserLang);
formatSizes();
setTotals();
initIndicators();
};
return {
settings: settings,
hash: hash,
api: api,
image: image,
icon: icon,
shiftTree: shiftTree,
linkHoverStates: linkHoverStates,
initIndicators: initIndicators,
formatDates: formatDates,
getFileType: getFileType,
init: init
};
}());
}(window, jQuery, H5AI, H5AI_CONFIG));

View File

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

View File

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

View File

@ -1,264 +0,0 @@
(function ($, H5AI) {
H5AI.html = (function () {
var onClick = function (path, context) {
},
updateCrumbHtml = function (path) {
var $html, $a;
if (path.html.$crumb && path.html.$crumb.data("status") === path.status) {
return path.html.$crumb;
}
$html = $("<li class='crumb'><a><img alt='>' /><span></span></a></li>")
.addClass(path.isFolder ? "folder" : "file");
if (path.status) {
$html.data("status", path.status);
}
$a = $html.find("a")
.attr("href", path.absHref)
.click(function() { onClick(path, "crumb"); })
.find("img").attr("src", H5AI.core.image("crumb")).end()
.find("span").text(path.label).end();
if (path.isDomain) {
$html.addClass("domain");
$a.find("img").attr("src", H5AI.core.image("home"));
}
if (path.isCurrentFolder) {
$html.addClass("current");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$a.append($("<img class='hint' src='" + H5AI.core.image("page") + "' alt='not listable' />"));
} else {
$a.append($("<span class='hint'>(" + path.status + ")</span>"));
}
}
if (path.html.$crumb) {
path.html.$crumb.replaceWith($html);
}
path.html.$crumb = $html;
return $html;
},
updateExtendedHtml = function (path) {
var $html, $a, $label,
formattedDate = path.date ? path.date.toString(H5AI.core.settings.dateFormat) : "",
imgClass = "",
icon16 = H5AI.core.icon(path.type),
icon48 = H5AI.core.icon(path.type, true);
if (path.html.$extended && path.html.$extended.data("status") === path.status) {
return path.html.$extended;
}
$html = $("<li class='entry' />")
.data("path", path)
.addClass(path.isFolder ? "folder" : "file");
if (path.status) {
$html.data("status", path.status);
}
if (H5AI.core.settings.showThumbs === true && $.inArray(path.type, H5AI.core.settings.thumbTypes) >= 0) {
imgClass = "class='thumb'";
var escapedHref = path.absHref.replace(/'/g, "%27").replace(/"/g, "%22");
icon16 = H5AI.core.api() + "?action=thumb&href=" + escapedHref + "&width=16&height=16&mode=square";
icon48 = H5AI.core.api() + "?action=thumb&href=" + escapedHref + "&width=96&height=46&mode=rational";
}
$label = $("<span class='label'>" + path.label + "</span>");
$a = $("<a />")
.attr("href", path.absHref)
.click(function() { onClick(path, "extended"); })
.appendTo($html)
.append($("<span class='icon small'><img " + imgClass + " src='" + icon16 + "' alt='" + path.type + "' /></span>"))
.append($("<span class='icon big'><img " + imgClass + " src='" + icon48 + "' alt='" + path.type + "' /></span>"))
.append($label)
.append($("<span class='date' data-time='" + path.time + "'></span>"))
.append($("<span class='size' data-bytes='" + path.size + "'></span>"));
$a.hover(
function () {
if ($("#extended").hasClass("icons-view")) {
var $this = $(this);
$(".status.default").hide();
$(".status.dynamic")
.empty()
.append($this.find(".label").clone())
.append($("<span class='sep'>·</span>"))
.append($this.find(".date").clone())
.show();
if (!$this.closest(".entry").hasClass("folder")) {
$(".status.dynamic")
.append($("<span class='sep'>·</span>"))
.append($this.find(".size").clone());
}
}
},
function () {
$(".status.default").show();
$(".status.dynamic").empty().hide();
}
);
if (path.isParentFolder) {
if (!H5AI.core.settings.setParentFolderLabels) {
$label.addClass("l10n-parentDirectory");
}
$html.addClass("folder-parent");
}
if (!isNaN(path.status)) {
if (path.status === 200) {
$html.addClass("page");
$a.find(".icon.small img").attr("src", H5AI.core.icon("folder-page"));
$a.find(".icon.big img").attr("src", H5AI.core.icon("folder-page", true));
} else {
$html.addClass("error");
$label.append($("<span class='hint'> " + path.status + " </span>"));
}
}
if (path.html.$extended) {
path.html.$extended.replaceWith($html);
H5AI.core.formatDates();
}
path.html.$extended = $html;
return $html;
},
updateTreeHtml = function (path) {
var $html, $blank, $a, $indicator, $ul, idx;
$html = $("<div class='entry' />")
.data("path", path)
.addClass(path.isFolder ? "folder" : "file");
$blank = $("<span class='blank' />").appendTo($html);
$a = $("<a />")
.attr("href", path.absHref)
.click(function() { onClick(path, "tree"); })
.appendTo($html)
.append($("<span class='icon'><img src='" + H5AI.core.icon(path.type) + "' /></span>"))
.append($("<span class='label'>" + path.label + "</span>"));
if (path.isFolder) {
// indicator
if (path.status === undefined || !path.isEmpty()) {
$indicator = $("<span class='indicator initiated'><img src='" + H5AI.core.image("tree") + "' /></span>")
.click(function (event) {
var $entry = $indicator.closest(".entry"); // $html
if ($indicator.hasClass("unknown")) {
H5AI.connector.fetchStatusAndContent(path.absHref, false, function (status, content) {
path.status = status;
path.content = content;
path.treeOpen = true;
$("#tree").get(0).updateScrollbar(true);
updateTreeHtml(path);
$("#tree").get(0).updateScrollbar();
});
} else if ($indicator.hasClass("open")) {
path.treeOpen = false;
$indicator.removeClass("open");
$("#tree").get(0).updateScrollbar(true);
$entry.find("> ul.content").slideUp(function() {
$("#tree").get(0).updateScrollbar();
});
} else {
path.treeOpen = true;
$indicator.addClass("open");
$("#tree").get(0).updateScrollbar(true);
$entry.find("> ul.content").slideDown(function() {
$("#tree").get(0).updateScrollbar();
});
}
});
if (path.status === undefined) {
$indicator.addClass("unknown");
} else if (path.treeOpen) {
$indicator.addClass("open");
}
$blank.replaceWith($indicator);
}
// is path the domain?
if (path.isDomain) {
$html.addClass("domain");
$a.find(".icon img").attr("src", H5AI.core.icon("folder-home"));
}
// is path the current folder?
if (path.isCurrentFolder) {
$html.addClass("current");
$a.find(".icon img").attr("src", H5AI.core.icon("folder-open"));
}
// does it have subfolders?
if (!path.isEmpty()) {
$ul = $("<ul class='content' />").appendTo($html);
$.each(path.content, function (idx, entry) {
$("<li />").append(updateTreeHtml(entry)).appendTo($ul);
});
if (path.status === undefined || !path.treeOpen) {
$ul.hide();
}
}
// reflect folder status
if (!isNaN(path.status)) {
if (path.status === 200) {
$a.find(".icon img").attr("src", H5AI.core.icon("folder-page"));
$a.append($("<span class='hint'><img src='" + H5AI.core.image("page") + "' /></span>"));
} else {
$html.addClass("error");
$a.append($("<span class='hint'>" + path.status + "</span>"));
}
}
}
if (path.html.$tree) {
path.html.$tree.replaceWith($html);
}
path.html.$tree = $html;
return $html;
},
updateHtml = function (path) {
updateCrumbHtml(path);
updateExtendedHtml(path);
updateTreeHtml(path);
};
return {
updateCrumbHtml: updateCrumbHtml,
updateExtendedHtml: updateExtendedHtml,
updateTreeHtml: updateTreeHtml,
updateHtml: updateHtml
};
}());
}(jQuery, H5AI));

View File

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

View File

@ -1,158 +0,0 @@
(function ($, H5AI) {
H5AI.sort = (function () {
var type = function (entry) {
var $entry = $(entry);
if ($entry.hasClass("folder-parent")) {
return 0;
} else if ($entry.hasClass("folder")) {
return 1;
}
return 2;
},
cmp = function (entry1, entry2, rev, getVal) {
var res, val1, val2;
res = type(entry1) - type(entry2);
if (res !== 0) {
return res;
}
val1 = getVal(entry1);
val2 = getVal(entry2);
if (val1 < val2) {
return rev ? 1 : -1;
} else if (val1 > val2) {
return rev ? -1 : 1;
}
return 0;
},
cmpName = function (entry1, entry2) {
return cmp(entry1, entry2, false, function (entry) {
return $(entry).find(".label").text().toLowerCase();
});
},
cmpTime = function (entry1, entry2) {
return cmp(entry1, entry2, false, function (entry) {
return $(entry).find(".date").data("time");
});
},
cmpSize = function (entry1, entry2) {
return cmp(entry1, entry2, false, function (entry) {
return $(entry).find(".size").data("bytes");
});
},
cmpNameRev = function (entry1, entry2) {
return cmp(entry1, entry2, true, function (entry) {
return $(entry).find(".label").text().toLowerCase();
});
},
cmpTimeRev = function (entry1, entry2) {
return cmp(entry1, entry2, true, function (entry) {
return $(entry).find(".date").data("time");
});
},
cmpSizeRev = function (entry1, entry2) {
return cmp(entry1, entry2, true, function (entry) {
return $(entry).find(".size").data("bytes");
});
},
sort = function (fn) {
$("#extended .entry").detach().sort(fn).appendTo($("#extended > ul"));
},
$all, orders,
sortBy = function (id) {
var order = orders[id];
$all.removeClass("ascending").removeClass("descending");
order.head.addClass(order.clas);
sort(order.fn);
H5AI.core.hash({sort: id});
},
init = function () {
var $ascending = $("<img src='" + H5AI.core.image("ascending") + "' class='sort ascending' alt='ascending' />"),
$descending = $("<img src='" + H5AI.core.image("descending") + "' class='sort descending' alt='descending' />"),
initialOrder = H5AI.core.hash('sort'),
$header = $("#extended li.header"),
$label = $header.find("a.label"),
$date = $header.find("a.date"),
$size = $header.find("a.size");
$all = $header.find("a.label,a.date,a.size");
orders = {
na: {
head: $label,
clas: "ascending",
fn: cmpName
},
nd: {
head: $label,
clas: "descending",
fn: cmpNameRev
},
da: {
head: $date,
clas: "ascending",
fn: cmpTime
},
dd: {
head: $date,
clas: "descending",
fn: cmpTimeRev
},
sa: {
head: $size,
clas: "ascending",
fn: cmpSize
},
sd: {
head: $size,
clas: "descending",
fn: cmpSizeRev
}
};
sortBy(initialOrder ? initialOrder : H5AI.core.settings.sortorder);
$label
.append($ascending.clone()).append($descending.clone())
.click(function (event) {
sortBy("n" + ($label.hasClass("ascending") ? "d" : "a"));
event.preventDefault();
});
$date
.prepend($ascending.clone()).prepend($descending.clone())
.click(function (event) {
sortBy("d" + ($date.hasClass("ascending") ? "d" : "a"));
event.preventDefault();
});
$size
.prepend($ascending.clone()).prepend($descending.clone())
.click(function (event) {
sortBy("s" + ($size.hasClass("ascending") ? "d" : "a"));
event.preventDefault();
});
};
return {
init: init
};
}());
}(jQuery, H5AI));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,93 @@
module.define('core/settings', [H5AI_CONFIG], function (config) {
var defaults = {
rootAbsHref: '/',
h5aiAbsHref: '/_h5ai/'
};
return _.extend({}, defaults, config.options);
});
module.define('core/types', [H5AI_CONFIG], function (config) {
var reEndsWithSlash = /\/$/,
reStartsWithDot = /^\./,
fileExts = {},
fileNames = {},
parse = function (types) {
_.each(types, function (matches, type) {
_.each(matches, function (match) {
match = match.toLowerCase();
if (reStartsWithDot.test(match)) {
fileExts[match] = type;
} else {
fileNames[match] = type;
}
});
});
},
getType = function (sequence) {
if (reEndsWithSlash.test(sequence)) {
return 'folder';
}
sequence = sequence.toLowerCase();
var slashidx = sequence.lastIndexOf('/'),
name = slashidx >= 0 ? sequence.substr(slashidx + 1) : sequence,
dotidx = sequence.lastIndexOf('.'),
ext = dotidx >= 0 ? sequence.substr(dotidx) : sequence;
return fileNames[name] || fileExts[ext] || 'unknown';
};
parse(_.extend({}, config.types));
return {
getType: getType
};
});
module.define('core/langs', [H5AI_CONFIG], function (config) {
var defaults = {
lang: 'unknown',
details: 'details',
icons: 'icons',
name: 'Name',
lastModified: 'Last modified',
size: 'Size',
parentDirectory: 'Parent Directory',
empty: 'empty',
folders: 'folders',
files: 'files',
download: 'download',
noMatch: 'no match',
dateFormat: 'YYYY-MM-DD HH:mm'
},
translations = {},
parse = function (langs) {
_.each(langs, function (trans, lang) {
translations[lang] = _.extend({}, defaults, trans);
});
};
parse(_.extend({}, config.langs));
return translations;
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,117 @@
module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format', 'core/store'], function ($, allsettings, langs, format, store) {
var defaults = {
enabled: true,
lang: 'en',
useBrowserLang: true
},
settings = _.extend({}, defaults, allsettings.l10n),
template = '<span id="langSelector">' +
'<span class="lang">en</span> - <span class="l10n-lang">english</span>' +
'<span class="langOptions"> <ul /> </span>' +
'</span>',
langOptionTemplate = '<li class="langOption" />',
storekey = 'h5ai.language',
currentLang = null,
localize = function (langs, lang, useBrowserLang) {
var storedLang = store.get(storekey),
browserLang, key;
if (langs[storedLang]) {
lang = storedLang;
} else if (useBrowserLang) {
browserLang = navigator.language || navigator.browserLanguage;
if (browserLang) {
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';
}
currentLang = langs[lang];
if (currentLang) {
$.each(currentLang, function (key, value) {
$('.l10n-' + key).text(value);
});
$('.lang').text(lang);
$('.langOption').removeClass('current');
$('.langOption.' + lang).addClass('current');
}
format.setDefaultDateFormat(currentLang.dateFormat);
$('#extended .entry .date').each(function () {
var $this = $(this);
$this.text(format.formatDate($this.data('time')));
});
},
initLangSelector = function (langs) {
var $langSelector = $(template).appendTo('#bottombar .right'),
$langOptions = $langSelector.find('.langOptions'),
$ul = $langOptions.find('ul'),
sortedLangsKeys = [];
$.each(langs, function (lang) {
sortedLangsKeys.push(lang);
});
sortedLangsKeys.sort();
$.each(sortedLangsKeys, function (idx, lang) {
$(langOptionTemplate)
.addClass(lang)
.text(lang + ' - ' + langs[lang].lang)
.appendTo($ul)
.click(function () {
store.put(storekey, lang);
localize(langs, lang, false);
});
});
$langOptions
.append($ul)
.scrollpanel();
$langSelector.hover(
function () {
$langOptions
.css('top', '-' + $langOptions.outerHeight() + 'px')
.stop(true, true)
.fadeIn();
$langOptions.get(0).updateScrollbar();
},
function () {
$langOptions
.stop(true, true)
.fadeOut();
}
);
},
init = function () {
if (!settings.enabled) {
return;
}
initLangSelector(langs);
localize(langs, settings.lang, settings.useBrowserLang);
};
init();
});

View File

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

View File

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

View File

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

View File

@ -0,0 +1,145 @@
module.define('ext/sort', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) {
var defaults = {
enabled: false,
order: 'na'
},
settings = _.extend({}, defaults, allsettings.sort),
storekey = 'h5ai.sortorder',
type = function (entry) {
var $entry = $(entry);
if ($entry.hasClass('folder-parent')) {
return 0;
} else if ($entry.hasClass('folder')) {
return 1;
}
return 2;
},
cmpFn = function (rev, getVal) {
return function (entry1, entry2) {
var res, val1, val2;
res = type(entry1) - type(entry2);
if (res !== 0) {
return res;
}
val1 = getVal(entry1);
val2 = getVal(entry2);
if (val1 < val2) {
return rev ? 1 : -1;
} else if (val1 > val2) {
return rev ? -1 : 1;
}
return 0;
};
},
getName = function (entry) {
return $(entry).find('.label').text().toLowerCase();
},
getTime = function (entry) {
return $(entry).find('.date').data('time');
},
getSize = function (entry) {
return $(entry).find('.size').data('bytes');
},
$all, orders,
sortBy = function (id) {
var order = orders[id];
store.put(storekey, id);
$all.removeClass('ascending').removeClass('descending');
order.head.addClass(order.clas);
$('#extended .entry').detach().sort(order.fn).appendTo('#extended > ul');
},
init = function () {
if (!settings.enabled) {
return;
}
var $ascending = $('<img src="' + resource.image('ascending') + '" class="sort ascending" alt="ascending" />'),
$descending = $('<img src="' + resource.image('descending') + '" class="sort descending" alt="descending" />'),
$header = $('#extended li.header'),
$label = $header.find('a.label'),
$date = $header.find('a.date'),
$size = $header.find('a.size');
$all = $header.find('a.label,a.date,a.size');
orders = {
na: {
head: $label,
clas: 'ascending',
fn: cmpFn(false, getName)
},
nd: {
head: $label,
clas: 'descending',
fn: cmpFn(true, getName)
},
da: {
head: $date,
clas: 'ascending',
fn: cmpFn(false, getTime)
},
dd: {
head: $date,
clas: 'descending',
fn: cmpFn(true, getTime)
},
sa: {
head: $size,
clas: 'ascending',
fn: cmpFn(false, getSize)
},
sd: {
head: $size,
clas: 'descending',
fn: cmpFn(true, getSize)
}
};
sortBy(store.get(storekey) || settings.order);
$label
.append($ascending.clone()).append($descending.clone())
.click(function (event) {
sortBy('n' + ($label.hasClass('ascending') ? 'd' : 'a'));
event.preventDefault();
});
$date
.prepend($ascending.clone()).prepend($descending.clone())
.click(function (event) {
sortBy('d' + ($date.hasClass('ascending') ? 'd' : 'a'));
event.preventDefault();
});
$size
.prepend($ascending.clone()).prepend($descending.clone())
.click(function (event) {
sortBy('s' + ($size.hasClass('ascending') ? 'd' : 'a'));
event.preventDefault();
});
};
init();
});

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,49 @@
module.define('h5ai-info', [jQuery, 'core/resource'], function ($, resource) {
var setCheckResult = function (id, result) {
var $ele = $(id).find('.test-result');
if (result) {
$ele.addClass('test-passed').text('yes');
} else {
$ele.addClass('test-failed').text('no');
}
},
handleChecksResponse = function (response) {
$('.test').each(function () {
setCheckResult(this, response && response[$(this).data('id')]);
});
},
checks = function () {
$.ajax({
url: resource.api(),
data: {
action: 'getchecks'
},
type: 'POST',
dataType: 'json',
success: function (response) {
handleChecksResponse(response);
},
error: function () {
handleChecksResponse();
}
});
},
init = function () {
checks();
};
init();
});

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,104 +0,0 @@
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
if(x.month||x.months){this.addMonths(x.month||x.months);}
if(x.year||x.years){this.addYears(x.year||x.years);}
if(x.day||x.days){this.addDays(x.day||x.days);}
return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
if(!x.second&&x.second!==0){x.second=-1;}
if(!x.minute&&x.minute!==0){x.minute=-1;}
if(!x.hour&&x.hour!==0){x.hour=-1;}
if(!x.day&&x.day!==0){x.day=-1;}
if(!x.month&&x.month!==0){x.month=-1;}
if(!x.year&&x.year!==0){x.year=-1;}
if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
if(x.timezone){this.setTimezone(x.timezone);}
if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
(function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
break;}
return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
rx.push(r[0]);s=r[1];}
return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){r=null;}
if(r){return r;}}
throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
rx.push(r[0]);s=r[1];}
return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
s=q[1];}
if(!r){throw new $P.Exception(s);}
if(q){throw new $P.Exception(q[1]);}
if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
if(!last&&q[1].length===0){last=true;}
if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
if(rx[1].length<best[1].length){best=rx;}
if(best[1].length===0){break;}}
if(best[0].length===0){return best;}
if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
best[1]=q[1];}
return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
return rx;};Date.Grammar={};Date.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=((s.length==3)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
if(this.now){return new Date();}
var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
if(!this.unit){this.unit="day";}
if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
this[this.unit+"s"]=this.value*orient;}
return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
if(this.month&&!this.day){this.day=1;}
return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
fn=_C[keys]=_.any.apply(null,px);}
return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.mm,g.ss],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@ -72,14 +72,14 @@
};
$element
.mousewheel(function (event, delta) {
.on('mousewheel', function (event, delta, deltaX, deltaY) {
$wrapper.scrollTop($wrapper.scrollTop() - 50 * delta);
$wrapper.scrollTop($wrapper.scrollTop() - 50 * deltaY);
update();
event.stopPropagation();
event.preventDefault();
})
.scroll(update);
.on('scroll', update);
$element.get(0).updateScrollbar = update;
$wrapper
.css({

View File

@ -0,0 +1,487 @@
/*
http://www.JSON.org/json2.js
2011-10-19
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,31 @@
// Underscore.js 1.3.1
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);

View File

@ -1,42 +1,48 @@
(function ($) {
'use strict';
/*jslint browser: true, confusion: true, regexp: true, vars: true, white: true */
/*global Modernizr, jQuery, amplify, H5AI_CONFIG */
'use strict';
/*jshint browser: true */
/*global _, amplify, Base64, H5AI_CONFIG, jQuery, Modernizr, module, moment */
var H5AI = {};
// @include "core/entry.js"
// @include "core/event.js"
// @include "core/format.js"
// @include "core/parser.js"
// @include "core/resource.js"
// @include "core/settings.js"
// @include "core/store.js"
// @include "Util.js"
// @include "Core.js"
// @include "Sort.js"
// @include "ZippedDownload.js"
// @include "Finder.js"
// @include "Context.js"
// @include "model/entry.js"
// @include "parser/apache-autoindex.js"
// @include "parser/generic-json.js"
// @include "view/extended.js"
// @include "view/spacing.js"
// @include "view/viewmode.js"
// @include "ext/crumb.js"
// @include "ext/custom.js"
// @include "ext/download.js"
// @include "ext/filter.js"
// @include "ext/folderstatus.js"
// @include "ext/l10n.js"
// @include "ext/link-hover-states.js"
// @include "ext/qrcode.js"
// @include "ext/select.js"
// @include "ext/sort.js"
// @include "ext/statusbar.js"
// @include "ext/thumbnails.js"
// @include "ext/title.js"
// @include "ext/tree.js"
// @include "h5ai-info.js"
// @include "h5ai-main.js"
// @include "Path.js"
// @include "Connector.js"
// @include "Html.js"
// @include "Extended.js"
$(function () {
var isPhp = $('html.h5ai-php').length > 0;
if (!isPhp) {
H5AI.extended.init();
}
H5AI.core.init();
H5AI.sort.init();
H5AI.finder.init();
H5AI.zippedDownload.init();
H5AI.context.init();
if (isPhp) {
$('#tree').scrollpanel();
H5AI.core.shiftTree(false, true);
}
module.require($('body').attr('id'));
});
}(jQuery));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +0,0 @@
// @include "inc/lib/jquery.min.js"
// @include "inc/lib/jquery.mousewheel.js"
// @include "inc/lib/jquery.fracs-core.min.js"
// @include "inc/lib/jquery.scrollpanel.js"
// @include "inc/lib/jquery.qrcode.js"
// @include "inc/lib/amplify.min.js"
// @include "inc/lib/base64.js"
// @include "inc/lib/date.js"
// @include "inc/main.js"

File diff suppressed because one or more lines are too long

25
src/_h5ai/js/scripts.js Normal file
View File

@ -0,0 +1,25 @@
// libs
// ----
// @include "inc/lib/modernizr-2.5.3.min.js"
// @include "inc/lib/moment-1.5.0.min.js"
// @include "inc/lib/json2.js"
// @include "inc/lib/base64.js"
// underscore libs
// ---------------
// @include "inc/lib/underscore-1.3.1.min.js"
// @include "inc/lib/module.js"
// jQuery libs
// -----------
// @include "inc/lib/jquery-1.7.1.min.js"
// @include "inc/lib/jquery.fracs-0.11.min.js"
// @include "inc/lib/jquery.mousewheel-3.0.6.js"
// @include "inc/lib/jquery.qrcode.js"
// @include "inc/lib/jquery.scrollpanel.js"
// @include "inc/lib/amplify-1.1.0.min.js"
// h5ai
// ----
// @include "inc/main.js"

View File

@ -1,150 +1,125 @@
<?php
function safe_dirname($path, $endWithSlash = false) {
$path = str_replace("\\", "/", dirname($path));
return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : ""));
require_once(str_replace("\\", "/", __DIR__) . "/inc/H5ai.php");
$h5ai = new H5ai();
$options = $h5ai->getOptions();
function json_exit($obj) {
$obj["code"] = 0;
echo json_encode($obj);
exit;
}
define("H5AI_ABS_PATH", safe_dirname(safe_dirname(__FILE__)));
function json_fail($code, $msg = "", $cond = true) {
function require_h5ai($lib) {
require_once(H5AI_ABS_PATH . $lib);
}
function fail($code, $msg, $cond = true) {
if ($cond) {
echo "$code: $msg";
echo json_encode(array("code" => $code, "msg" => $msg));
exit;
}
}
function checkKeys($keys) {
function check_keys($keys) {
$values = array();
foreach ($keys as $key) {
fail(1, "parameter '$key' is missing", !array_key_exists($key, $_REQUEST));
json_fail(101, "parameter '$key' is missing", !array_key_exists($key, $_REQUEST));
$values[] = $_REQUEST[$key];
}
return $values;
}
require_h5ai("/php/inc/H5ai.php");
$h5ai = new H5ai();
$options = $h5ai->getOptions();
list($action) = check_keys(array("action"));
list($action) = checkKeys(array("action"));
if ($action === "getthumbsrc") {
if ($action === "httpcodes") {
list($hrefs) = checkKeys(array("hrefs"));
function getHttpCodes($h5ai, $hrefs) {
$codes = array();
foreach ($hrefs as $href) {
$href = trim($href);
if (strlen($href) > 0) {
$codes[$href] = $h5ai->getHttpCode($href);
}
}
return $codes;
if (!$options["thumbnails"]["enabled"]) {
json_fail(1, "thumbnails disabled");
}
$hrefs = preg_split("/;/", $hrefs);
$codes = getHttpCodes($h5ai, $hrefs);
list($srcAbsHref, $width, $height, $mode) = check_keys(array("href", "width", "height", "mode"));
echo count($codes) === 0 ? "{}" : json_encode($codes);
}
else if ($action === "thumb") {
fail(0, "thumbs are disabled", !$options["showThumbs"]);
list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode"));
require_h5ai("/php/inc/Thumbnail.php");
require_h5ai("/php/inc/Image.php");
H5ai::req_once("/php/inc/Thumbnail.php");
H5ai::req_once("/php/inc/Image.php");
$srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref);
if (!Thumbnail::isUsable()) {
Image::showImage($srcAbsPath);
exit;
json_fail(2, "thumbnails not supported");
}
$thumbnail = new Thumbnail($h5ai, $srcAbsHref, $mode, $width, $height);
$thumbnail->create(1);
if (file_exists($thumbnail->getPath())) {
Image::showImage($thumbnail->getPath());
} else {
$image = new Image();
$image->setSource($srcAbsPath);
$image->thumb($mode, $width, $height);
$image->showDest();
if (!file_exists($thumbnail->getPath())) {
json_fail(3, "thumbnail creation failed");
}
json_exit(array("absHref" => $thumbnail->getHref()));
}
else if ($action === "tree") {
else if ($action === "archive") {
list($href) = checkKeys(array("href"));
json_fail(1, "downloads disabled", !$options["download"]["enabled"]);
require_h5ai("/php/inc/Tree.php");
list($execution, $format, $hrefs) = check_keys(array("execution", "format", "hrefs"));
$absHref = trim($href);
$absPath = $h5ai->getAbsPath($absHref);
$tree = new TreeEntry($h5ai, $absPath, $absHref);
$tree->loadContent();
echo $tree->contentToHtml();
}
else if ($action === "zip") {
fail(0, "zipped download is disabled", !$options["zippedDownload"]);
list($hrefs) = checkKeys(array("hrefs"));
require_h5ai("/php/inc/ZipIt.php");
$zipit = new ZipIt($h5ai);
H5ai::req_once("/php/inc/Archive.php");
$archive = new Archive($h5ai);
$hrefs = explode(":", trim($hrefs));
$zipFile = $zipit->zip($hrefs);
$target = $archive->create($execution, $format, $hrefs);
if (is_string($zipFile)) {
$response = array('status' => 'ok', 'id' => basename($zipFile), 'size' => filesize($zipFile));
} else {
$response = array('status' => 'failed', 'code' => $zipFile);
if (!is_string($target)) {
json_fail($target, "package creation failed");
}
echo json_encode($response);
json_exit(array("id" => basename($target), "size" => filesize($target)));
}
else if ($action === "getzip") {
else if ($action === "getarchive") {
list($id) = checkKeys(array("id"));
fail(1, "zipped file not found: " . $id, !preg_match("/^h5ai-zip-/", $id));
json_fail(1, "downloads disabled", !$options["download"]["enabled"]);
$zipFile = str_replace("\\", "/", sys_get_temp_dir()) . "/" . $id;
fail(2, "zipped file not found: " . $id, !file_exists($zipFile));
list($id, $as) = check_keys(array("id", "as"));
json_fail(2, "file not found", !preg_match("/^h5ai-selection-/", $id));
$target = H5ai::normalize_path(sys_get_temp_dir(), true) . $id;
json_fail(3, "file not found", !file_exists($target));
header("Content-Disposition: attachment; filename=\"h5ai-selection.zip\"");
header("Content-Type: application/octet-stream");
header("Content-Length: " . filesize($zipFile));
header("Content-Length: " . filesize($target));
header("Content-Disposition: attachment; filename=\"$as\"");
header("Connection: close");
readfile($zipFile);
readfile($target);
}
else if ($action === "getchecks") {
$php = $h5ai->checks["php"];
$cache = $php && $h5ai->checks["cache"];
$temp = $php && $h5ai->checks["temp"];
json_exit(array(
"php" => $php,
"cache" => $cache,
"thumbs" => $cache && $h5ai->checks["gd"],
"temp" => $temp,
"archive" => $temp && $h5ai->checks["archive"],
"tar" => $temp && $h5ai->checks["tar"],
"zip" => $temp && $h5ai->checks["zip"]
));
}
else {
fail(1, "unsupported 'action' specified");
json_fail(100, "unsupported action");
}

View File

@ -0,0 +1,131 @@
<?php
class Archive {
private static $TAR_CMD = "$(cd [ROOTDIR] && tar --no-recursion -cf [TARGET] [DIRS] [FILES])";
private static $ZIP_CMD = "$(cd [ROOTDIR] && zip [TARGET] [FILES])";
private $h5ai, $dirs, $files, $sc401;
public function __construct($h5ai) {
$this->h5ai = $h5ai;
}
public function create($execution, $format, $hrefs) {
$this->dirs = array();
$this->files = array();
$this->sc401 = false;
$this->addHrefs($hrefs);
if ($this->sc401) {
return 401;
} else if (count($this->dirs) === 0 && count($this->files) === 0) {
return 404;
}
$target = H5ai::normalize_path(sys_get_temp_dir(), true) . "h5ai-selection-" . microtime(true) . rand() . "." . $format;
try {
if ($execution === "shell") {
if ($format === "tar") {
$cmd = Archive::$TAR_CMD;
} else if ($format === "zip") {
$cmd = Archive::$ZIP_CMD;
} else {
return null;
}
$cmd = str_replace("[ROOTDIR]", "\"" . $this->h5ai->getRootAbsPath() . "\"", $cmd);
$cmd = str_replace("[TARGET]", "\"" . $target . "\"", $cmd);
$cmd = str_replace("[DIRS]", count($this->dirs) ? "\"" . implode("\" \"", array_values($this->dirs)) . "\"" : "", $cmd);
$cmd = str_replace("[FILES]", count($this->files) ? "\"" . implode("\" \"", array_values($this->files)) . "\"" : "", $cmd);
`$cmd`;
} else if ($execution === "php") {
$archive = new PharData($target);
foreach ($this->dirs as $archivedDir) {
$archive->addEmptyDir($archivedDir);
}
foreach ($this->files as $realFile => $archivedFile) {
$archive->addFile($realFile, $archivedFile); // very, very slow :/
}
}
} catch (Exeption $err) {
return 500;
}
return @filesize($target) ? $target : null;
}
private function addHrefs($hrefs) {
foreach ($hrefs as $href) {
$d = H5ai::normalize_path(dirname($href), true);
$n = basename($href);
$code = $this->h5ai->getHttpCode($d);
if ($code == 401) {
$this->sc401 = true;
}
if ($code == "h5ai" && !$this->h5ai->ignoreThisFile($n)) {
$realFile = $this->h5ai->getAbsPath($href);
$archivedFile = preg_replace("!^" . H5ai::normalize_path($this->h5ai->getRootAbsPath(), true) . "!", "", $realFile);
if (is_dir($realFile)) {
$this->addDir($realFile, $archivedFile);
} else {
$this->addFile($realFile, $archivedFile);
}
}
}
}
private function addFile($realFile, $archivedFile) {
if (is_readable($realFile)) {
$this->files[$realFile] = $archivedFile;
}
}
private function addDir($realDir, $archivedDir) {
$code = $this->h5ai->getHttpCode($this->h5ai->getAbsHref($realDir));
if ($code == 401) {
$this->sc401 = true;
}
if ($code == "h5ai") {
$this->dirs[] = $archivedDir;
$files = $this->h5ai->readDir($realDir);
foreach ($files as $file) {
$realFile = $realDir . "/" . $file;
$archivedFile = $archivedDir . "/" . $file;
if (is_dir($realFile)) {
$this->addDir($realFile, $archivedFile);
} else {
$this->addFile($realFile, $archivedFile);
}
}
}
}
}
?>

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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