Thumbnails and image preview.
24
README.md
|
@ -1,15 +1,14 @@
|
|||
# h5ai
|
||||
|
||||
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).
|
||||
Please don't use files from the `src` folder for installation.
|
||||
They need to be preprocessed to work correctly. You'll find a preprocessed
|
||||
package on the [project page](http://larsjung.de/h5ai).
|
||||
|
||||
To report a bug or make a feature request
|
||||
please create [a new issue](http://github.com/lrsjng/h5ai/issues/new).
|
||||
|
||||
* Website with download, docs and demo: <http://larsjung.de/h5ai>
|
||||
* Sources: <http://github.com/lrsjng/h5ai>
|
||||
* Q&A group: <http://groups.google.com/group/h5ai>
|
||||
|
||||
h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h5ai/blob/master/LICENSE.txt).
|
||||
|
||||
|
@ -31,7 +30,18 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h
|
|||
## Changelog
|
||||
|
||||
|
||||
### v0.19 - *2012-04-??*
|
||||
### v0.20 - *2012-05-11*
|
||||
|
||||
* adds image preview
|
||||
* adds thumbnails for video and pdf
|
||||
* adds support for lighttpd, nginx and cherokee and maybe other webservers with PHP
|
||||
* adds folder size in PHP version via shell `du`
|
||||
* fixes some localization problems
|
||||
* updates info page at `/_h5ai/`
|
||||
* switches to JSHint
|
||||
|
||||
|
||||
### v0.19 - *2012-04-19*
|
||||
|
||||
* adds lots of config options
|
||||
* changes in `config.js` and `h5ai.htaccess`
|
||||
|
@ -40,7 +50,7 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h
|
|||
* 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`
|
||||
* 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
|
||||
|
@ -54,7 +64,7 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h
|
|||
* 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 sr translation by [vBm](http://github.com/vBm)
|
||||
* adds gr translation by [xhmikosr](http://github.com/xhmikosr)
|
||||
|
||||
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
custom = true
|
||||
|
||||
|
||||
# project
|
||||
project.name = h5ai
|
||||
project.version = 0.19
|
||||
|
||||
project.version = 0.20
|
||||
|
||||
# src
|
||||
src.dir = src
|
||||
|
||||
|
||||
# build
|
||||
build.dir = build
|
||||
release.dir = release
|
||||
|
||||
|
||||
# tools
|
||||
tool.wepp = wepp
|
||||
tool.jslint = jslint
|
||||
tool.jshint = jshint
|
||||
|
||||
|
|
40
build.xml
|
@ -49,14 +49,18 @@
|
|||
<zip destfile="${release.dir}/${project.name}-${project.version}.zip" basedir="${build.dir}" />
|
||||
</target>
|
||||
|
||||
<target name="lint" depends="build-prepare">
|
||||
<wepp file="${build.dir}/_h5ai/js/inc/main.js" tofile="${build.dir}/_h5ai/js/inc/main.js" />
|
||||
<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 name="jshint" depends="init">
|
||||
<apply executable="${tool.jshint}" verbose="true" parallel="true">
|
||||
<srcfile />
|
||||
<arg line="--config jshint.json" />
|
||||
<arg line="--show-non-errors" />
|
||||
<fileset dir="${src.dir}/_h5ai/js/inc">
|
||||
<patternset>
|
||||
<include name="**/*.js" />
|
||||
<exclude name="lib/**/*" />
|
||||
</patternset>
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
|
||||
|
@ -107,24 +111,4 @@
|
|||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="jslint">
|
||||
<attribute name="files" />
|
||||
<sequential>
|
||||
<echo>JSLint @{files}</echo>
|
||||
<exec executable="${tool.jslint}" failonerror="false">
|
||||
<arg line="@{files}" />
|
||||
</exec>
|
||||
</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>
|
||||
|
|
28
jshint.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
// Enforcing Options
|
||||
"bitwise": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"forin": true,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noempty": true,
|
||||
"plusplus": true,
|
||||
"trailing": true,
|
||||
"undef": true,
|
||||
|
||||
// Environments
|
||||
"browser": true,
|
||||
|
||||
// Globals
|
||||
"predef": [
|
||||
"amplify",
|
||||
"Base64",
|
||||
"H5AI_CONFIG",
|
||||
"jQuery",
|
||||
"Modernizr",
|
||||
"module",
|
||||
"moment",
|
||||
"_"
|
||||
]
|
||||
}
|
|
@ -1,37 +1,43 @@
|
|||
|
||||
Options -Indexes
|
||||
Options -Indexes
|
||||
|
||||
AddType text/html .php
|
||||
<IfModule mod_expires.c>
|
||||
Header set Cache-Control "public"
|
||||
ExpiresActive on
|
||||
|
||||
# Perhaps better to whitelist expires rules? Perhaps.
|
||||
ExpiresDefault "access plus 1 month"
|
||||
|
||||
###########################################
|
||||
# if php doesn't get interpreted try to
|
||||
# uncomment one of the following lines
|
||||
###########################################
|
||||
# cache.manifest needs re-requests in FF 3.6 (thx Remy ~Introducing HTML5)
|
||||
ExpiresByType text/cache-manifest "access plus 0 seconds"
|
||||
|
||||
#AddHandler application/x-httpd-php .php
|
||||
#AddHandler application/x-httpd-php5 .php
|
||||
#AddHandler application/x-httpd-php52 .php
|
||||
#AddHandler application/x-httpd-php53 .php
|
||||
#AddHandler php-script .php
|
||||
#AddHandler php5-script .php
|
||||
#AddHandler php52-script .php
|
||||
#AddHandler php53-script .php
|
||||
# your document html
|
||||
ExpiresByType text/html "access plus 0 seconds"
|
||||
|
||||
# data
|
||||
ExpiresByType text/xml "access plus 0 seconds"
|
||||
ExpiresByType application/xml "access plus 0 seconds"
|
||||
ExpiresByType application/json "access plus 0 seconds"
|
||||
|
||||
# cache images, css and js for 7 days
|
||||
<IfModule headers_module>
|
||||
<FilesMatch "\.png$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
<FilesMatch "\.css$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
<FilesMatch "\.js$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
<FilesMatch "thumb-.*\.jpg$">
|
||||
Header set Cache-Control "max-age=604800, public"
|
||||
</FilesMatch>
|
||||
# media: images, video, audio
|
||||
ExpiresByType image/gif "access plus 1 month"
|
||||
ExpiresByType image/png "access plus 1 month"
|
||||
ExpiresByType image/jpg "access plus 1 month"
|
||||
ExpiresByType image/jpeg "access plus 1 month"
|
||||
ExpiresByType video/ogg "access plus 1 month"
|
||||
ExpiresByType audio/ogg "access plus 1 month"
|
||||
ExpiresByType video/mp4 "access plus 1 month"
|
||||
ExpiresByType video/webm "access plus 1 month"
|
||||
|
||||
# webfonts
|
||||
ExpiresByType font/truetype "access plus 1 month"
|
||||
ExpiresByType font/opentype "access plus 1 month"
|
||||
ExpiresByType font/woff "access plus 1 month"
|
||||
ExpiresByType image/svg+xml "access plus 1 month"
|
||||
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
|
||||
|
||||
# css and javascript
|
||||
ExpiresByType text/css "access plus 1 month"
|
||||
ExpiresByType application/javascript "access plus 1 month"
|
||||
ExpiresByType text/javascript "access plus 1 month"
|
||||
</IfModule>
|
||||
|
||||
|
|
|
@ -3,20 +3,13 @@
|
|||
# customized .htaccess
|
||||
################################
|
||||
|
||||
# Options +Indexes
|
||||
# Options +FollowSymLinks
|
||||
Options +Indexes
|
||||
Options +FollowSymLinks
|
||||
|
||||
HeaderName /_h5ai/apache/h5ai-header.html
|
||||
ReadmeName /_h5ai/apache/h5ai-footer.html
|
||||
|
||||
HeaderName /_h5ai/header.html
|
||||
|
||||
# pure JavaScript version
|
||||
ReadmeName /_h5ai/footer.html
|
||||
|
||||
# PHP version
|
||||
# ReadmeName /_h5ai/footer.php
|
||||
|
||||
|
||||
IndexIgnore _h5ai*
|
||||
IndexIgnore _h5ai*
|
||||
|
||||
IndexOptions Charset=UTF-8
|
||||
IndexOptions FancyIndexing
|
|
@ -13,8 +13,7 @@
|
|||
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
|
||||
<link rel="stylesheet" href="/_h5ai/css/styles.css">
|
||||
<script src="/_h5ai/config.js"></script>
|
||||
<script src="/_h5ai/js/scripts.js"></script>
|
||||
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
|
||||
</head>
|
||||
<body id="h5ai-main">
|
||||
<div id="topbar" class="clearfix">
|
||||
|
@ -32,9 +31,12 @@
|
|||
<span class="right"></span>
|
||||
<span class="center"></span>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
<script>window.jQuery || document.write('<script src="/_h5ai/js/jquery-1.7.2.min.js"><\/script>')</script>
|
||||
<script src="/_h5ai/config.js"></script>
|
||||
<script src="/_h5ai/js/scripts.js"></script>
|
||||
<div id="data-apache-autoindex" class="hideOnJs">
|
||||
<!--
|
||||
The following code was generated by Apache's autoindex module. It is not valid HTML5, but this
|
||||
section gets removed from the DOM tree as soon as its information is parsed. The actual page
|
||||
should render as valid HTML5, even if the produced source is not valid HTML5.
|
||||
The following code was generated by Apache's autoindex module. It is not valid HTML5, but gets
|
||||
removed from the DOM tree as soon as possible. The actual page should render as valid HTML5.
|
||||
-->
|
2
src/_h5ai/cache/README.md
vendored
|
@ -1,7 +1,7 @@
|
|||
# Cache
|
||||
|
||||
This directory is used for server side caching. To use caching make this
|
||||
directory writable for Apache.
|
||||
directory writable for your webserver.
|
||||
|
||||
There is no critical data in here. You can savely remove any content. This
|
||||
will clear the cache.
|
||||
|
|
|
@ -77,9 +77,9 @@ var H5AI_CONFIG = {
|
|||
* Supported formats: "tar", "zip".
|
||||
*/
|
||||
"download": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"execution": "shell",
|
||||
"format": "zip"
|
||||
"format": "tar"
|
||||
},
|
||||
|
||||
/*
|
||||
|
@ -91,6 +91,15 @@ var H5AI_CONFIG = {
|
|||
"enabled": true
|
||||
},
|
||||
|
||||
/*
|
||||
* Requires PHP on the server.
|
||||
* Calc the size of folders.
|
||||
* Depends on du.
|
||||
*/
|
||||
"foldersize": {
|
||||
"enabled": false
|
||||
},
|
||||
|
||||
/*
|
||||
* Associative array of folders and their HTTP status codes to
|
||||
* avoid HEAD requests to that folders. The key (folder) must start
|
||||
|
@ -127,6 +136,26 @@ var H5AI_CONFIG = {
|
|||
"enabled": true
|
||||
},
|
||||
|
||||
/*
|
||||
* Shows the server mode in the bottom left corner.
|
||||
* display values:
|
||||
* 0: only show mode
|
||||
* 1: mode and servername
|
||||
* 2: mode, servername and -version
|
||||
*/
|
||||
"mode": {
|
||||
"enabled": true,
|
||||
"display": 2
|
||||
},
|
||||
|
||||
/*
|
||||
* Show an image preview on click.
|
||||
*/
|
||||
"preview-img": {
|
||||
"enabled": true,
|
||||
"types": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"]
|
||||
},
|
||||
|
||||
/*
|
||||
* Show QRCodes on hovering files.
|
||||
*/
|
||||
|
@ -164,10 +193,15 @@ var H5AI_CONFIG = {
|
|||
* Requires PHP on the server.
|
||||
* Show thumbnails for image files. Needs the "/_h5ai/cache" folder to be
|
||||
* writable for the Apache Server.
|
||||
* - img thumbnails depend on PHP-GD
|
||||
* - mov thumbnails depend on ffmpeg
|
||||
* - doc thumbnails depend on convert
|
||||
*/
|
||||
"thumbnails": {
|
||||
"enabled": true,
|
||||
"types": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
|
||||
"enabled": false,
|
||||
"img": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
|
||||
"mov": ["video"],
|
||||
"doc": ["pdf", "ps"],
|
||||
"delay": 1000
|
||||
},
|
||||
|
||||
|
@ -240,6 +274,7 @@ var H5AI_CONFIG = {
|
|||
"playlist": [".m3u", ".m3u8", ".pls"],
|
||||
"png": [".png"],
|
||||
"pres": [".odp", ".otp", ".pps", ".ppt", ".pptx"],
|
||||
"ps": [".ps"],
|
||||
"psd": [".psd"],
|
||||
"py": [".py"],
|
||||
"rar": [".rar"],
|
||||
|
@ -413,7 +448,8 @@ var H5AI_CONFIG = {
|
|||
"folders": "mapes",
|
||||
"files": "faili",
|
||||
"download": "lejupielādēt",
|
||||
"noMatch": "nav sakritības"
|
||||
"noMatch": "nav sakritības",
|
||||
"dateFormat": "YYYY-MM-DD HH:mm"
|
||||
},
|
||||
|
||||
"nb": {
|
||||
|
|
|
@ -22,8 +22,13 @@ $H5AI_CONFIG = array(
|
|||
* http://www.php.net/manual/en/function.preg-match.php
|
||||
*/
|
||||
"IGNORE" => array(),
|
||||
"IGNORE_PATTERNS" => array("/^\\./", "/^_h5ai/")
|
||||
"IGNORE_PATTERNS" => array("/^\\./", "/^_h5ai/"),
|
||||
|
||||
/*
|
||||
* Folders that contain one of these files will be considered
|
||||
* as none h5ai folders.
|
||||
*/
|
||||
"INDEX_FILES" => array("index.html", "index.htm", "index.php")
|
||||
);
|
||||
|
||||
?>
|
|
@ -1,5 +1,17 @@
|
|||
|
||||
#extended.details-view {
|
||||
#selection-rect {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
border: 1px dashed rgba(240,100,0,0.5);
|
||||
background-color: rgba(240,100,0,0.2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#extended.view-details {
|
||||
display: none;
|
||||
|
||||
ul {
|
||||
|
@ -49,7 +61,7 @@
|
|||
color: #555;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
|
||||
&:hover, &.hover {
|
||||
background-color: #f6f6f6;
|
||||
|
@ -83,11 +95,6 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
&.folder {
|
||||
.size {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.icon, .label, .date, .size {
|
||||
padding: 6px;
|
||||
|
@ -98,12 +105,13 @@
|
|||
left: 0;
|
||||
top: -2px;
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
&.thumb {
|
||||
// border: 1px solid #ddd;
|
||||
.box-shadow(0 0 0 1px #ddd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,18 +156,124 @@
|
|||
}
|
||||
|
||||
|
||||
#selection-rect {
|
||||
|
||||
|
||||
#extended.view-list {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
border: 1px dashed rgba(240,100,0,0.5);
|
||||
background-color: rgba(240,100,0,0.2);
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
clear: both;
|
||||
|
||||
&.header {
|
||||
display: none;
|
||||
}
|
||||
&.entry {
|
||||
a, a:active, a:visited {
|
||||
display: block;
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
height: 56px;
|
||||
|
||||
&:hover, &.hover {
|
||||
background-color: #f6f6f6;
|
||||
color: #e80;
|
||||
}
|
||||
}
|
||||
&.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;
|
||||
|
||||
.label {
|
||||
.hint {
|
||||
margin-left: 12px;
|
||||
font-size: 0.9em;
|
||||
color: #c55;
|
||||
}
|
||||
}
|
||||
&:hover, &.hover {
|
||||
opacity: 1;
|
||||
background-color: #f6f6f6;
|
||||
color: #e80;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.folder-parent {
|
||||
.date, .size {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.icon, .label, .date, .size {
|
||||
padding: 6px;
|
||||
}
|
||||
.icon {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -2px;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
max-width: 100px;
|
||||
max-height: 48px;
|
||||
&.thumb {
|
||||
.box-shadow(0 0 0 1px #ddd);
|
||||
}
|
||||
}
|
||||
}
|
||||
.icon.small {
|
||||
display: none;
|
||||
}
|
||||
.label {
|
||||
display: block;
|
||||
margin: 0 270px 0 106px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
.date {
|
||||
margin: 0 0 0 106px;
|
||||
text-align: right;
|
||||
width: 160px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.size {
|
||||
text-align: right;
|
||||
width: 80px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
.empty, .no-match {
|
||||
text-align: center;
|
||||
margin: 50px 0;
|
||||
color: #ddd;
|
||||
font-size: 5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.no-match {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#extended.icons-view {
|
||||
|
||||
|
||||
#extended.view-icons {
|
||||
display: none;
|
||||
padding: 3px;
|
||||
|
||||
|
@ -197,13 +311,14 @@
|
|||
}
|
||||
.icon {
|
||||
display: block;
|
||||
height: 48px;
|
||||
margin-bottom: 6px;
|
||||
|
||||
img {
|
||||
max-width: 100px;
|
||||
height: 48px;
|
||||
margin-bottom: 8px;
|
||||
max-height: 48px;
|
||||
&.thumb {
|
||||
// border: 1px solid #ddd;
|
||||
.box-shadow(0 0 0 1px #ddd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,17 @@ body#h5ai-info {
|
|||
font-family: 'Miltonian Tattoo';
|
||||
font-weight: normal;
|
||||
}
|
||||
.build-version {
|
||||
display: block;
|
||||
// font-size: 0.9em;
|
||||
// color: #aaa;
|
||||
}
|
||||
.build-stamp {
|
||||
display: block;
|
||||
margin-top: 0.3em;
|
||||
font-size: 0.6em;
|
||||
color: #aaa;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3.6em;
|
||||
margin: 0.9em 0 0 0;
|
||||
|
@ -55,6 +66,13 @@ body#h5ai-info {
|
|||
color: #a55;
|
||||
}
|
||||
}
|
||||
.test-info {
|
||||
margin: 4px 0 12px 12px;
|
||||
font-size: 0.7em;
|
||||
color: #aaa;
|
||||
width: 300px;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
#bottombar {
|
||||
|
|
125
src/_h5ai/css/inc/preview.less
Normal file
|
@ -0,0 +1,125 @@
|
|||
|
||||
#preview-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
|
||||
background-color: #111;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#preview-content {
|
||||
position: fixed;
|
||||
|
||||
#preview-img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
#preview-mov {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#preview-close {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#preview-prev {
|
||||
position: fixed;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#preview-next {
|
||||
position: fixed;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
#preview-buttons, #preview-topbuttons {
|
||||
list-style: none;
|
||||
list-style-image: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
img + span, img + input {
|
||||
margin-left: 6px;
|
||||
}
|
||||
input {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
border: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.bar-label {
|
||||
display: block;
|
||||
color: #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 10px;
|
||||
opacity: 0.7;
|
||||
.transition(all 0.2s ease-in-out);
|
||||
}
|
||||
|
||||
.bar-highlight {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
@bar-sep-border: 1px solid rgba(255,255,255,0.05);
|
||||
|
||||
.bar-button {
|
||||
.bar-label;
|
||||
cursor: pointer;
|
||||
&:hover, &.hover {
|
||||
.bar-highlight;
|
||||
}
|
||||
}
|
||||
|
||||
.bar-left {
|
||||
float: left;
|
||||
border-right: @bar-sep-border;
|
||||
}
|
||||
|
||||
.bar-right {
|
||||
float: right;
|
||||
border-left: @bar-sep-border;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#preview-topbar {
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
.vert-gradient(rgb(37,37,37), rgb(24,24,24));
|
||||
border-bottom: 1px solid rgb(27,27,27);
|
||||
}
|
||||
|
||||
|
||||
#preview-bottombar {
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
.vert-gradient(rgb(27,27,27), rgb(14,14,14));
|
||||
border-top: 1px solid rgb(45,45,45);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
#extended.icons-view {
|
||||
#extended.view-icons {
|
||||
padding: 0;
|
||||
border: none;
|
||||
margin: 0 -14px;
|
||||
|
@ -21,7 +21,7 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
#extended.details-view {
|
||||
#extended.view-details {
|
||||
.header .label, .entry .label {
|
||||
margin-right: 110px;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ body {
|
|||
@import "inc/context";
|
||||
@import "inc/apache-autoindex-table";
|
||||
|
||||
@import "inc/preview";
|
||||
|
||||
@import "inc/responsive";
|
||||
|
||||
@import "inc/h5ai-info";
|
||||
|
@ -44,4 +46,3 @@ html.oldie {
|
|||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<!-- 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>
|
BIN
src/_h5ai/icons/16x16/ps.png
Normal file
After Width: | Height: | Size: 817 B |
BIN
src/_h5ai/icons/48x48/ps.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.3 KiB |
BIN
src/_h5ai/images/preview/close.png
Normal file
After Width: | Height: | Size: 612 B |
BIN
src/_h5ai/images/preview/crumb.png
Normal file
After Width: | Height: | Size: 495 B |
BIN
src/_h5ai/images/preview/fullscreen.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
src/_h5ai/images/preview/home.png
Normal file
After Width: | Height: | Size: 524 B |
BIN
src/_h5ai/images/preview/image.png
Normal file
After Width: | Height: | Size: 589 B |
BIN
src/_h5ai/images/preview/next.png
Normal file
After Width: | Height: | Size: 492 B |
BIN
src/_h5ai/images/preview/no-fullscreen.png
Normal file
After Width: | Height: | Size: 658 B |
BIN
src/_h5ai/images/preview/play.png
Normal file
After Width: | Height: | Size: 495 B |
BIN
src/_h5ai/images/preview/prev.png
Normal file
After Width: | Height: | Size: 499 B |
BIN
src/_h5ai/images/view-list.png
Normal file
After Width: | Height: | Size: 324 B |
|
@ -6,29 +6,52 @@
|
|||
<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">
|
||||
<title>h5ai %BUILD_VERSION% server details</title>
|
||||
<meta name="description" content="h5ai server details">
|
||||
<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>
|
||||
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
|
||||
</head>
|
||||
<body id="h5ai-info">
|
||||
<h1><span class="h5ai">h5ai</span></h1>
|
||||
version %BUILD_VERSION%
|
||||
<span class="build-version">version %BUILD_VERSION%</span>
|
||||
<span class="build-stamp">%BUILD_STAMP%</span>
|
||||
<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>
|
||||
<li class="test" data-id="php"><span class="test-label">php version</span><span class="test-result">?</span>
|
||||
<div class="test-info">PHP version >= 5.2.1</div>
|
||||
</li>
|
||||
<li class="test" data-id="cache"><span class="test-label">cache</span><span class="test-result">?</span>
|
||||
<div class="test-info">_h5ai/cache writable for the server</div>
|
||||
</li>
|
||||
<li class="test" data-id="thumbs"><span class="test-label">image thumbs</span><span class="test-result">?</span>
|
||||
<div class="test-info">PHP GD extension with JPEG support available</div>
|
||||
</li>
|
||||
<li class="test" data-id="ffmpeg"><span class="test-label">movie thumbs</span><span class="test-result">?</span>
|
||||
<div class="test-info">ffmpeg executable in a shell</div>
|
||||
</li>
|
||||
<li class="test" data-id="convert"><span class="test-label">pdf thumbs</span><span class="test-result">?</span>
|
||||
<div class="test-info">convert executable in a shell</div>
|
||||
</li>
|
||||
<li class="test" data-id="temp"><span class="test-label">temp directory</span><span class="test-result">?</span>
|
||||
<div class="test-info">temporary directory writable for the server</div>
|
||||
</li>
|
||||
<li class="test" data-id="archive"><span class="test-label">php tar and zip</span><span class="test-result">?</span>
|
||||
<div class="test-info">PHP Phar extension available</div>
|
||||
</li>
|
||||
<li class="test" data-id="tar"><span class="test-label">shell tar</span><span class="test-result">?</span>
|
||||
<div class="test-info">tar executable in a shell</div>
|
||||
</li>
|
||||
<li class="test" data-id="zip"><span class="test-label">shell zip</span><span class="test-result">?</span>
|
||||
<div class="test-info">zip executable in a shell</div>
|
||||
</li>
|
||||
<li class="test" data-id="du"><span class="test-label">folder size</span><span class="test-result">?</span>
|
||||
<div class="test-info">du executable in a shell</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="bottombar" class="clearfix">
|
||||
<span class="left">
|
||||
|
@ -39,5 +62,9 @@
|
|||
<span class="right"></span>
|
||||
<span class="center"></span>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
<script>window.jQuery || document.write('<script src="/_h5ai/js/jquery-1.7.2.min.js"><\/script>')</script>
|
||||
<script src="/_h5ai/config.js"></script>
|
||||
<script src="/_h5ai/js/scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
module.define('core/entry', [jQuery, 'core/parser', 'model/entry'], function ($, parser, Entry) {
|
||||
|
||||
var absHref = document.location.pathname;
|
||||
var absHref = document.location.pathname.replace(/[^\/]*$/, '');
|
||||
|
||||
parser.parse(absHref, $('body'));
|
||||
$('#data-apache-autoindex').remove();
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
|
||||
module.define('core/parser', [jQuery], function ($) {
|
||||
|
||||
if ($('#data-apache-autoindex').length) {
|
||||
return module.require('parser/apache-autoindex');
|
||||
}
|
||||
if ($('#data-generic-json').length) {
|
||||
return module.require('parser/generic-json');
|
||||
}
|
||||
|
||||
return module.require('parser/apache-autoindex');
|
||||
return {
|
||||
id: 'none',
|
||||
parse: function () {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -3,7 +3,9 @@ module.define('core/settings', [H5AI_CONFIG], function (config) {
|
|||
|
||||
var defaults = {
|
||||
rootAbsHref: '/',
|
||||
h5aiAbsHref: '/_h5ai/'
|
||||
h5aiAbsHref: '/_h5ai/',
|
||||
server: 'unknown',
|
||||
mode: 'unknown'
|
||||
};
|
||||
|
||||
return _.extend({}, defaults, config.options);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
module.define('ext/crumb', [jQuery, 'core/settings', 'core/resource', 'core/entry'], function ($, allsettings, resource, entry) {
|
||||
|
||||
var defaults = {
|
||||
enabled: true
|
||||
enabled: false
|
||||
},
|
||||
|
||||
settings = _.extend({}, defaults, allsettings.crumb),
|
||||
|
|
|
@ -9,7 +9,7 @@ module.define('ext/download', [jQuery, 'core/settings', 'core/resource', 'core/e
|
|||
|
||||
settings = _.extend({}, defaults, allsettings.download),
|
||||
|
||||
formats = ['tar', 'zip'],
|
||||
// formats = ['tar', 'zip'],
|
||||
|
||||
downloadBtnTemplate = '<li id="download">' +
|
||||
'<a href="#">' +
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
module.define('ext/folderstatus', [jQuery, 'core/settings'], function ($, allsettings) {
|
||||
|
||||
var defaults = {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
folders: {}
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format', 'core/store'], function ($, allsettings, langs, format, store) {
|
||||
module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format', 'core/store', 'core/event'], function ($, allsettings, langs, format, store, event) {
|
||||
|
||||
var defaults = {
|
||||
enabled: true,
|
||||
|
@ -21,13 +21,12 @@ module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format',
|
|||
|
||||
localize = function (langs, lang, useBrowserLang) {
|
||||
|
||||
var storedLang = store.get(storekey),
|
||||
browserLang, key;
|
||||
var storedLang = store.get(storekey);
|
||||
|
||||
if (langs[storedLang]) {
|
||||
lang = storedLang;
|
||||
} else if (useBrowserLang) {
|
||||
browserLang = navigator.language || navigator.browserLanguage;
|
||||
var browserLang = navigator.language || navigator.browserLanguage;
|
||||
if (browserLang) {
|
||||
if (langs[browserLang]) {
|
||||
lang = browserLang;
|
||||
|
@ -110,7 +109,11 @@ module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format',
|
|||
}
|
||||
|
||||
initLangSelector(langs);
|
||||
localize(langs, settings.lang, settings.useBrowserLang);
|
||||
|
||||
event.sub('ready', function () {
|
||||
|
||||
localize(langs, settings.lang, settings.useBrowserLang);
|
||||
});
|
||||
};
|
||||
|
||||
init();
|
||||
|
|
35
src/_h5ai/js/inc/ext/mode.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
module.define('ext/mode', [jQuery, 'core/settings', 'core/parser'], function ($, allsettings, parser) {
|
||||
|
||||
var defaults = {
|
||||
enabled: false,
|
||||
display: 0
|
||||
},
|
||||
|
||||
settings = _.extend({}, defaults, allsettings.mode),
|
||||
|
||||
init = function () {
|
||||
|
||||
if (!settings.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var info = '';
|
||||
|
||||
if (parser.mode) {
|
||||
info += parser.mode;
|
||||
}
|
||||
if (settings.display > 0 && parser.server.name) {
|
||||
info += (info ? ' on ' : '') + parser.server.name;
|
||||
}
|
||||
if (settings.display > 1 && parser.server.version) {
|
||||
info += (info ? '-' : '') + parser.server.version;
|
||||
}
|
||||
|
||||
if (info) {
|
||||
$('#h5ai-reference').append(' (' + info + ')');
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
});
|
248
src/_h5ai/js/inc/ext/preview-img.js
Normal file
|
@ -0,0 +1,248 @@
|
|||
|
||||
module.define('ext/preview-img', [jQuery, 'core/settings', 'core/resource', 'core/store', 'core/entry'], function ($, allsettings, resource, store, entry) {
|
||||
|
||||
var defaults = {
|
||||
enabled: false,
|
||||
types: ['bmp', 'gif', 'ico', 'image', 'jpg', 'png', 'tiff']
|
||||
},
|
||||
|
||||
settings = _.extend({}, defaults, allsettings['preview-img']),
|
||||
|
||||
template = '<div id="preview-overlay" class="noSelection">' +
|
||||
'<div id="preview-content">' +
|
||||
'<img id="preview-img" />' +
|
||||
'</div>' +
|
||||
'<div id="preview-close" />' +
|
||||
'<div id="preview-prev" />' +
|
||||
'<div id="preview-next" />' +
|
||||
'<div id="preview-bottombar" class="clearfix">' +
|
||||
'<ul id="preview-buttons">' +
|
||||
'<li id="preview-bar-size" class="bar-left bar-label"></li>' +
|
||||
'<li id="preview-bar-percent" class="bar-left bar-label"></li>' +
|
||||
'<li id="preview-bar-label" class="bar-left bar-label"></li>' +
|
||||
'<li id="preview-bar-close" class="bar-right bar-button"><img src="' + resource.image('preview/close') + '" /></li>' +
|
||||
'<li id="preview-bar-original" class="bar-right"><a class="bar-button" target="_blank"><img src="' + resource.image('preview/image') + '" /></a></li>' +
|
||||
'<li id="preview-bar-fullscreen" class="bar-right bar-button"><img src="' + resource.image('preview/fullscreen') + '" /></li>' +
|
||||
'<li id="preview-bar-next" class="bar-right bar-button"><img src="' + resource.image('preview/next') + '" /></li>' +
|
||||
'<li id="preview-bar-idx" class="bar-right bar-label"></li>' +
|
||||
'<li id="preview-bar-prev" class="bar-right bar-button"><img src="' + resource.image('preview/prev') + '" /></li>' +
|
||||
'</ul>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
|
||||
storekey = 'h5ai.preview-img.isFullscreen',
|
||||
|
||||
currentEntries = [],
|
||||
currentIdx = 0,
|
||||
isFullscreen = store.get(storekey) || false,
|
||||
|
||||
adjustSize = function () {
|
||||
|
||||
var rect = $(window).fracs('viewport'),
|
||||
$container = $('#preview-content'),
|
||||
$img = $('#preview-img'),
|
||||
margin = isFullscreen ? 0 : 20,
|
||||
barheight = isFullscreen ? 0 : 31;
|
||||
|
||||
$container.css({
|
||||
width: rect.width - 2 * margin,
|
||||
height: rect.height - 2 * margin - barheight,
|
||||
left: margin,
|
||||
top: margin
|
||||
});
|
||||
|
||||
var lr = ($container.width() - $img.width()) / 2,
|
||||
tb = ($container.height() - $img.height()) / 2;
|
||||
|
||||
$img.css({
|
||||
margin: '' + tb + 'px ' + lr + 'px'
|
||||
});
|
||||
|
||||
rect = $img.fracs('rect');
|
||||
if (!rect) {
|
||||
// console.log('RECT FAILED!');
|
||||
return;
|
||||
}
|
||||
rect = rect.relativeTo($('#preview-overlay').fracs('rect'));
|
||||
|
||||
$('#preview-prev').css({
|
||||
'left': rect.left,
|
||||
'top': rect.top,
|
||||
'width': rect.width / 2,
|
||||
'height': rect.height
|
||||
});
|
||||
$('#preview-next').css({
|
||||
'left': rect.left + rect.width / 2,
|
||||
'top': rect.top,
|
||||
'width': rect.width / 2,
|
||||
'height': rect.height
|
||||
});
|
||||
},
|
||||
|
||||
preload = function (src, callback) {
|
||||
|
||||
var $hidden = $('<div><img/></div>')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
.appendTo('body'),
|
||||
$img = $hidden.find('img')
|
||||
.one('load', function () {
|
||||
|
||||
var width = $img.width(),
|
||||
height = $img.height();
|
||||
|
||||
$hidden.remove();
|
||||
|
||||
callback(width, height);
|
||||
})
|
||||
.attr('src', src);
|
||||
},
|
||||
|
||||
showImg = function (entries, idx) {
|
||||
|
||||
currentEntries = entries;
|
||||
currentIdx = (idx + currentEntries.length) % currentEntries.length;
|
||||
|
||||
var $container = $('#preview-content'),
|
||||
$img = $('#preview-img'),
|
||||
src = currentEntries[currentIdx].absHref,
|
||||
spinnerTimeout = setTimeout(function () {
|
||||
|
||||
$container.spin({
|
||||
length: 12,
|
||||
width: 4,
|
||||
radius: 24,
|
||||
color: '#ccc',
|
||||
shadow: true
|
||||
});
|
||||
}, 200);
|
||||
|
||||
$('#preview-overlay').stop(true, true).fadeIn(200);
|
||||
$('#preview-bar-idx').text('' + (currentIdx + 1) + ' / ' + currentEntries.length);
|
||||
|
||||
preload(src, function (width, height) {
|
||||
|
||||
clearTimeout(spinnerTimeout);
|
||||
$container.spin(false);
|
||||
|
||||
$img.attr('src', src).show();
|
||||
|
||||
adjustSize();
|
||||
|
||||
$('#preview-bar-label').text(currentEntries[currentIdx].label);
|
||||
$('#preview-bar-percent').text('' + (100 * $img.width() / width).toFixed(0) + '%');
|
||||
$('#preview-bar-size').text('' + width + 'x' + height);
|
||||
$('#preview-bar-idx').text('' + (currentIdx + 1) + ' / ' + currentEntries.length);
|
||||
$('#preview-bar-original').find('a').attr('href', currentEntries[currentIdx].absHref);
|
||||
});
|
||||
},
|
||||
|
||||
checkEntry = function (entry) {
|
||||
|
||||
if (entry.$extended && $.inArray(entry.type, settings.types) >= 0) {
|
||||
|
||||
var $a = entry.$extended.find('a');
|
||||
$a.on('click', function (event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var entries = _.filter(_.map($('#extended .entry'), function (entry) {
|
||||
|
||||
return $(entry).data('entry');
|
||||
}), function (entry) {
|
||||
|
||||
return _.indexOf(settings.types, entry.type) >= 0;
|
||||
});
|
||||
|
||||
showImg(entries, _.indexOf(entries, entry));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
init = function (entry) {
|
||||
|
||||
if (!settings.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(template).appendTo('body');
|
||||
|
||||
_.each(entry.content, checkEntry);
|
||||
|
||||
$('#preview-bar-prev, #preview-prev').on('click', function (event) {
|
||||
// event.stopPropagation();
|
||||
showImg(currentEntries, currentIdx - 1);
|
||||
});
|
||||
$('#preview-prev')
|
||||
.on('mouseenter', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-prev').addClass('hover');
|
||||
})
|
||||
.on('mouseleave', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-prev').removeClass('hover');
|
||||
});
|
||||
|
||||
$('#preview-bar-next, #preview-next').on('click', function (event) {
|
||||
// event.stopPropagation();
|
||||
showImg(currentEntries, currentIdx + 1);
|
||||
});
|
||||
$('#preview-next')
|
||||
.on('mouseenter', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-next').addClass('hover');
|
||||
})
|
||||
.on('mouseleave', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-next').removeClass('hover');
|
||||
});
|
||||
|
||||
$('#preview-bar-close, #preview-close').on('click', function () {
|
||||
// event.stopPropagation();
|
||||
$('#preview-overlay').stop(true, true).fadeOut(200);
|
||||
});
|
||||
$('#preview-close')
|
||||
.on('mouseenter', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-close').addClass('hover');
|
||||
})
|
||||
.on('mouseleave', function (event) {
|
||||
// event.stopPropagation();
|
||||
$('#preview-bar-close').removeClass('hover');
|
||||
});
|
||||
|
||||
$('#preview-bar-fullscreen').on('click', function (event) {
|
||||
// event.stopPropagation();
|
||||
isFullscreen = !isFullscreen;
|
||||
store.put(storekey, isFullscreen);
|
||||
$('#preview-bar-fullscreen').find('img').attr('src', isFullscreen ? resource.image('preview/no-fullscreen') : resource.image('preview/fullscreen'));
|
||||
adjustSize();
|
||||
});
|
||||
|
||||
$('#preview-overlay')
|
||||
.on('mousedown', function (event) {
|
||||
|
||||
event.stopPropagation();
|
||||
})
|
||||
.on('mousemove', function (event) {
|
||||
|
||||
if (isFullscreen) {
|
||||
var rect = $('#preview-overlay').fracs('rect');
|
||||
|
||||
if (rect.bottom - event.pageY < 64) {
|
||||
$('#preview-bottombar').fadeIn(200);
|
||||
} else {
|
||||
$('#preview-bottombar').fadeOut(400);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on('resize load', adjustSize);
|
||||
};
|
||||
|
||||
init(entry);
|
||||
});
|
|
@ -57,7 +57,19 @@ module.define('ext/select', [jQuery, 'core/settings', 'core/event'], function ($
|
|||
|
||||
$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);
|
||||
.animate(
|
||||
{
|
||||
left: l + w * 0.5 * shrink,
|
||||
top: t + h * 0.5 * shrink,
|
||||
width: w * (1 - shrink),
|
||||
height: h * (1 - shrink),
|
||||
opacity: 0
|
||||
},
|
||||
300,
|
||||
function () {
|
||||
$selectionRect.hide();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
selectionStart = function (event) {
|
||||
|
|
|
@ -57,9 +57,16 @@ module.define('ext/statusbar', [jQuery, 'core/settings', 'core/format', 'core/ev
|
|||
|
||||
event.sub('entry.mouseenter', function (entry) {
|
||||
|
||||
var $span = $('<span/>').append(entry.label).append(sepTemplate).append(format.formatDate(entry.time));
|
||||
if (entry.isParentFolder) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entry.isFolder()) {
|
||||
var $span = $('<span/>').append(entry.label);
|
||||
|
||||
if (_.isNumber(entry.time)) {
|
||||
$span.append(sepTemplate).append(format.formatDate(entry.time));
|
||||
}
|
||||
if (_.isNumber(entry.size)) {
|
||||
$span.append(sepTemplate).append(format.formatSize(entry.size));
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@ module.define('ext/thumbnails', [jQuery, 'core/settings', 'core/resource', 'core
|
|||
|
||||
var defaults = {
|
||||
enabled: false,
|
||||
types: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
|
||||
img: ['bmp', 'gif', 'ico', 'image', 'jpg', 'png', 'tiff'],
|
||||
mov: ['video'],
|
||||
doc: ['pdf', 'ps'],
|
||||
delay: 1000
|
||||
},
|
||||
|
||||
|
@ -21,25 +23,36 @@ module.define('ext/thumbnails', [jQuery, 'core/settings', 'core/resource', 'core
|
|||
|
||||
checkEntry = function (entry) {
|
||||
|
||||
if (entry.$extended && $.inArray(entry.type, settings.types) >= 0) {
|
||||
if (entry.$extended) {
|
||||
|
||||
var $imgSmall = entry.$extended.find('.icon.small img');
|
||||
var $imgBig = entry.$extended.find('.icon.big img');
|
||||
var type = null;
|
||||
|
||||
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'
|
||||
});
|
||||
if ($.inArray(entry.type, settings.img) >= 0) {
|
||||
type = 'img';
|
||||
} else if ($.inArray(entry.type, settings.mov) >= 0) {
|
||||
type = 'mov';
|
||||
} else if ($.inArray(entry.type, settings.doc) >= 0) {
|
||||
type = 'doc';
|
||||
}
|
||||
|
||||
if (type) {
|
||||
requestThumb(entry.$extended.find('.icon.small img'), {
|
||||
action: 'getthumbsrc',
|
||||
type: type,
|
||||
href: entry.absHref,
|
||||
mode: 'square',
|
||||
width: 16,
|
||||
height: 16
|
||||
});
|
||||
requestThumb(entry.$extended.find('.icon.big img'), {
|
||||
action: 'getthumbsrc',
|
||||
type: type,
|
||||
href: entry.absHref,
|
||||
mode: 'rational',
|
||||
width: 100,
|
||||
height: 48
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
module.define('h5ai-main', [jQuery, 'core/event'], function ($, event) {
|
||||
|
||||
module.define('h5ai-main', [jQuery, 'core/event', 'core/settings'], function ($, event, settings) {
|
||||
|
||||
event.pub('beforeView');
|
||||
|
||||
|
@ -8,8 +7,6 @@ module.define('h5ai-main', [jQuery, 'core/event'], function ($, event) {
|
|||
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) {
|
||||
|
|
4
src/_h5ai/js/inc/lib/jquery-1.7.1.min.js
vendored
|
@ -7,6 +7,15 @@
|
|||
(function (global, name) {
|
||||
'use strict';
|
||||
|
||||
var err = function (message) {
|
||||
|
||||
throw name + ' exception: ' + message;
|
||||
};
|
||||
|
||||
if (!_) {
|
||||
err(name + ' depends on underscore');
|
||||
}
|
||||
|
||||
var self = {},
|
||||
previous = global[name],
|
||||
|
||||
|
@ -18,11 +27,6 @@
|
|||
return self;
|
||||
},
|
||||
|
||||
err = function (message) {
|
||||
|
||||
throw name + ' exception: ' + message;
|
||||
},
|
||||
|
||||
definitions = {},
|
||||
modules = {},
|
||||
|
||||
|
@ -180,16 +184,14 @@
|
|||
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;
|
||||
_.extend(self, {
|
||||
noConflict: noConflict,
|
||||
log: log,
|
||||
define: define,
|
||||
require: require,
|
||||
getIds: getIds,
|
||||
isDefined: isDefined
|
||||
});
|
||||
|
||||
global[name] = self;
|
||||
|
||||
|
|
18
src/_h5ai/js/inc/lib/spin-1.2.5.min.js
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
//fgnass.github.com/spin.js#v1.2.5
|
||||
(function(a,b,c){function g(a,c){var d=b.createElement(a||"div"),e;for(e in c)d[e]=c[e];return d}function h(a){for(var b=1,c=arguments.length;b<c;b++)a.appendChild(arguments[b]);return a}function j(a,b,c,d){var g=["opacity",b,~~(a*100),c,d].join("-"),h=.01+c/d*100,j=Math.max(1-(1-a)/b*(100-h),a),k=f.substring(0,f.indexOf("Animation")).toLowerCase(),l=k&&"-"+k+"-"||"";return e[g]||(i.insertRule("@"+l+"keyframes "+g+"{"+"0%{opacity:"+j+"}"+h+"%{opacity:"+a+"}"+(h+.01)+"%{opacity:1}"+(h+b)%100+"%{opacity:"+a+"}"+"100%{opacity:"+j+"}"+"}",0),e[g]=1),g}function k(a,b){var e=a.style,f,g;if(e[b]!==c)return b;b=b.charAt(0).toUpperCase()+b.slice(1);for(g=0;g<d.length;g++){f=d[g]+b;if(e[f]!==c)return f}}function l(a,b){for(var c in b)a.style[k(a,c)||c]=b[c];return a}function m(a){for(var b=1;b<arguments.length;b++){var d=arguments[b];for(var e in d)a[e]===c&&(a[e]=d[e])}return a}function n(a){var b={x:a.offsetLeft,y:a.offsetTop};while(a=a.offsetParent)b.x+=a.offsetLeft,b.y+=a.offsetTop;return b}var d=["webkit","Moz","ms","O"],e={},f,i=function(){var a=g("style");return h(b.getElementsByTagName("head")[0],a),a.sheet||a.styleSheet}(),o={lines:12,length:7,width:5,radius:10,rotate:0,color:"#000",speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"auto",left:"auto"},p=function q(a){if(!this.spin)return new q(a);this.opts=m(a||{},q.defaults,o)};p.defaults={},m(p.prototype,{spin:function(a){this.stop();var b=this,c=b.opts,d=b.el=l(g(0,{className:c.className}),{position:"relative",zIndex:c.zIndex}),e=c.radius+c.length+c.width,h,i;a&&(a.insertBefore(d,a.firstChild||null),i=n(a),h=n(d),l(d,{left:(c.left=="auto"?i.x-h.x+(a.offsetWidth>>1):c.left+e)+"px",top:(c.top=="auto"?i.y-h.y+(a.offsetHeight>>1):c.top+e)+"px"})),d.setAttribute("aria-role","progressbar"),b.lines(d,b.opts);if(!f){var j=0,k=c.fps,m=k/c.speed,o=(1-c.opacity)/(m*c.trail/100),p=m/c.lines;!function q(){j++;for(var a=c.lines;a;a--){var e=Math.max(1-(j+a*p)%m*o,c.opacity);b.opacity(d,c.lines-a,e,c)}b.timeout=b.el&&setTimeout(q,~~(1e3/k))}()}return b},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=c),this},lines:function(a,b){function e(a,d){return l(g(),{position:"absolute",width:b.length+b.width+"px",height:b.width+"px",background:a,boxShadow:d,transformOrigin:"left",transform:"rotate("+~~(360/b.lines*c+b.rotate)+"deg) translate("+b.radius+"px"+",0)",borderRadius:(b.width>>1)+"px"})}var c=0,d;for(;c<b.lines;c++)d=l(g(),{position:"absolute",top:1+~(b.width/2)+"px",transform:b.hwaccel?"translate3d(0,0,0)":"",opacity:b.opacity,animation:f&&j(b.opacity,b.trail,c,b.lines)+" "+1/b.speed+"s linear infinite"}),b.shadow&&h(d,l(e("#000","0 0 4px #000"),{top:"2px"})),h(a,h(d,e(b.color,"0 0 1px rgba(0,0,0,.1)")));return a},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}}),!function(){function a(a,b){return g("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',b)}var b=l(g("group"),{behavior:"url(#default#VML)"});!k(b,"transform")&&b.adj?(i.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(b,c){function f(){return l(a("group",{coordsize:e+" "+e,coordorigin:-d+" "+ -d}),{width:e,height:e})}function k(b,e,g){h(i,h(l(f(),{rotation:360/c.lines*b+"deg",left:~~e}),h(l(a("roundrect",{arcsize:1}),{width:d,height:c.width,left:c.radius,top:-c.width>>1,filter:g}),a("fill",{color:c.color,opacity:c.opacity}),a("stroke",{opacity:0}))))}var d=c.length+c.width,e=2*d,g=-(c.width+c.length)*2+"px",i=l(f(),{position:"absolute",top:g,left:g}),j;if(c.shadow)for(j=1;j<=c.lines;j++)k(j,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(j=1;j<=c.lines;j++)k(j);return h(b,i)},p.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}):f=k(b,"animation")}(),a.Spinner=p})(window,document);
|
||||
|
||||
$.fn.spin = function(opts) {
|
||||
this.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data();
|
||||
|
||||
if (data.spinner) {
|
||||
data.spinner.stop();
|
||||
delete data.spinner;
|
||||
}
|
||||
if (opts !== false) {
|
||||
data.spinner = new Spinner($.extend({color: $this.css('color')}, opts)).spin(this);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
(function ($) {
|
||||
'use strict';
|
||||
/*jshint browser: true */
|
||||
/*global _, amplify, Base64, H5AI_CONFIG, jQuery, Modernizr, module, moment */
|
||||
|
||||
// @include "core/entry.js"
|
||||
// @include "core/event.js"
|
||||
|
@ -28,6 +26,8 @@
|
|||
// @include "ext/folderstatus.js"
|
||||
// @include "ext/l10n.js"
|
||||
// @include "ext/link-hover-states.js"
|
||||
// @include "ext/mode.js"
|
||||
// @include "ext/preview-img.js"
|
||||
// @include "ext/qrcode.js"
|
||||
// @include "ext/select.js"
|
||||
// @include "ext/sort.js"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
|
||||
|
||||
var domain = document.domain,
|
||||
location = document.location.pathname,
|
||||
location = document.location.pathname.replace(/[^\/]*$/, ''),
|
||||
|
||||
|
||||
// utils
|
||||
|
@ -104,10 +104,13 @@ module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
|
|||
if (split.parent) {
|
||||
this.parent = cache[split.parent] || new Entry(split.parent);
|
||||
this.parent.content[this.absHref] = this;
|
||||
if (_.keys(this.parent.content).length > 1) {
|
||||
this.parent.isContentFetched = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get = function (absHref, time, size, status) {
|
||||
get = function (absHref, time, size, status, isContentFetched) {
|
||||
|
||||
absHref = absHref || location;
|
||||
|
||||
|
@ -122,6 +125,9 @@ module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
|
|||
if (status) {
|
||||
self.status = status;
|
||||
}
|
||||
if (isContentFetched) {
|
||||
self.isContentFetched = true;
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
|
@ -146,8 +152,7 @@ module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
|
|||
|
||||
var self = cache[absHref] || new Entry(absHref);
|
||||
|
||||
if (self.isContentFetched || _.keys(self.content).length > 1) {
|
||||
self.isContentFetched = true;
|
||||
if (self.isContentFetched) {
|
||||
callback(self);
|
||||
} else {
|
||||
fetchStatus(absHref, function (self) {
|
||||
|
@ -215,7 +220,7 @@ module.define('model/entry', [jQuery, 'core/types'], function ($, types) {
|
|||
return entry.isFolder();
|
||||
}), function (entry) {
|
||||
|
||||
return entry.absHref;
|
||||
return entry.label.toLowerCase();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
module.define('parser/apache-autoindex', [jQuery, 'core/format', 'model/entry'], function ($, format, Entry) {
|
||||
module.define('parser/apache-autoindex', [jQuery, 'core/settings', 'core/format', 'model/entry'], function ($, settings, format, Entry) {
|
||||
|
||||
var parseTableRow = function (absHref, tr) {
|
||||
|
||||
|
@ -37,6 +37,11 @@ module.define('parser/apache-autoindex', [jQuery, 'core/format', 'model/entry'],
|
|||
|
||||
return {
|
||||
id: 'apache-autoindex',
|
||||
mode: 'aai',
|
||||
server: {
|
||||
name: 'apache',
|
||||
version: null
|
||||
},
|
||||
parse: parse
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
|
||||
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 parser = {
|
||||
id: 'generic-json',
|
||||
mode: null,
|
||||
server: {
|
||||
name: null,
|
||||
version: null
|
||||
}
|
||||
},
|
||||
|
||||
var parseJson = function (absHref, json) {
|
||||
parseJson = function (absHref, json) {
|
||||
|
||||
if (json.hasOwnProperty('customHeader')) {
|
||||
settings.custom.header = json.customHeader;
|
||||
|
@ -16,10 +18,16 @@ module.define('parser/generic-json', [jQuery, 'core/settings', 'model/entry'], f
|
|||
if (json.hasOwnProperty('customFooter')) {
|
||||
settings.custom.footer = json.customFooter;
|
||||
}
|
||||
if (json.hasOwnProperty('mode')) {
|
||||
parser.mode = json.mode;
|
||||
}
|
||||
if (json.hasOwnProperty('server')) {
|
||||
parser.server = json.server;
|
||||
}
|
||||
|
||||
return _.map(json.entries, function (jsonEntry) {
|
||||
|
||||
return Entry.get(jsonEntry.absHref, jsonEntry.time, jsonEntry.size, jsonEntry.status);
|
||||
return Entry.get(jsonEntry.absHref, jsonEntry.time, jsonEntry.size, jsonEntry.status, jsonEntry.content);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -41,8 +49,7 @@ module.define('parser/generic-json', [jQuery, 'core/settings', 'model/entry'], f
|
|||
return parseJsonStr(absHref, $id.text());
|
||||
};
|
||||
|
||||
return {
|
||||
id: 'generic-json',
|
||||
parse: parse
|
||||
};
|
||||
parser.parse = parse;
|
||||
|
||||
return parser;
|
||||
});
|
||||
|
|
|
@ -28,8 +28,6 @@ module.define('view/extended', [jQuery, 'core/settings', 'core/resource', 'core/
|
|||
'</ul>',
|
||||
emptyTemplate = '<div class="empty l10n-empty">empty</div>',
|
||||
|
||||
|
||||
|
||||
// updates this single entry
|
||||
update = function (entry) {
|
||||
|
||||
|
@ -43,28 +41,17 @@ module.define('view/extended', [jQuery, 'core/settings', 'core/resource', 'core/
|
|||
$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");
|
||||
$size = $html.find('.size');
|
||||
// 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);
|
||||
$imgSmall.attr('src', resource.icon(entry.type)).attr('alt', entry.type);
|
||||
$imgBig.attr('src', resource.icon(entry.type, true)).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));
|
||||
|
@ -80,6 +67,15 @@ module.define('view/extended', [jQuery, 'core/settings', 'core/resource', 'core/
|
|||
}
|
||||
}
|
||||
|
||||
if (entry.isParentFolder) {
|
||||
$imgSmall.attr('src', resource.icon('folder-parent'));
|
||||
$imgBig.attr('src', resource.icon('folder-parent', true));
|
||||
if (!settings.setParentFolderLabels) {
|
||||
$label.addClass('l10n-parentDirectory');
|
||||
}
|
||||
$html.addClass('folder-parent');
|
||||
}
|
||||
|
||||
if (entry.$extended) {
|
||||
entry.$extended.replaceWith($html);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
module.define('view/viewmode', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) {
|
||||
|
||||
var defaults = {
|
||||
modes: ['details', 'icons'],
|
||||
modes: ['details', 'list', 'icons'],
|
||||
setParentFolderLabels: false
|
||||
},
|
||||
|
||||
|
@ -10,67 +10,51 @@ module.define('view/viewmode', [jQuery, 'core/settings', 'core/resource', 'core/
|
|||
|
||||
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>'
|
||||
},
|
||||
template = '<li id="view-[MODE]" class="view">' +
|
||||
'<a href="#">' +
|
||||
'<img src="' + resource.image('view-[MODE]') + '" alt="view-[MODE]" />' +
|
||||
'<span class="l10n-[MODE]">[MODE]</span>' +
|
||||
'</a>' +
|
||||
'</li>',
|
||||
|
||||
update = function (viewmode) {
|
||||
|
||||
var $viewDetails = $('#viewdetails'),
|
||||
$viewIcons = $('#viewicons'),
|
||||
$extended = $('#extended');
|
||||
var $extended = $('#extended');
|
||||
|
||||
if (viewmode) {
|
||||
store.put(storekey, viewmode);
|
||||
} else {
|
||||
viewmode = store.get(storekey);
|
||||
}
|
||||
viewmode = $.inArray(viewmode, settings.modes) >= 0 ? viewmode : settings.modes[0];
|
||||
viewmode = _.indexOf(settings.modes, viewmode) >= 0 ? viewmode : settings.modes[0];
|
||||
store.put(storekey, 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();
|
||||
}
|
||||
_.each(defaults.modes, function (mode) {
|
||||
if (mode === viewmode) {
|
||||
$('#view-' + mode).addClass('current');
|
||||
$extended.addClass('view-' + mode).show();
|
||||
} else {
|
||||
$('#view-' + mode).removeClass('current');
|
||||
$extended.removeClass('view-' + mode);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
init = function () {
|
||||
|
||||
var $navbar = $('#navbar'),
|
||||
$extended = $('#extended');
|
||||
var $navbar = $('#navbar');
|
||||
|
||||
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])
|
||||
_.each(defaults.modes.reverse(), function (mode) {
|
||||
if (_.indexOf(settings.modes, mode) >= 0) {
|
||||
$(template.replace(/\[MODE\]/g, mode))
|
||||
.appendTo($navbar)
|
||||
.on('click', 'a', function (event) {
|
||||
update(view);
|
||||
update(mode);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update();
|
||||
update(store.get(storekey));
|
||||
};
|
||||
|
||||
init();
|
||||
|
|
4
src/_h5ai/js/jquery-1.7.2.min.js
vendored
Normal file
|
@ -1,24 +1,23 @@
|
|||
|
||||
// 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"
|
||||
// jQuery libs
|
||||
// -----------
|
||||
// @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"
|
||||
|
||||
// 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"
|
||||
// other libs
|
||||
// ----------
|
||||
// @include "inc/lib/amplify-1.1.0.min.js"
|
||||
// @include "inc/lib/moment-1.5.0.min.js"
|
||||
// @include "inc/lib/json2.js"
|
||||
// @include "inc/lib/base64.js"
|
||||
// @include "inc/lib/spin-1.2.5.min.js"
|
||||
|
||||
// h5ai
|
||||
// ----
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
require_once(str_replace("\\", "/", __DIR__) . "/inc/H5ai.php");
|
||||
require_once(str_replace("\\", "/", dirname(__FILE__)) . "/inc/H5ai.php");
|
||||
|
||||
|
||||
$h5ai = new H5ai();
|
||||
$h5ai = new H5ai(__FILE__);
|
||||
$options = $h5ai->getOptions();
|
||||
|
||||
|
||||
|
@ -41,24 +41,20 @@ if ($action === "getthumbsrc") {
|
|||
json_fail(1, "thumbnails disabled");
|
||||
}
|
||||
|
||||
list($srcAbsHref, $width, $height, $mode) = check_keys(array("href", "width", "height", "mode"));
|
||||
|
||||
H5ai::req_once("/php/inc/Thumbnail.php");
|
||||
H5ai::req_once("/php/inc/Image.php");
|
||||
|
||||
$srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref);
|
||||
|
||||
if (!Thumbnail::isUsable()) {
|
||||
H5ai::req_once("/php/inc/Thumb.php");
|
||||
if (!Thumb::is_supported()) {
|
||||
json_fail(2, "thumbnails not supported");
|
||||
}
|
||||
|
||||
$thumbnail = new Thumbnail($h5ai, $srcAbsHref, $mode, $width, $height);
|
||||
$thumbnail->create(1);
|
||||
if (!file_exists($thumbnail->getPath())) {
|
||||
list($type, $srcAbsHref, $mode, $width, $height) = check_keys(array("type", "href", "mode", "width", "height"));
|
||||
|
||||
$thumb = new Thumb($h5ai);
|
||||
$thumbHref = $thumb->thumb($type, $srcAbsHref, $mode, $width, $height);
|
||||
if ($thumbHref === null) {
|
||||
json_fail(3, "thumbnail creation failed");
|
||||
}
|
||||
|
||||
json_exit(array("absHref" => $thumbnail->getHref()));
|
||||
json_exit(array("absHref" => $thumbHref));
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,22 +98,46 @@ else if ($action === "getarchive") {
|
|||
|
||||
else if ($action === "getchecks") {
|
||||
|
||||
$php = $h5ai->checks["php"];
|
||||
$cache = $php && $h5ai->checks["cache"];
|
||||
$temp = $php && $h5ai->checks["temp"];
|
||||
$php = version_compare(PHP_VERSION, "5.2.1") >= 0;
|
||||
$archive = class_exists("PharData");
|
||||
$gd = false;
|
||||
if (function_exists("gd_info")) {
|
||||
$gdinfo = gd_info();
|
||||
$gd = array_key_exists("JPG Support", $gdinfo) && $gdinfo["JPG Support"] || array_key_exists("JPEG Support", $gdinfo) && $gdinfo["JPEG Support"];
|
||||
}
|
||||
$cache = is_writable($h5ai->getH5aiAbsPath() . "/cache");
|
||||
$temp = is_writable(sys_get_temp_dir());
|
||||
$tar = preg_match("/tar$/", `which tar`) > 0;
|
||||
$zip = preg_match("/zip$/", `which zip`) > 0;
|
||||
$convert = preg_match("/convert$/", `which convert`) > 0;
|
||||
$ffmpeg = preg_match("/ffmpeg$/", `which ffmpeg`) > 0;
|
||||
$du = preg_match("/du$/", `which du`) > 0;
|
||||
|
||||
json_exit(array(
|
||||
"php" => $php,
|
||||
"cache" => $cache,
|
||||
"thumbs" => $cache && $h5ai->checks["gd"],
|
||||
"thumbs" => $gd,
|
||||
"temp" => $temp,
|
||||
"archive" => $temp && $h5ai->checks["archive"],
|
||||
"tar" => $temp && $h5ai->checks["tar"],
|
||||
"zip" => $temp && $h5ai->checks["zip"]
|
||||
"archive" => $archive,
|
||||
"tar" => $tar,
|
||||
"zip" => $zip,
|
||||
"convert" => $convert,
|
||||
"ffmpeg" => $ffmpeg,
|
||||
"du" => $du
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
else if ($action === "getentries") {
|
||||
|
||||
list($href, $content) = check_keys(array("href", "content"));
|
||||
|
||||
$content = intval($content, 10);
|
||||
|
||||
json_exit(array("entries" => $h5ai->getEntries($href, $content)));
|
||||
}
|
||||
|
||||
|
||||
else {
|
||||
json_fail(100, "unsupported action");
|
||||
}
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
<link rel="apple-touch-icon" type="image/png" href="/_h5ai/images/h5ai-48x48.png">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ubuntu:regular,italic,bold">
|
||||
<link rel="stylesheet" href="/_h5ai/css/styles.css">
|
||||
<script src="/_h5ai/config.js"></script>
|
||||
<script src="/_h5ai/js/scripts.js"></script>
|
||||
<script src="/_h5ai/js/modernizr-2.5.3.min.js"></script>
|
||||
</head>
|
||||
<body id="h5ai-main">
|
||||
<div id="topbar" class="clearfix">
|
||||
|
@ -33,24 +32,37 @@
|
|||
<span class="right"></span>
|
||||
<span class="center"></span>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
<script>window.jQuery || document.write('<script src="/_h5ai/js/jquery-1.7.2.min.js"><\/script>')</script>
|
||||
<script src="/_h5ai/config.js"></script>
|
||||
<script src="/_h5ai/js/scripts.js"></script>
|
||||
<div id="data-generic-json" class="hidden">
|
||||
<?php if (stripos($_SERVER["REQUEST_METHOD"], "HEAD") === false) {
|
||||
|
||||
function find_h5ai($path, $h5ai) {
|
||||
$h5ai_php = str_replace("\\", "/", dirname(__FILE__)) . "/inc/H5ai.php";
|
||||
|
||||
if (!file_exists($h5ai_php)) {
|
||||
|
||||
function find_h5ai($path, $h5ai) {
|
||||
|
||||
if (file_exists($path . $h5ai)) {
|
||||
return $path . $h5ai;
|
||||
}
|
||||
|
||||
if (file_exists($path . $h5ai)) {
|
||||
return $path . $h5ai;
|
||||
} else {
|
||||
$parent = str_replace("\\", "/", dirname($path));
|
||||
if ($parent !== $path) {
|
||||
return find_h5ai($parent, $h5ai);
|
||||
}
|
||||
|
||||
error_log("h5ai not found: " . __FILE__);
|
||||
}
|
||||
error_log("h5ai not found from " . __DIR__);
|
||||
|
||||
$h5ai_php = find_h5ai(str_replace("\\", "/", dirname(__FILE__)), "/_h5ai/php/inc/H5ai.php");
|
||||
}
|
||||
|
||||
require_once(find_h5ai(str_replace("\\", "/", __DIR__), "/_h5ai/php/inc/H5ai.php"));
|
||||
$h5ai = new H5ai();
|
||||
require_once($h5ai_php);
|
||||
|
||||
$h5ai = new H5ai(__FILE__);
|
||||
echo $h5ai->getGenericJson();
|
||||
} ?>
|
||||
</div>
|
|
@ -21,7 +21,7 @@ class Archive {
|
|||
$this->files = array();
|
||||
$this->sc401 = false;
|
||||
|
||||
$this->addHrefs($hrefs);
|
||||
$this->add_hrefs($hrefs);
|
||||
|
||||
if ($this->sc401) {
|
||||
return 401;
|
||||
|
@ -55,7 +55,7 @@ class Archive {
|
|||
$archive->addEmptyDir($archivedDir);
|
||||
}
|
||||
foreach ($this->files as $realFile => $archivedFile) {
|
||||
$archive->addFile($realFile, $archivedFile); // very, very slow :/
|
||||
$archive->add_file($realFile, $archivedFile); // very, very slow :/
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class Archive {
|
|||
}
|
||||
|
||||
|
||||
private function addHrefs($hrefs) {
|
||||
private function add_hrefs($hrefs) {
|
||||
|
||||
foreach ($hrefs as $href) {
|
||||
|
||||
|
@ -79,22 +79,22 @@ class Archive {
|
|||
$this->sc401 = true;
|
||||
}
|
||||
|
||||
if ($code == "h5ai" && !$this->h5ai->ignoreThisFile($n)) {
|
||||
if ($code == "h5ai" && !$this->h5ai->is_ignored($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);
|
||||
$this->add_dir($realFile, $archivedFile);
|
||||
} else {
|
||||
$this->addFile($realFile, $archivedFile);
|
||||
$this->add_file($realFile, $archivedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function addFile($realFile, $archivedFile) {
|
||||
private function add_file($realFile, $archivedFile) {
|
||||
|
||||
if (is_readable($realFile)) {
|
||||
$this->files[$realFile] = $archivedFile;
|
||||
|
@ -102,7 +102,7 @@ class Archive {
|
|||
}
|
||||
|
||||
|
||||
private function addDir($realDir, $archivedDir) {
|
||||
private function add_dir($realDir, $archivedDir) {
|
||||
|
||||
$code = $this->h5ai->getHttpCode($this->h5ai->getAbsHref($realDir));
|
||||
if ($code == 401) {
|
||||
|
@ -112,16 +112,16 @@ class Archive {
|
|||
if ($code == "h5ai") {
|
||||
$this->dirs[] = $archivedDir;
|
||||
|
||||
$files = $this->h5ai->readDir($realDir);
|
||||
$files = $this->h5ai->read_dir($realDir);
|
||||
foreach ($files as $file) {
|
||||
|
||||
$realFile = $realDir . "/" . $file;
|
||||
$archivedFile = $archivedDir . "/" . $file;
|
||||
|
||||
if (is_dir($realFile)) {
|
||||
$this->addDir($realFile, $archivedFile);
|
||||
$this->add_dir($realFile, $archivedFile);
|
||||
} else {
|
||||
$this->addFile($realFile, $archivedFile);
|
||||
$this->add_file($realFile, $archivedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
|
||||
##############################################
|
||||
# taken from here:
|
||||
# http://www.jongales.com/blog/2009/02/18/simple-file-based-php-cache-class/
|
||||
# with minor modifications
|
||||
##############################################
|
||||
|
||||
class Cache {
|
||||
|
||||
private $dir;
|
||||
|
||||
|
||||
function __construct($dir) {
|
||||
|
||||
$this->dir = $dir;
|
||||
}
|
||||
|
||||
|
||||
private function _name($key) {
|
||||
|
||||
return $this->dir . "/" . sha1($key);
|
||||
}
|
||||
|
||||
|
||||
public function get($key, $expiration = 3600) {
|
||||
|
||||
if (!is_dir($this->dir) || !is_writable($this->dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache_path = $this->_name($key);
|
||||
|
||||
if (!@file_exists($cache_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filemtime($cache_path) < (time() - $expiration)) {
|
||||
$this->clear($key);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$fp = @fopen($cache_path, "rb")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
flock($fp, LOCK_SH);
|
||||
$cache = "";
|
||||
|
||||
if (filesize($cache_path) > 0) {
|
||||
$cache = unserialize(fread($fp, filesize($cache_path)));
|
||||
} else {
|
||||
$cache = null;
|
||||
}
|
||||
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
|
||||
return $cache;
|
||||
}
|
||||
|
||||
|
||||
public function set($key, $data) {
|
||||
|
||||
if (!is_dir($this->dir) || !is_writable($this->dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache_path = $this->_name($key);
|
||||
|
||||
if (! $fp = fopen($cache_path, "wb")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flock($fp, LOCK_EX)) {
|
||||
fwrite($fp, serialize($data));
|
||||
flock($fp, LOCK_UN);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
fclose($fp);
|
||||
@chmod($cache_path, 0777);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function clear($key) {
|
||||
|
||||
$cache_path = $this->_name($key);
|
||||
|
||||
if (file_exists($cache_path)) {
|
||||
unlink($cache_path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
class Entry {
|
||||
|
||||
private static $FOLDER_SIZE_CMD = "du -sb \"[DIR]\"";
|
||||
|
||||
|
||||
private static $cache = array();
|
||||
|
||||
|
||||
public static function getCache() {
|
||||
public static function get_cache() {
|
||||
|
||||
return Entry::$cache;
|
||||
}
|
||||
|
@ -24,16 +26,18 @@ class Entry {
|
|||
|
||||
public static function sort() {
|
||||
|
||||
uasort(Entry::$cache, function ($entry1, $entry2) {
|
||||
function cmp($entry1, $entry2) {
|
||||
|
||||
return strcasecmp($entry1->absHref, $entry2->absHref);
|
||||
});
|
||||
}
|
||||
|
||||
uasort(Entry::$cache, "cmp");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public $h5ai, $absPath, $absHref, $date, $size, $isFolder, $parent;
|
||||
public $h5ai, $absPath, $absHref, $date, $size, $isFolder, $parent, $isContentFetched;
|
||||
|
||||
|
||||
private function __construct($h5ai, $absPath, $absHref) {
|
||||
|
@ -49,6 +53,11 @@ class Entry {
|
|||
|
||||
if ($this->isFolder) {
|
||||
$this->size = null;
|
||||
$options = $h5ai->getOptions();
|
||||
if ($options["foldersize"]["enabled"]) {
|
||||
$cmd = str_replace("[DIR]", $this->absPath, Entry::$FOLDER_SIZE_CMD);
|
||||
$this->size = intval(preg_replace("/\s.*$/", "", `$cmd`), 10);
|
||||
}
|
||||
} else {
|
||||
$this->size = filesize($this->absPath);
|
||||
}
|
||||
|
@ -58,6 +67,8 @@ class Entry {
|
|||
$this->parent = Entry::get($this->h5ai, H5ai::normalize_path(dirname($this->absPath)), H5ai::normalize_path(dirname($this->absHref), true));
|
||||
}
|
||||
|
||||
$this->isContentFetched = false;
|
||||
|
||||
Entry::$cache[$this->absHref] = $this;
|
||||
}
|
||||
|
||||
|
@ -72,6 +83,7 @@ class Entry {
|
|||
|
||||
if ($withStatus && $this->isFolder) {
|
||||
$obj["status"] = $this->h5ai->getHttpCode($this->absHref);
|
||||
$obj["content"] = $this->isContentFetched;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
|
@ -92,12 +104,14 @@ class Entry {
|
|||
return $content;
|
||||
}
|
||||
|
||||
$files = $this->h5ai->readDir($this->absPath);
|
||||
$files = $this->h5ai->read_dir($this->absPath);
|
||||
foreach ($files as $file) {
|
||||
$entry = Entry::get($this->h5ai, $this->absPath . "/" . $file, $this->absHref . rawurlencode($file));
|
||||
$content[$entry->absPath] = $entry;
|
||||
}
|
||||
|
||||
$this->isContentFetched = true;
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ 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");
|
||||
|
||||
|
||||
|
@ -25,18 +24,6 @@ class H5ai {
|
|||
}
|
||||
|
||||
|
||||
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) : "";
|
||||
|
@ -51,26 +38,30 @@ class H5ai {
|
|||
}
|
||||
|
||||
|
||||
private static $H5AI_CONTENT_TYPE = "Content-Type: text/html;h5ai=";
|
||||
|
||||
|
||||
private $h5aiAbsPath,
|
||||
$rootAbsPath, $ignore, $ignoreRE,
|
||||
|
||||
|
||||
private $requested_from,
|
||||
$h5aiAbsPath,
|
||||
$rootAbsPath, $ignore_names, $ignore_patterns, $index_files,
|
||||
$config, $options,
|
||||
$rootAbsHref, $h5aiAbsHref,
|
||||
$absHref, $absPath,
|
||||
$cache;
|
||||
|
||||
public $checks;
|
||||
$absHref, $absPath;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
public function __construct($requested_from) {
|
||||
|
||||
$this->requested_from = H5ai::normalize_path($requested_from);
|
||||
|
||||
$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->ignore_names = $H5AI_CONFIG["IGNORE"];
|
||||
$this->ignore_patterns = $H5AI_CONFIG["IGNORE_PATTERNS"];
|
||||
$this->index_files = $H5AI_CONFIG["INDEX_FILES"];
|
||||
|
||||
$this->config = H5ai::load_config($this->h5aiAbsPath . "/config.js");
|
||||
$this->options = $this->config["options"];
|
||||
|
@ -78,20 +69,8 @@ class H5ai {
|
|||
$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->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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,12 +98,6 @@ class H5ai {
|
|||
}
|
||||
|
||||
|
||||
public function api() {
|
||||
|
||||
return $this->h5aiAbsHref . "php/api.php";
|
||||
}
|
||||
|
||||
|
||||
public function getOptions() {
|
||||
|
||||
return $this->options;
|
||||
|
@ -161,18 +134,18 @@ class H5ai {
|
|||
}
|
||||
|
||||
|
||||
public function ignoreThisFile($file) {
|
||||
public function is_ignored($name) {
|
||||
|
||||
// always ignore
|
||||
if ($file === "." || $file === ".." || H5ai::starts_with($file, '.ht')) {
|
||||
if ($name === "." || $name === "..") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($file, $this->ignore)) {
|
||||
if (in_array($name, $this->ignore_names)) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->ignoreRE as $re) {
|
||||
if (preg_match($re, $file)) {
|
||||
foreach ($this->ignore_patterns as $re) {
|
||||
if (preg_match($re, $name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -181,13 +154,13 @@ class H5ai {
|
|||
}
|
||||
|
||||
|
||||
public function readDir($path) {
|
||||
public function read_dir($path) {
|
||||
|
||||
$content = array();
|
||||
if (is_dir($path)) {
|
||||
if ($dir = opendir($path)) {
|
||||
while (($file = readdir($dir)) !== false) {
|
||||
if (!$this->ignoreThisFile($file)) {
|
||||
if (!$this->is_ignored($file)) {
|
||||
$content[] = $file;
|
||||
}
|
||||
}
|
||||
|
@ -200,25 +173,6 @@ class H5ai {
|
|||
|
||||
public function getHttpCode($absHref) {
|
||||
|
||||
//return $this->cachedHttpCode($absHref);
|
||||
return $this->fetchHttpCode($absHref);
|
||||
}
|
||||
|
||||
|
||||
public function cachedHttpCode($absHref) {
|
||||
|
||||
$cached = $this->cache->get($absHref);
|
||||
if ($cached === false) {
|
||||
$code = $this->fetchHttpCode($absHref);
|
||||
$cached = array("href" => $absHref, "code" => $code);
|
||||
$this->cache->set($absHref, $cached);
|
||||
}
|
||||
return $cached["code"];
|
||||
}
|
||||
|
||||
|
||||
public function fetchHttpCode($absHref) {
|
||||
|
||||
if (!is_dir($this->getAbsPath($absHref))) {
|
||||
return null;
|
||||
}
|
||||
|
@ -230,8 +184,30 @@ class H5ai {
|
|||
}
|
||||
}
|
||||
|
||||
$contentType = "Content-Type:";
|
||||
$h5aiContentType = "Content-Type: text/html;h5ai=";
|
||||
// return $this->fetchHttpCode($absHref);
|
||||
return $this->guessHttpCode($absHref);
|
||||
}
|
||||
|
||||
|
||||
public function guessHttpCode($absHref) {
|
||||
|
||||
$absPath = $this->getAbsPath($absHref);
|
||||
|
||||
foreach ($this->index_files as $if) {
|
||||
if (file_exists($absPath . "/" . $if)) {
|
||||
if ($if === "index.php") {
|
||||
$fileheader = file_get_contents($absPath . "/" . $if, false, null, -1, 50);
|
||||
return stripos($fileheader, H5ai::$H5AI_CONTENT_TYPE) === false ? 200 : "h5ai";
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
return "h5ai";
|
||||
}
|
||||
|
||||
|
||||
public function fetchHttpCode($absHref) {
|
||||
|
||||
$host = getenv("HTTP_HOST");
|
||||
$port = getenv("SERVER_PORT");
|
||||
$msg = "HEAD $absHref HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n";
|
||||
|
@ -251,10 +227,10 @@ class H5ai {
|
|||
$content = fgets($socket);
|
||||
$code = intval(trim(substr($content, 9, 4)));
|
||||
if ($code === 200) {
|
||||
while (! H5ai::starts_with($content, $contentType)) {
|
||||
while ($content !== false && stripos($content, "Content-Type") === false) {
|
||||
$content = fgets($socket);
|
||||
}
|
||||
if (H5ai::starts_with($content, $h5aiContentType)) {
|
||||
if (stripos($content, H5ai::$H5AI_CONTENT_TYPE) !== false) {
|
||||
$code = "h5ai";
|
||||
}
|
||||
}
|
||||
|
@ -272,31 +248,49 @@ class H5ai {
|
|||
|
||||
public function getGenericJson() {
|
||||
|
||||
$entries = $this->getEntries($this->absHref, 1);
|
||||
|
||||
$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) {
|
||||
$json = array(
|
||||
"entries" => $entries,
|
||||
"customHeader" => $header,
|
||||
"customFooter" => $footer,
|
||||
"mode" => $this->requested_from === $this->h5aiAbsPath . "/php/h5ai-index.php" ? "php" : "idx.php",
|
||||
"server" => array(
|
||||
"name" => strtolower(preg_replace("/\\/.*$/", "", getenv("SERVER_SOFTWARE"))),
|
||||
"version" => strtolower(preg_replace("/^.*\\//", "", preg_replace("/\\s.*$/", "", getenv("SERVER_SOFTWARE"))))
|
||||
)
|
||||
);
|
||||
|
||||
return json_encode($json) . "\n";
|
||||
}
|
||||
|
||||
|
||||
public function getEntries($absHref, $content) {
|
||||
|
||||
$folder = Entry::get($this, $this->getAbsPath($absHref), $absHref);
|
||||
if ($content > 1 && $folder !== null) {
|
||||
foreach ($folder->getContent() as $entry) {
|
||||
$entry->getContent();
|
||||
}
|
||||
$folder = $folder->getParent();
|
||||
}
|
||||
while ($content > 0 && $folder !== null) {
|
||||
$folder->getContent();
|
||||
$folder = $folder->getParent();
|
||||
}
|
||||
Entry::sort();
|
||||
|
||||
$entries = array();
|
||||
foreach(Entry::getCache() as $entry) {
|
||||
foreach (Entry::get_cache() as $entry) {
|
||||
$entries[] = $entry->toJsonObject(true);
|
||||
}
|
||||
|
||||
$json = array(
|
||||
"entries" => $entries,
|
||||
"customHeader" => $header,
|
||||
"customFooter" => $footer
|
||||
);
|
||||
|
||||
return json_encode($json) . "\n";
|
||||
return $entries;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
<?php
|
||||
|
||||
class Image {
|
||||
|
||||
private $sourceFile, $source, $width, $height, $type, $dest;
|
||||
|
||||
|
||||
public static function isUsable() {
|
||||
|
||||
return GD_VERSION != "GD_VERSION";
|
||||
}
|
||||
|
||||
|
||||
public static function showImage($filename) {
|
||||
|
||||
$image = file_get_contents($filename);
|
||||
header("content-type: image");
|
||||
echo $image;
|
||||
}
|
||||
|
||||
|
||||
public function __construct($filename = null) {
|
||||
|
||||
$this->sourceFile = null;
|
||||
$this->source = null;
|
||||
$this->width = null;
|
||||
$this->height = null;
|
||||
$this->type = null;
|
||||
|
||||
$this->dest = null;
|
||||
|
||||
$this->setSource($filename);
|
||||
}
|
||||
|
||||
|
||||
public function __destruct() {
|
||||
|
||||
$this->releaseSource();
|
||||
$this->releaseDest();
|
||||
}
|
||||
|
||||
|
||||
public function setSource($filename) {
|
||||
|
||||
$this->releaseSource();
|
||||
$this->releaseDest();
|
||||
|
||||
if (is_null($filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sourceFile = $filename;
|
||||
|
||||
list($this->width, $this->height, $this->type) = @getimagesize($this->sourceFile);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
public function showDest() {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
header("Content-type: image/jpeg");
|
||||
imagejpeg($this->dest, null, 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function saveDest($filename) {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
@imagejpeg($this->dest, $filename, 90);
|
||||
@chmod($filename, 0775);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function releaseDest() {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
@imagedestroy($this->dest);
|
||||
$this->dest = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function releaseSource() {
|
||||
|
||||
if (!is_null($this->source)) {
|
||||
@imagedestroy($this->source);
|
||||
$this->sourceFile = null;
|
||||
$this->source = null;
|
||||
$this->width = null;
|
||||
$this->height = null;
|
||||
$this->type = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
$this->dest = imagecreatetruecolor($destWidth, $destHeight);
|
||||
}
|
||||
|
||||
if (is_null($color)) {
|
||||
$color = array(255, 255, 255);
|
||||
}
|
||||
$icol = imagecolorallocate($this->dest, $color[0], $color[1], $color[2]);
|
||||
imagefill($this->dest, 0, 0, $icol);
|
||||
|
||||
imagecopyresampled($this->dest, $this->source, $destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight);
|
||||
}
|
||||
|
||||
|
||||
public function thumb($mode, $width, $height = null, $color = null) {
|
||||
|
||||
if ($height === null) {
|
||||
$height = $width;
|
||||
}
|
||||
if ($mode === "square") {
|
||||
$this->squareThumb($width);
|
||||
} elseif ($mode === "rational") {
|
||||
$this->rationalThumb($width, $height);
|
||||
} elseif ($mode === "center") {
|
||||
$this->centerThumb($width, $height, $color);
|
||||
} else {
|
||||
$this->freeThumb($width, $height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function squareThumb($width) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$a = min($this->width, $this->height);
|
||||
$x = intval(($this->width - $a) / 2);
|
||||
$y = intval(($this->height - $a) / 2);
|
||||
|
||||
$this->magic(0, 0, $x, $y, $width, $width, $a, $a);
|
||||
}
|
||||
|
||||
|
||||
public function rationalThumb($width, $height) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = 1.0 * $this->width / $this->height;
|
||||
|
||||
$h = $height;
|
||||
$w = $r * $h;
|
||||
|
||||
if ($w > $width) {
|
||||
|
||||
$w = $width;
|
||||
$h = 1.0 / $r * $w;
|
||||
}
|
||||
|
||||
$w = intval($w);
|
||||
$h = intval($h);
|
||||
|
||||
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
|
||||
}
|
||||
|
||||
|
||||
public function centerThumb($width, $height, $color = null) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = 1.0 * $this->width / $this->height;
|
||||
|
||||
$h = $height;
|
||||
$w = $r * $h;
|
||||
|
||||
if ($w > $width) {
|
||||
|
||||
$w = $width;
|
||||
$h = 1.0 / $r * $w;
|
||||
}
|
||||
|
||||
$w = intval($w);
|
||||
$h = intval($h);
|
||||
|
||||
$x = intval(($width - $w) / 2);
|
||||
$y = intval(($height - $h) / 2);
|
||||
|
||||
$this->magic($x, $y, 0, 0, $w, $h, $this->width, $this->height, $width, $height, $color);
|
||||
}
|
||||
|
||||
|
||||
public function freeThumb($width, $height) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$w = intval($width);
|
||||
$h = intval($height);
|
||||
|
||||
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
380
src/_h5ai/php/inc/Thumb.php
Normal file
|
@ -0,0 +1,380 @@
|
|||
<?php
|
||||
|
||||
class Thumb {
|
||||
|
||||
private static $FFMPEG = "ffmpeg -i \"[SOURCE]\" -an -ss 3 -vframes 1 \"[TARGET]\"";
|
||||
private static $CONVERT = "convert -strip \"[SOURCE][0]\" \"[TARGET]\"";
|
||||
|
||||
public static final function is_supported() {
|
||||
|
||||
if (!function_exists("gd_info")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$gdinfo = gd_info();
|
||||
return array_key_exists("JPG Support", $gdinfo) && $gdinfo["JPG Support"] || array_key_exists("JPEG Support", $gdinfo) && $gdinfo["JPEG Support"];
|
||||
}
|
||||
|
||||
|
||||
private $h5ai;
|
||||
|
||||
|
||||
public function __construct($h5ai) {
|
||||
|
||||
$this->h5ai = $h5ai;
|
||||
}
|
||||
|
||||
|
||||
public function thumb($type, $sourceAbsHref, $mode, $width, $height) {
|
||||
|
||||
$sourceAbsPath = $this->h5ai->getAbsPath($sourceAbsHref);
|
||||
|
||||
if ($type === "img") {
|
||||
$captureAbsPath = $sourceAbsPath;
|
||||
} else if ($type === "mov") {
|
||||
$captureAbsPath = $this->capture(Thumb::$FFMPEG, $sourceAbsPath);
|
||||
} else if ($type === "doc") {
|
||||
$captureAbsPath = $this->capture(Thumb::$CONVERT, $sourceAbsPath);
|
||||
}
|
||||
|
||||
return $this->thumb_href($captureAbsPath, $mode, $width, $height);
|
||||
}
|
||||
|
||||
|
||||
private function thumb_href($sourceAbsPath, $mode, $width, $height) {
|
||||
|
||||
if (!file_exists($sourceAbsPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = "cache/thumb-" . sha1("$sourceAbsPath-$width-$height-$mode") . ".jpg";
|
||||
// $name = "cache/thumb-" . sha1("$sourceAbsPath-$width-$height-$mode") . ".png";
|
||||
$thumbAbsHref = $this->h5ai->getH5aiAbsHref() . $name;
|
||||
$thumbAbsPath = $this->h5ai->getH5aiAbsPath() . "/" . $name;
|
||||
|
||||
if (!file_exists($thumbAbsPath) || filemtime($sourceAbsPath) >= filemtime($thumbAbsPath)) {
|
||||
$image = new Image();
|
||||
$image->setSource($sourceAbsPath);
|
||||
$image->thumb($mode, $width, $height);
|
||||
$image->saveDestJpeg($thumbAbsPath, 80);
|
||||
|
||||
// $image->saveDestPng($thumbAbsPath, 9);
|
||||
// Magic::thumb($mode, $sourceAbsPath, $thumbAbsPath, $width, $height);
|
||||
}
|
||||
|
||||
return file_exists($thumbAbsPath) ? $thumbAbsHref : null;
|
||||
}
|
||||
|
||||
|
||||
private function capture($cmd, $sourceAbsPath) {
|
||||
|
||||
if (!file_exists($sourceAbsPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$captureAbsPath = $this->h5ai->getH5aiAbsPath() . "/cache/capture-" . sha1($sourceAbsPath) . ".jpg";
|
||||
|
||||
if (!file_exists($captureAbsPath) || filemtime($sourceAbsPath) >= filemtime($captureAbsPath)) {
|
||||
$cmd = str_replace("[SOURCE]", $sourceAbsPath, $cmd);
|
||||
$cmd = str_replace("[TARGET]", $captureAbsPath, $cmd);
|
||||
`$cmd`;
|
||||
}
|
||||
|
||||
return file_exists($captureAbsPath) ? $captureAbsPath : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Magic {
|
||||
|
||||
private static $GET_SIZE_CMD = "identify -format \"%w %h\" \"[SOURCE]\"";
|
||||
private static $RESIZE_CMD = "convert -strip -transparent-color \"#ffffff\" -resize [WIDTH]x[HEIGHT] -quality 80 \"[SOURCE]\" \"[TARGET]\"";
|
||||
private static $SQUARE_CMD = "convert -strip -transparent-color \"#ffffff\" -crop [CWIDTH]x[CWIDTH]+[CLEFT]+[CTOP] -resize [WIDTH]x[WIDTH] -quality 80 \"[SOURCE]\" \"[TARGET]\"";
|
||||
|
||||
|
||||
private static final function img_size($source) {
|
||||
|
||||
$cmd = str_replace("[SOURCE]", str_replace("\"", "\\\"", $source), Magic::$GET_SIZE_CMD);
|
||||
$size = explode(" ", `$cmd`);
|
||||
$size[0] = intval($size[0]);
|
||||
$size[1] = intval($size[1]);
|
||||
return $size;
|
||||
}
|
||||
|
||||
private static final function rational($source, $target, $width, $height) {
|
||||
|
||||
$cmd = str_replace("[SOURCE]", str_replace("\"", "\\\"", $source), Magic::$RESIZE_CMD);
|
||||
$cmd = str_replace("[TARGET]", str_replace("\"", "\\\"", $target), $cmd);
|
||||
$cmd = str_replace("[WIDTH]", $width, $cmd);
|
||||
$cmd = str_replace("[HEIGHT]", $height, $cmd);
|
||||
`$cmd`;
|
||||
}
|
||||
|
||||
private static final function square($source, $target, $width) {
|
||||
|
||||
$size = Magic::img_size($source);
|
||||
$w = $size[0];
|
||||
$h = $size[1];
|
||||
|
||||
$cwidth = min($w, $h);
|
||||
$cleft = ($w - $cwidth) / 2;
|
||||
$ctop = ($h - $cwidth) / 2;
|
||||
|
||||
$cmd = str_replace("[SOURCE]", str_replace("\"", "\\\"", $source), Magic::$SQUARE_CMD);
|
||||
$cmd = str_replace("[TARGET]", str_replace("\"", "\\\"", $target), $cmd);
|
||||
$cmd = str_replace("[CWIDTH]", $cwidth, $cmd);
|
||||
$cmd = str_replace("[CLEFT]", $cleft, $cmd);
|
||||
$cmd = str_replace("[CTOP]", $ctop, $cmd);
|
||||
$cmd = str_replace("[WIDTH]", $width, $cmd);
|
||||
`$cmd`;
|
||||
}
|
||||
|
||||
public static final function thumb($mode, $source, $target, $width, $height = null, $color = null) {
|
||||
|
||||
if ($height === null) {
|
||||
$height = $width;
|
||||
}
|
||||
if ($mode === "square") {
|
||||
Magic::square($source, $target, $width);
|
||||
} elseif ($mode === "rational") {
|
||||
Magic::rational($source, $target, $width, $height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Image {
|
||||
|
||||
private $sourceFile, $source, $width, $height, $type, $dest;
|
||||
|
||||
|
||||
public static final function is_supported() {
|
||||
|
||||
if (!function_exists("gd_info")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$gdinfo = gd_info();
|
||||
return array_key_exists("JPG Support", $gdinfo) && $gdinfo["JPG Support"] || array_key_exists("JPEG Support", $gdinfo) && $gdinfo["JPEG Support"];
|
||||
}
|
||||
|
||||
|
||||
public function __construct($filename = null) {
|
||||
|
||||
$this->sourceFile = null;
|
||||
$this->source = null;
|
||||
$this->width = null;
|
||||
$this->height = null;
|
||||
$this->type = null;
|
||||
|
||||
$this->dest = null;
|
||||
|
||||
$this->setSource($filename);
|
||||
}
|
||||
|
||||
|
||||
public function __destruct() {
|
||||
|
||||
$this->releaseSource();
|
||||
$this->releaseDest();
|
||||
}
|
||||
|
||||
|
||||
public function setSource($filename) {
|
||||
|
||||
$this->releaseSource();
|
||||
$this->releaseDest();
|
||||
|
||||
if (is_null($filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sourceFile = $filename;
|
||||
|
||||
list($this->width, $this->height, $this->type) = @getimagesize($this->sourceFile);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
public function saveDestJpeg($filename, $quality = 80) {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
@imagejpeg($this->dest, $filename, $quality);
|
||||
@chmod($filename, 0775);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function saveDestPng($filename, $quality = 9) {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
@imagepng($this->dest, $filename, $quality);
|
||||
@chmod($filename, 0775);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function releaseDest() {
|
||||
|
||||
if (!is_null($this->dest)) {
|
||||
@imagedestroy($this->dest);
|
||||
$this->dest = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function releaseSource() {
|
||||
|
||||
if (!is_null($this->source)) {
|
||||
@imagedestroy($this->source);
|
||||
$this->sourceFile = null;
|
||||
$this->source = null;
|
||||
$this->width = null;
|
||||
$this->height = null;
|
||||
$this->type = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function magic($destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight, $canWidth = null, $canHeight = null, $color = null) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($canWidth === 0) {
|
||||
$canWidth = 1;
|
||||
}
|
||||
if ($canHeight === 0) {
|
||||
$canHeight = 1;
|
||||
}
|
||||
if ($destWidth === 0) {
|
||||
$destWidth = 1;
|
||||
}
|
||||
if ($destHeight === 0) {
|
||||
$destHeight = 1;
|
||||
}
|
||||
|
||||
if (!is_null($canWidth) && !is_null($canHeight)) {
|
||||
$this->dest = imagecreatetruecolor($canWidth, $canHeight);
|
||||
} else {
|
||||
$this->dest = imagecreatetruecolor($destWidth, $destHeight);
|
||||
}
|
||||
|
||||
if (is_null($color)) {
|
||||
$color = array(255, 255, 255);
|
||||
}
|
||||
$icol = imagecolorallocate($this->dest, $color[0], $color[1], $color[2]);
|
||||
imagefill($this->dest, 0, 0, $icol);
|
||||
|
||||
imagecopyresampled($this->dest, $this->source, $destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight);
|
||||
}
|
||||
|
||||
|
||||
public function thumb($mode, $width, $height = null, $color = null) {
|
||||
|
||||
if ($height === null) {
|
||||
$height = $width;
|
||||
}
|
||||
if ($mode === "square") {
|
||||
$this->squareThumb($width);
|
||||
} elseif ($mode === "rational") {
|
||||
$this->rationalThumb($width, $height);
|
||||
} elseif ($mode === "center") {
|
||||
$this->centerThumb($width, $height, $color);
|
||||
} else {
|
||||
$this->freeThumb($width, $height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function squareThumb($width) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$a = min($this->width, $this->height);
|
||||
$x = intval(($this->width - $a) / 2);
|
||||
$y = intval(($this->height - $a) / 2);
|
||||
|
||||
$this->magic(0, 0, $x, $y, $width, $width, $a, $a);
|
||||
}
|
||||
|
||||
|
||||
public function rationalThumb($width, $height) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = 1.0 * $this->width / $this->height;
|
||||
|
||||
$h = $height;
|
||||
$w = $r * $h;
|
||||
|
||||
if ($w > $width) {
|
||||
|
||||
$w = $width;
|
||||
$h = 1.0 / $r * $w;
|
||||
}
|
||||
|
||||
$w = intval($w);
|
||||
$h = intval($h);
|
||||
|
||||
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
|
||||
}
|
||||
|
||||
|
||||
public function centerThumb($width, $height, $color = null) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = 1.0 * $this->width / $this->height;
|
||||
|
||||
$h = $height;
|
||||
$w = $r * $h;
|
||||
|
||||
if ($w > $width) {
|
||||
|
||||
$w = $width;
|
||||
$h = 1.0 / $r * $w;
|
||||
}
|
||||
|
||||
$w = intval($w);
|
||||
$h = intval($h);
|
||||
|
||||
$x = intval(($width - $w) / 2);
|
||||
$y = intval(($height - $h) / 2);
|
||||
|
||||
$this->magic($x, $y, 0, 0, $w, $h, $this->width, $this->height, $width, $height, $color);
|
||||
}
|
||||
|
||||
|
||||
public function freeThumb($width, $height) {
|
||||
|
||||
if (is_null($this->source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$w = intval($width);
|
||||
$h = intval($height);
|
||||
|
||||
$this->magic(0, 0, 0, 0, $w, $h, $this->width, $this->height);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
H5ai::req_once("/php/inc/Image.php");
|
||||
|
||||
|
||||
class Thumbnail {
|
||||
|
||||
private $srcAbsHref, $srcAbsPath, $width, $height, $name, $href, $path;
|
||||
|
||||
|
||||
public static function isUsable() {
|
||||
|
||||
return Image::isUsable();
|
||||
}
|
||||
|
||||
|
||||
public function __construct($h5ai, $absHref, $mode, $width, $height) {
|
||||
|
||||
$this->h5ai = $h5ai;
|
||||
$this->srcAbsHref = $absHref;
|
||||
$this->srcAbsPath = $this->h5ai->getRootAbsPath() . urldecode($absHref);
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->mode = $mode;
|
||||
$this->name = sha1("$this->srcAbsPath-$this->width-$this->height-$this->mode");
|
||||
$this->href = $this->h5ai->getH5aiAbsHref() . "cache/thumb-" . $this->name . ".jpg";
|
||||
$this->path = $this->h5ai->getRootAbsPath() . $this->href;
|
||||
$this->liveHref = $this->h5ai->api() . "?action=thumb&href=" . $this->srcAbsHref . "&width=" . $this->width . "&height=" . $this->height . "&mode=" . $this->mode;
|
||||
}
|
||||
|
||||
|
||||
public function create($force = 0) {
|
||||
|
||||
if (
|
||||
$force === 2
|
||||
|| ($force === 1 && !file_exists($this->path))
|
||||
|| (file_exists($this->path) && filemtime($this->srcAbsPath) >= filemtime($this->path))
|
||||
) {
|
||||
$image = new Image();
|
||||
$image->setSource($this->srcAbsPath);
|
||||
$image->thumb($this->mode, $this->width, $this->height);
|
||||
$image->saveDest($this->path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getHref() {
|
||||
|
||||
return $this->href;
|
||||
}
|
||||
|
||||
|
||||
public function getPath() {
|
||||
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
|
||||
public function getLiveHref() {
|
||||
|
||||
return $this->liveHref;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|