From 71ed41fa6998048d5c2f351397af8f8882c50f10 Mon Sep 17 00:00:00 2001 From: Lars Jung Date: Mon, 16 Apr 2012 12:53:54 +0200 Subject: [PATCH] Refactored and lots of modification. See README.md. --- README.md | 20 +- build.properties | 3 +- build.xml | 15 + src/_h5ai/config.js | 257 +++++++----- src/_h5ai/config.php | 2 +- ...table.less => apache-autoindex-table.less} | 45 ++- src/_h5ai/css/inc/bottombar.less | 68 ++++ src/_h5ai/css/inc/content.less | 36 +- src/_h5ai/css/inc/extended.less | 47 +-- src/_h5ai/css/inc/footer.less | 120 ------ src/_h5ai/css/inc/h5ai-info.less | 59 +++ src/_h5ai/css/inc/l10n.less | 53 +++ src/_h5ai/css/inc/mixins.less | 2 - src/_h5ai/css/inc/responsive.less | 13 +- src/_h5ai/css/inc/splash.less | 59 --- src/_h5ai/css/inc/{nav.less => topbar.less} | 86 ++-- src/_h5ai/css/inc/tree.less | 30 +- src/_h5ai/css/styles.less | 53 +-- src/_h5ai/footer.html | 32 +- src/_h5ai/footer.php | 11 + src/_h5ai/header.html | 49 ++- src/_h5ai/header.php | 33 -- src/_h5ai/images/page.png | Bin 706 -> 564 bytes src/_h5ai/index.html | 33 +- src/_h5ai/js/inc/connector.js | 373 ------------------ src/_h5ai/js/inc/context.js | 50 --- src/_h5ai/js/inc/core.js | 311 --------------- src/_h5ai/js/inc/core/entry.js | 16 + src/_h5ai/js/inc/core/event.js | 25 ++ src/_h5ai/js/inc/core/format.js | 80 ++++ src/_h5ai/js/inc/core/parser.js | 9 + src/_h5ai/js/inc/core/resource.js | 22 ++ src/_h5ai/js/inc/core/settings.js | 32 ++ src/_h5ai/js/inc/core/store.js | 18 + src/_h5ai/js/inc/ext/crumb.js | 84 ++++ src/_h5ai/js/inc/ext/custom.js | 42 ++ src/_h5ai/js/inc/ext/filter.js | 123 ++++++ src/_h5ai/js/inc/ext/folderstatus.js | 14 + src/_h5ai/js/inc/{localize.js => ext/l10n.js} | 81 ++-- src/_h5ai/js/inc/ext/link-hover-states.js | 44 +++ src/_h5ai/js/inc/ext/qrcode.js | 56 +++ src/_h5ai/js/inc/ext/select.js | 114 ++++++ src/_h5ai/js/inc/{ => ext}/sort.js | 31 +- src/_h5ai/js/inc/ext/statusbar.js | 76 ++++ src/_h5ai/js/inc/ext/thumbnails.js | 59 +++ src/_h5ai/js/inc/ext/title.js | 27 ++ src/_h5ai/js/inc/ext/tree.js | 227 +++++++++++ src/_h5ai/js/inc/ext/zipped-download.js | 133 +++++++ src/_h5ai/js/inc/extended.js | 130 ------ src/_h5ai/js/inc/finder.js | 106 ----- src/_h5ai/js/inc/{splash.js => h5ai-info.js} | 18 +- src/_h5ai/js/inc/h5ai-main.js | 21 + src/_h5ai/js/inc/h5ai.js | 38 -- src/_h5ai/js/inc/html.js | 0 .../js/inc/lib/jquery.mousewheel-3.0.6.js | 84 ++++ src/_h5ai/js/inc/lib/jquery.mousewheel.js | 84 ---- src/_h5ai/js/inc/lib/module.js | 196 +++++++++ src/_h5ai/js/inc/main.js | 60 +-- src/_h5ai/js/inc/model/entry.js | 282 +++++++++++++ src/_h5ai/js/inc/module.js | 174 -------- src/_h5ai/js/inc/parser/apache-autoindex.js | 42 ++ src/_h5ai/js/inc/parser/generic-json.js | 48 +++ src/_h5ai/js/inc/path.js | 98 ----- src/_h5ai/js/inc/settings.js | 57 --- src/_h5ai/js/inc/util.js | 117 ------ src/_h5ai/js/inc/view/extended.js | 135 +++++++ src/_h5ai/js/inc/view/spacing.js | 35 ++ src/_h5ai/js/inc/view/viewmode.js | 77 ++++ src/_h5ai/js/inc/zip.js | 187 --------- src/_h5ai/js/modernizr-2.5.3.min.js | 4 + src/_h5ai/js/modernizr.min.js | 4 - src/_h5ai/js/scripts.js | 3 +- src/_h5ai/php/api.php | 64 +-- src/_h5ai/php/inc/Crumb.php | 55 --- src/_h5ai/php/inc/Customize.php | 35 -- src/_h5ai/php/inc/Entry.php | 105 +++++ src/_h5ai/php/inc/Extended.php | 152 ------- src/_h5ai/php/inc/H5ai.php | 275 ++++++------- src/_h5ai/php/inc/Image.php | 30 +- src/_h5ai/php/inc/Thumbnail.php | 2 +- src/_h5ai/php/inc/Tree.php | 158 -------- src/_h5ai/php/inc/ZipIt.php | 4 +- src/_h5ai/php/main.php | 28 -- src/h5ai.htaccess | 20 +- src/index.php | 59 +++ 85 files changed, 3191 insertions(+), 2969 deletions(-) rename src/_h5ai/css/inc/{table.less => apache-autoindex-table.less} (67%) create mode 100644 src/_h5ai/css/inc/bottombar.less delete mode 100644 src/_h5ai/css/inc/footer.less create mode 100644 src/_h5ai/css/inc/h5ai-info.less create mode 100644 src/_h5ai/css/inc/l10n.less delete mode 100644 src/_h5ai/css/inc/splash.less rename src/_h5ai/css/inc/{nav.less => topbar.less} (73%) create mode 100644 src/_h5ai/footer.php delete mode 100644 src/_h5ai/header.php delete mode 100644 src/_h5ai/js/inc/connector.js delete mode 100644 src/_h5ai/js/inc/context.js delete mode 100644 src/_h5ai/js/inc/core.js create mode 100644 src/_h5ai/js/inc/core/entry.js create mode 100644 src/_h5ai/js/inc/core/event.js create mode 100644 src/_h5ai/js/inc/core/format.js create mode 100644 src/_h5ai/js/inc/core/parser.js create mode 100644 src/_h5ai/js/inc/core/resource.js create mode 100644 src/_h5ai/js/inc/core/settings.js create mode 100644 src/_h5ai/js/inc/core/store.js create mode 100644 src/_h5ai/js/inc/ext/crumb.js create mode 100644 src/_h5ai/js/inc/ext/custom.js create mode 100644 src/_h5ai/js/inc/ext/filter.js create mode 100644 src/_h5ai/js/inc/ext/folderstatus.js rename src/_h5ai/js/inc/{localize.js => ext/l10n.js} (54%) create mode 100644 src/_h5ai/js/inc/ext/link-hover-states.js create mode 100644 src/_h5ai/js/inc/ext/qrcode.js create mode 100644 src/_h5ai/js/inc/ext/select.js rename src/_h5ai/js/inc/{ => ext}/sort.js (78%) create mode 100644 src/_h5ai/js/inc/ext/statusbar.js create mode 100644 src/_h5ai/js/inc/ext/thumbnails.js create mode 100644 src/_h5ai/js/inc/ext/title.js create mode 100644 src/_h5ai/js/inc/ext/tree.js create mode 100644 src/_h5ai/js/inc/ext/zipped-download.js delete mode 100644 src/_h5ai/js/inc/extended.js delete mode 100644 src/_h5ai/js/inc/finder.js rename src/_h5ai/js/inc/{splash.js => h5ai-info.js} (66%) create mode 100644 src/_h5ai/js/inc/h5ai-main.js delete mode 100644 src/_h5ai/js/inc/h5ai.js delete mode 100644 src/_h5ai/js/inc/html.js create mode 100644 src/_h5ai/js/inc/lib/jquery.mousewheel-3.0.6.js delete mode 100644 src/_h5ai/js/inc/lib/jquery.mousewheel.js create mode 100644 src/_h5ai/js/inc/lib/module.js create mode 100644 src/_h5ai/js/inc/model/entry.js delete mode 100644 src/_h5ai/js/inc/module.js create mode 100644 src/_h5ai/js/inc/parser/apache-autoindex.js create mode 100644 src/_h5ai/js/inc/parser/generic-json.js delete mode 100644 src/_h5ai/js/inc/path.js delete mode 100644 src/_h5ai/js/inc/settings.js delete mode 100644 src/_h5ai/js/inc/util.js create mode 100644 src/_h5ai/js/inc/view/extended.js create mode 100644 src/_h5ai/js/inc/view/spacing.js create mode 100644 src/_h5ai/js/inc/view/viewmode.js delete mode 100644 src/_h5ai/js/inc/zip.js create mode 100644 src/_h5ai/js/modernizr-2.5.3.min.js delete mode 100644 src/_h5ai/js/modernizr.min.js delete mode 100644 src/_h5ai/php/inc/Crumb.php delete mode 100644 src/_h5ai/php/inc/Customize.php create mode 100644 src/_h5ai/php/inc/Entry.php delete mode 100644 src/_h5ai/php/inc/Extended.php delete mode 100644 src/_h5ai/php/inc/Tree.php delete mode 100644 src/_h5ai/php/main.php create mode 100644 src/index.php diff --git a/README.md b/README.md index 53fc4967..f29cac09 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # h5ai -Don't use files from this repository (`src` folder) for installation. +Please don't use files from this repository (`src` folder) for installation. They need to be preprocessed/compiled to work correctly. You'll find a precompiled package on the [project page](http://larsjung.de/h5ai). @@ -20,6 +20,7 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h * [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228) (GPL) * [HTML5 ★ Boilerplate](http://html5boilerplate.com) * [jQuery](http://jquery.com) (MIT/GPL) +* [jQuery.fracs](http://larsjung.de/fracs) (MIT) * [jQuery.mousewheel](http://github.com/brandonaaron/jquery-mousewheel) (MIT) * [modernizr](http://www.modernizr.com) (MIT/BSD) * [Moment.js](http://momentjs.com) (MIT) @@ -30,20 +31,29 @@ h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h ## Changelog -### v0.19 - *2012-??-??* +### v0.19 - *2012-04-??* +* adds lots of config options +* changes in `config.js` and `h5ai.htaccess` * fixes js problems in IE 7+8 -* hides broken tree view in IE < 9 and adds a message to the footer -* disables hash changes since they break logical browser history +* hides broken tree view in IE < 9, adds a message to the footer +* removes hash changes since they break logical browser history * fixes thumbnail size for portrait images in icon view +* adds an info page at `/_h5ai` +* sort order is preserved while browsing +* removes PHP error messages on thumbnail generation +* fixes PHP problems with zipped download +* changes crumb image for folders with an index file +* adds `index.php` to use h5ai in non-Apache environments * switches from [Datejs](http://www.datejs.com) to [Moment.js](http://momentjs.com) * adds [underscore.js](http://underscorejs.org) -* adds a info page to `/_ha5i` +* fixes mousewheel problems, updates [jQuery.mousewheel](http://github.com/brandonaaron/jquery-mousewheel) to 3.0.6 * updates lv translation * adds ro translation by [Jakob Cosoroabă](http://github.com/midday) * adds ja translation by [metasta](http://github.com/metasta) * adds nb translation by [Sindre Sorhus](http://github.com/sindresorhus) * adds sr translation by [Goran](http://github.com/vBm) +* adds gr translation by [xhmikosr](http://github.com/xhmikosr) ### v0.18 - *2012-02-24* diff --git a/build.properties b/build.properties index f887c5a5..1b874df3 100644 --- a/build.properties +++ b/build.properties @@ -3,7 +3,7 @@ custom = true # project project.name = h5ai -project.version = pre0.19 +project.version = 0.19-pre # src @@ -18,4 +18,5 @@ release.dir = release # tools tool.wepp = wepp tool.jslint = jslint +tool.jshint = jshint diff --git a/build.xml b/build.xml index af2a78cc..48e26d10 100644 --- a/build.xml +++ b/build.xml @@ -54,6 +54,11 @@ + + + + + @@ -112,4 +117,14 @@ + + + + JSHint @{files} + + + + + + diff --git a/src/_h5ai/config.js b/src/_h5ai/config.js index fe3395dc..fdb1f6af 100644 --- a/src/_h5ai/config.js +++ b/src/_h5ai/config.js @@ -17,16 +17,17 @@ var H5AI_CONFIG = { "h5aiAbsHref": "/_h5ai/", /* - * Filenames of customized header and footer files to look for - * in each folder. For Example: - * - * "customHeader": "_h5ai.header.html", - * "customFooter": "_h5ai.footer.html", - * - * This is disabled by default. + * Spacing of the main content. + * Left and right will be added to a minimum of 30px. Top and bottom + * are calculated relative to the top and bottom bar heights. */ - "customHeader": null, - "customFooter": null, + "spacing": { + "maxWidth": 960, + "top": 50, + "right": "auto", + "bottom": 50, + "left": "auto" + }, /* * An array of view modes the user may choose from. Currently there @@ -35,8 +36,102 @@ var H5AI_CONFIG = { * view mode is fixed and the selector buttons are hidden. * The user selected view mode is also stored local in modern browsers * so that it will be persistent. + * + * Set parent folder labels to real folder names. */ - "viewmodes": ["details", "icons"], + "view": { + "modes": ["details", "icons"], + "setParentFolderLabels": true + }, + + + + + /* + * Extensions in alphabetical order. + */ + + /* + * Show a clickable breadcrumb. + */ + "crumb": { + "enabled": true + }, + + /* + * Filenames of customized header and footer files to look for + * in each folder. + */ + "custom": { + "enabled": true, + "header": "_h5ai.header.html", + "footer": "_h5ai.footer.html" + }, + + /* + * Allow filtering the displayed files and folders. + * Note: filters will be treated as JavaScript regular expressions + * if you prefix them with "re:". + */ + "filter": { + "enabled": true + }, + + /* + * Associative array of folders and their HTTP status codes to + * avoid HEAD requests to that folders. The key (folder) must start + * and end with a slash (/). + * For example + * "/some/folder/": 200 + * will always return HTTP status 200 (OK), which will be interpreted + * as a non auto indexed folder, that means a folder containing an + * appropriate default index file. + */ + "folderstatus": { + "enabled": true, + "folders": {} + }, + + /* + * Localization, for example "en", "de" etc. - see "langs" below for + * possible values. Adjust it to your needs. If lang is not found in + * "langs" it defaults to "en". + * + * Optionally try to use browser language, falls back to previous + * specified language. + * + * Date format in detailed view, for example: "YYYY-MM-DD HH:mm:ss" + * Syntax as specified by Moment.js (http://momentjs.com) + * This might be overidden by "dateFormat" in a lang specification. + */ + "l10n": { + "enabled": true, + "lang": "en", + "useBrowserLang": true, + "defaultDateFormat": "YYYY-MM-DD HH:mm" + }, + + /* + * Link the hover effects between crumb, main view and tree. + */ + "link-hover-states": { + "enabled": true + }, + + /* + * Show QRCodes on hovering files. + */ + "qrcode": { + "enabled": true, + "size": 150 + }, + + /* + * Make entries selectable. At the moment only needed for zipped download. + */ + "select": { + "enabled": true + }, /* * Default sort order is a two letter code. The first letter specifies @@ -44,96 +139,66 @@ var H5AI_CONFIG = { * second letter specifies the sort order: "a" for "ascending" or "d" * for "descending". */ - "sortorder": "na", + "sort": { + "enabled": true, + "order": "na" + }, /* - * Show a folder tree, boolean. - * Note that this tree might have side effects as it sends HEAD requests - * to the folders, and therefore will invoke index.php scripts. Use - * folderStatus below to avoid such requests. - * It might also affect performance significantly. + * Show additional info in a statusbar. */ - "showTree": true, - - /* - * Slide tree bar into viewport if there is enough space, boolean. - */ - "slideTree": true, - - /* - * Associative array of folders and their HTTP status codes to - * avoid HEAD requests to that folders. The key (folder) must start - * and end with a slash (/). - * For example: - * "/some/folder/": 200 - * will always return HTTP status 200 (OK), which will be interpreted - * as a non auto indexed folder, that means a folder containing an - * appropriate default index file. - */ - "folderStatus": {}, - - /* - * Localization, for example "en", "de" etc. - see h5aiLangs below for - * possible values. Adjust it to your needs. If lang is not found in - * h5aiLangs it defaults to "en". - */ - "lang": "en", - - /* - * Try to use browser language, falls back to previous specified lang. - */ - "useBrowserLang": true, - - /* - * Set parent folder labels to real folder names. - */ - "setParentFolderLabels": true, - - /* - * Link the hover effects between crumb, extended view and tree. - */ - "linkHoverStates": true, - - /* - * Date format in detailed view, for example: "YYYY-MM-DD HH:mm:ss" - * Syntax as specified by Moment.js (http://momentjs.com) - */ - "dateFormat": "YYYY-MM-DD HH:mm", + "statusbar": { + "enabled": true + }, /* * Requires PHP on the server. - * Show thumbnails for image files. + * Show thumbnails for image files. Needs the "/_h5ai/cache" folder to be + * writable for the Apache Server. */ - "showThumbs": true, - "thumbTypes": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"], + "thumbnails": { + "enabled": true, + "types": ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"], + "delay": 1000 + }, + + /* + * Replace window title with current breadcrumb. + */ + "title": { + "enabled": true + }, + + /* + * Show a folder tree. + * Note that this tree might have side effects as it sends HEAD requests + * to the folders, and therefore will invoke index.php scripts. Use + * "folderstatus" above to avoid such requests. + * It might also affect performance significantly. + * + * Slide tree bar into viewport if there is enough space. + */ + "tree": { + "enabled": true, + "slide": true + }, /* * Requires PHP on the server. * Enable zipped download of selected entries. */ - "zippedDownload": true, - - /* - * Show QRCodes on hovering files. - * Set this to the desired size in pixel or null to not display QRCodes. - * A good size to start with might be 150. - */ - "qrCodesSize": 150, - - /* - * Allow filtering the displayed files and folders. - * Filters are ment to be JavaScript regular expressions. - */ - "showFilter": true + "zipped-download": { + "enabled": true + } }, /* - * File types mapped to file extensions. + * File types mapped to file extensions. In alphabetical order. */ "types": { "archive": [".tar.bz2", ".tar.gz", ".tgz"], - "audio": [".aif", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"], + "audio": [".aif", ".flac", ".m4a", ".mid", ".mp3", ".mpa", ".ra", ".ogg", ".wav", ".wma"], "authors": ["authors"], "bin": [".class", ".o", ".so"], "blank": [], @@ -149,7 +214,7 @@ var H5AI_CONFIG = { "doc": [".doc", ".docx", ".odm", ".odt", ".ott"], "draw": [".drw"], "eps": [".eps"], - "exe": [".exe"], + "exe": [".bat", ".cmd", ".exe"], "folder": [], "folder-home": [], "folder-open": [], @@ -171,7 +236,7 @@ var H5AI_CONFIG = { "package": [], "pdf": [".pdf"], "php": [".php"], - "playlist": [".m3u"], + "playlist": [".m3u", ".m3u8", ".pls"], "png": [".png"], "pres": [".odp", ".otp", ".pps", ".ppt", ".pptx"], "psd": [".psd"], @@ -187,18 +252,18 @@ var H5AI_CONFIG = { "sql": [], "tar": [".tar"], "tex": [".tex"], - "text": [".markdown", ".md", ".text", ".txt"], + "text": [".diff", ".markdown", ".md", ".patch", ".text", ".txt"], "tiff": [".tiff"], "unknown": [], "vcal": [".vcal"], - "video": [".avi", ".flv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"], + "video": [".avi", ".flv", ".mkv", ".mov", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"], "xml": [".xml"], - "zip": [".bz2", ".jar", ".war", ".z", ".Z", ".zip"] + "zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"] }, /* - * Available translations. + * Available translations. "en" in first place as a reference, otherwise in alphabetical order. */ "langs": { @@ -259,7 +324,8 @@ var H5AI_CONFIG = { "folders": "Ordner", "files": "Dateien", "download": "Download", - "noMatch": "keine Treffer" + "noMatch": "keine Treffer", + "dateFormat": "DD.MM.YYYY HH:mm" }, "es": { @@ -292,6 +358,21 @@ var H5AI_CONFIG = { "noMatch": "no match" }, + "gr": { + "lang": "ελληνικά", + "details": "Λεπτομέρειες", + "icons": "Εικονίδια", + "name": "Όνομα", + "lastModified": "Τελευταία Τροποποίηση", + "size": "Μέγεθος", + "parentDirectory": "Προηγούμενος Κατάλογος", + "empty": "κενό", + "folders": "Φάκελοι", + "files": "Αρχεία", + "download": "Μεταμόρφωση", + "noMatch": "Κανένα Ταίριασμα" + }, + "it": { "lang": "italiano", "details": "dettagli", diff --git a/src/_h5ai/config.php b/src/_h5ai/config.php index 8ab74296..95143e8b 100644 --- a/src/_h5ai/config.php +++ b/src/_h5ai/config.php @@ -14,7 +14,7 @@ $H5AI_CONFIG = array( * This configuration assumes that h5ai is installed * in the webroot directory of the Apache server. */ - "ROOT_ABS_PATH" => safe_dirname(safe_dirname(__FILE__)), + "ROOT_ABS_PATH" => dirname(dirname(__FILE__)), /* * Files/folders that should not be listed. Specified diff --git a/src/_h5ai/css/inc/table.less b/src/_h5ai/css/inc/apache-autoindex-table.less similarity index 67% rename from src/_h5ai/css/inc/table.less rename to src/_h5ai/css/inc/apache-autoindex-table.less index cfd5241b..957e54c2 100644 --- a/src/_h5ai/css/inc/table.less +++ b/src/_h5ai/css/inc/apache-autoindex-table.less @@ -1,33 +1,32 @@ -#table { +#data-apache-autoindex { + max-width: 960px; + margin: 0 auto; + table { display: block; width: 100%; border-collapse: collapse; th, td { - padding: 3px 6px; + padding: 6px; text-align: left; border: none; } th { padding-bottom: 18px; - opacity: 0.4; - .transition(all 0.2s ease-in-out); - &:hover, &:hover a { - color: #555; - cursor: pointer; - opacity: 0.9; - } a, a:visited { color: #555; font-weight: normal; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + .transition(all 0.2s ease-in-out); - img { - width: 12px; - height: 12px; - padding: 0 8px; + &:hover { + color: #555; + opacity: 0.9; } } } @@ -35,6 +34,19 @@ border: 1px solid #ddd; border-left: none; border-right: none; + overflow: hidden; + white-space: nowrap; + + a, a:active, a:visited { + display: block; + color: #555; + text-decoration: none; + cursor: pointer; + + &:hover { + color: #e80; + } + } } td:nth-child(1), th:nth-child(1) { text-align: center; @@ -43,26 +55,23 @@ img { width: 16px; height: 16px; - padding-top: 2px; + position: relative; + top: -2px; } } td:nth-child(2), th:nth-child(2) { width: 682px; max-width: 682px; - overflow: hidden; - white-space: nowrap; } td:nth-child(3), th:nth-child(3) { text-align: right; width: 160px; min-width: 160px; - white-space: nowrap; } td:nth-child(4), th:nth-child(4) { text-align: right; width: 70px; min-width: 70px; - white-space: nowrap; } } } diff --git a/src/_h5ai/css/inc/bottombar.less b/src/_h5ai/css/inc/bottombar.less new file mode 100644 index 00000000..432e0466 --- /dev/null +++ b/src/_h5ai/css/inc/bottombar.less @@ -0,0 +1,68 @@ + +#bottombar { + position: fixed; + z-index: 5; + width: 100%; + left: 0; + bottom: 0; + padding: 6px 0 8px 0; + .vert-gradient(rgb(241,241,241), rgb(228,228,228)); + border-top: 1px solid rgb(210,210,210); + + color: #999; + font-size: @smaller-font; + text-align: center; + + a, a:active, a:visited { + color: #555; + text-decoration: none; + .transition(all 0.2s ease-in-out); + opacity: 0.7; + + &:hover { + color: #e80; + opacity: 1; + } + } + .left { + display: block; + padding: 0 8px; + float: left + } + .center { + display: block; + margin: 0 100px; + } + .right { + display: block; + padding: 0 8px; + float: right + } + .noJsMsg { + color: #c33; + margin-left: 16px; + } + .oldBrowser { + display: none; + color: #c33; + margin-left: 16px; + a, a:active, a:visited { + color: #c33; + text-decoration: underline; + &:hover { + color: #e80; + } + } + } + .status { + .sep { + display: inline-block; + padding: 0 6px; + } + &.default { + } + &.dynamic { + display: none; + } + } +} diff --git a/src/_h5ai/css/inc/content.less b/src/_h5ai/css/inc/content.less index cd84d554..202d2084 100644 --- a/src/_h5ai/css/inc/content.less +++ b/src/_h5ai/css/inc/content.less @@ -1,18 +1,30 @@ #content { max-width: 960px; - margin: 0 auto; + margin: 50px auto; +} - > header { - display: none; - padding-bottom: 10px; - margin-bottom: 80px; - border-bottom: 2px dashed #ddd; - } - > footer { - display: none; - padding-top: 10px; - margin-top: 80px; - border-top: 2px dashed #ddd; + +#content-header, #content-footer { + + a, a:active, a:visited { + color: #2080FF; + text-decoration: none; + cursor: pointer; + + &:hover { + color: #68A9FF; + } } } + + +#content-header { + padding-bottom: 12px; + margin-bottom: 32px; +} + +#content-footer { + padding-top: 12px; + margin-top: 32px; +} diff --git a/src/_h5ai/css/inc/extended.less b/src/_h5ai/css/inc/extended.less index c4ca3845..3fbb7810 100644 --- a/src/_h5ai/css/inc/extended.less +++ b/src/_h5ai/css/inc/extended.less @@ -54,10 +54,10 @@ background-color: #f6f6f6; color: #e80; } - &.selected:not(.selecting), &.selecting:not(.selected) { - border-color: rgba(240,100,0,0.2); - background-color: rgba(240,100,0,0.2); - } + } + &.selected:not(.selecting) a, &.selecting:not(.selected) a { + border-color: rgba(240,100,0,0.2); + background-color: rgba(240,100,0,0.2); } &.error { a, a:active, a:visited { @@ -102,7 +102,7 @@ width: 16px; height: 16px; &.thumb { - border: 1px solid #eee; + // border: 1px solid #ddd; } } } @@ -132,18 +132,6 @@ width: 80px; white-space: nowrap; } - &.entry.thumb .icon.small { - overflow: hidden; - padding: 5px; - - img { - background-color: #eee; - width: 16px; - height: 16px; - border: 1px solid #ddd; - overflow: hidden; - } - } } } .empty, .no-match { @@ -206,10 +194,6 @@ border-color: #eee; background-color: #f6f6f6; } - &.selected:not(.selecting), &.selecting:not(.selected) { - border-color: rgba(240,100,0,0.2); - background-color: rgba(240,100,0,0.2); - } .icon { display: block; @@ -218,7 +202,7 @@ height: 48px; margin-bottom: 8px; &.thumb { - border: 1px solid #eee; + // border: 1px solid #ddd; } } } @@ -233,6 +217,10 @@ display: none; } } + &.selected:not(.selecting) a, &.selecting:not(.selected) a { + border-color: rgba(240,100,0,0.2); + background-color: rgba(240,100,0,0.2); + } &.error { a, a:active, a:visited { color: #aaa; @@ -253,21 +241,6 @@ } } } - &.entry.thumb .icon.big { - width: 100px; - height: 58px; - overflow: hidden; - - img { - background-color: #eee; - min-width: 46px; - min-height: 46px; - min-width: 12px; - min-height: 12px; - border: 1px solid #ddd; - overflow: hidden; - } - } } } .empty, .no-match { diff --git a/src/_h5ai/css/inc/footer.less b/src/_h5ai/css/inc/footer.less deleted file mode 100644 index e8cd26ef..00000000 --- a/src/_h5ai/css/inc/footer.less +++ /dev/null @@ -1,120 +0,0 @@ - -body > footer { - position: fixed; - z-index: 5; - width: 100%; - left: 0; - bottom: 0; - padding: 6px 0 8px 0; - .vert-gradient(rgb(241,241,241), rgb(228,228,228)); - border-top: 1px solid rgb(210,210,210); - - color: #999; - font-size: 0.85em; - text-align: center; - - a, a:active, a:visited { - color: #555; - text-decoration: none; - .transition(all 0.2s ease-in-out); - opacity: 0.7; - - &:hover { - color: #e80; - opacity: 1; - } - } - .left { - display: block; - padding: 0 8px; - float: left - } - .center { - display: block; - margin: 0 100px; - } - .right { - display: block; - padding: 0 8px; - float: right - } - .noJsMsg { - color: #c33; - margin-left: 16px; - } - .oldBrowser { - display: none; - color: #c33; - margin-left: 16px; - a, a:active, a:visited { - color: #c33; - text-decoration: underline; - &:hover { - color: #e80; - } - } - } - .status { - .sep { - display: inline-block; - padding: 0 6px; - } - &.default { - } - &.dynamic { - display: none; - } - } - #langSelector { - position: relative; - cursor: pointer; - - .langOptions { - position: absolute; - z-index: 2; - overflow: auto; - display: none; - right: 0; - top: 0; - max-height: 200px; - background-color: rgb(241,241,241); - border: 1px solid rgb(210,210,210); - - > .scrollbar { - margin: 0; - width: 6px; - background-color: rgb(210,210,210); - - .drag { - background-color: rgb(180,180,180); - } - &.dragOn .drag { - background-color: rgb(150,150,150); - } - } - - ul { - margin: 0; - padding: 0; - list-style: none; - text-align: left; - - li { - padding: 8px 24px 10px 24px; - white-space: nowrap; - border-top: 1px solid rgb(231,231,231); - .transition(all 0.2s ease-in-out); - - &.current { - color: #333; - background-color: rgba(255,255,255,0.8); - } - &:hover { - color: #e80; - background-color: rgba(255,255,255,0.8); - } - } - } - } - } -} diff --git a/src/_h5ai/css/inc/h5ai-info.less b/src/_h5ai/css/inc/h5ai-info.less new file mode 100644 index 00000000..e63d8664 --- /dev/null +++ b/src/_h5ai/css/inc/h5ai-info.less @@ -0,0 +1,59 @@ + +body#h5ai-info { + font-family: Ubuntu, Arial, sans; + margin: 0 auto; + font-size: 20px; + color: #555; + max-width: 600px; + text-align: center; + + .h5ai { + font-family: 'Miltonian Tattoo'; + font-weight: normal; + } + h1 { + font-size: 3.6em; + margin: 0.9em 0 0 0; + } + h2 { + font-size: 1.15em; + margin: 2.6em 0 0 0; + } + p { + line-height: 1.6em; + } + p + p { + margin-top: 1.2em; + } + li { + margin-top: 0.6em; + line-height: 1.4em; + } + + #tests { + display: inline-block; + list-style-type: none; + text-align: left; + margin: 0; + padding: 0; + + .test-label { + display: inline-block; + width: 300px; + } + .test-result { + display: inline-block; + width: 70px; + text-align: right; + font-weight: bold; + color: #aaa; + + &.test-passed { + color: #5a5; + } + &.test-failed { + color: #a55; + } + } + } +} diff --git a/src/_h5ai/css/inc/l10n.less b/src/_h5ai/css/inc/l10n.less new file mode 100644 index 00000000..c47f9746 --- /dev/null +++ b/src/_h5ai/css/inc/l10n.less @@ -0,0 +1,53 @@ + +#langSelector { + position: relative; + cursor: pointer; + + .langOptions { + position: absolute; + z-index: 2; + overflow: auto; + display: none; + right: 0; + top: 0; + max-height: 200px; + background-color: rgb(241,241,241); + border: 1px solid rgb(210,210,210); + + > .scrollbar { + margin: 0; + width: 6px; + background-color: rgb(210,210,210); + + .drag { + background-color: rgb(180,180,180); + } + &.dragOn .drag { + background-color: rgb(150,150,150); + } + } + + ul { + margin: 0; + padding: 0; + list-style: none; + text-align: left; + + li { + padding: 8px 24px 10px 24px; + white-space: nowrap; + border-top: 1px solid rgb(231,231,231); + .transition(all 0.2s ease-in-out); + + &.current { + color: #333; + background-color: rgba(255,255,255,0.8); + } + &:hover { + color: #e80; + background-color: rgba(255,255,255,0.8); + } + } + } + } +} diff --git a/src/_h5ai/css/inc/mixins.less b/src/_h5ai/css/inc/mixins.less index a9691734..e1ecd862 100644 --- a/src/_h5ai/css/inc/mixins.less +++ b/src/_h5ai/css/inc/mixins.less @@ -1,5 +1,4 @@ - .border-radius (@radius) { -webkit-border-radius: @radius; /* Saf3-4, iOS 1-3.2, Android <1.6 */ -moz-border-radius: @radius; /* FF1-3.6 */ @@ -56,4 +55,3 @@ -moz-background-size: @size; /* FF3.6 */ background-size: @size; /* Opera, IE9, Saf5, Chrome, FF4 */ } - diff --git a/src/_h5ai/css/inc/responsive.less b/src/_h5ai/css/inc/responsive.less index 917b5236..3b0b52ca 100644 --- a/src/_h5ai/css/inc/responsive.less +++ b/src/_h5ai/css/inc/responsive.less @@ -1,5 +1,6 @@ + @media only screen and (max-width: 500px) { -body > nav { +#topbar { .view span { display: none; } @@ -12,7 +13,7 @@ body > nav { } @media only screen and (max-width: 350px) { -body > nav { +#topbar { .crumb { display: none; } @@ -28,7 +29,7 @@ body > nav { display: none; } } -body > footer { +#bottombar { .center { display: none; } @@ -39,18 +40,18 @@ body > footer { a[href]:after { content: ""; } -body > nav { +#topbar { position: static; margin-bottom: 2em; .view, #download { display: none; } } -body > footer { +#bottombar { position: static; margin-top: 2em; } #tree { display: none !important; } -} \ No newline at end of file +} diff --git a/src/_h5ai/css/inc/splash.less b/src/_h5ai/css/inc/splash.less deleted file mode 100644 index c1d5e101..00000000 --- a/src/_h5ai/css/inc/splash.less +++ /dev/null @@ -1,59 +0,0 @@ - -html.h5ai-splash { - body { - font-family: Ubuntu, Arial, sans; - margin: 0 auto; - font-size: 20px; - color: #555; - max-width: 600px; - text-align: center; - - .h5ai { - font-family: 'Miltonian Tattoo'; - font-weight: normal; - } - h1 { - font-size: 3.6em; - margin: 0.9em 0 0 0; - } - h2 { - font-size: 1.15em; - margin: 2.6em 0 0 0; - } - p { - line-height: 1.6em; - } - p + p { - margin-top: 1.2em; - } - li { - margin-top: 0.6em; - line-height: 1.4em; - } - #tests { - display: inline-block; - list-style-type: none; - text-align: left; - margin: 0; - padding: 0; - - .test-label { - display: inline-block; - width: 300px; - } - .test-result { - display: inline-block; - width: 70px; - text-align: right; - font-weight: bold; - - &.test-passed { - color: #5a5; - } - &.test-failed { - color: #a55; - } - } - } - } -} diff --git a/src/_h5ai/css/inc/nav.less b/src/_h5ai/css/inc/topbar.less similarity index 73% rename from src/_h5ai/css/inc/nav.less rename to src/_h5ai/css/inc/topbar.less index 89c4f580..231fa4ee 100644 --- a/src/_h5ai/css/inc/nav.less +++ b/src/_h5ai/css/inc/topbar.less @@ -1,4 +1,16 @@ +#topbar { + position: fixed; + z-index: 5; + width: 100%; + left: 0; + top: 0; + font-size: @smaller-font; + .vert-gradient(rgb(241,241,241), rgb(228,228,228)); + border-bottom: 1px solid rgb(210,210,210); +} + + .nav-highlight { background-color: rgba(255,255,255,0.5); opacity: 1.0; @@ -21,23 +33,13 @@ border-left: @nav-sep-border; } -body > nav { - position: fixed; - z-index: 5; - width: 100%; - left: 0; - top: 0; - font-size: 0.85em; - .vert-gradient(rgb(241,241,241), rgb(228,228,228)); - border-bottom: 1px solid rgb(210,210,210); - span.jsDisabledFallback { - display: block; - height: 30px; - line-height: 30px; - padding: 0 10px; - color: #999; - } +#navbar { + list-style: none; + list-style-image: none; + margin: 0; + padding: 0; + a, a:active, a:visited, span.element { color: #555; cursor: pointer; @@ -76,50 +78,54 @@ body > nav { color: #999; } img.hint { - width: 10px; - height: 10px; + width: 14px; + height: 14px; + opacity: 0.8; } } .view { .nav-right; } - #download { +} + + +#filter { + .nav-right; + + input { display: none; - .nav-right; - .transition(all 0.2s ease-in-out); - - &.failed { - background-color: rgba(255,0,0,0.5); - } + border: none; + font-family: Ubuntu, sans-serif; + color: #555; + background-color: rgba(0,0,0,0); + width: 100px; } - #filter { - .nav-right; + &.current { input { - display: none; - border: none; - font-family: Ubuntu, sans-serif; - color: #555; - background-color: rgba(0,0,0,0); - width: 100px; - } - - &.current { - input { - display: inline; - } + display: inline; } } } +#download { + display: none; + .nav-right; + .transition(all 0.2s ease-in-out); + + &.failed { + background-color: rgba(255,0,0,0.5); + } +} + #download-auth { display: none; position: fixed; z-index: 5; left: 0; top: 0; - font-size: 0.85em; + font-size: @smaller-font; .vert-gradient(rgb(241,241,241), rgb(228,228,228)); border: 1px solid rgb(210,210,210); diff --git a/src/_h5ai/css/inc/tree.less b/src/_h5ai/css/inc/tree.less index 6bd2e477..2c96fe3f 100644 --- a/src/_h5ai/css/inc/tree.less +++ b/src/_h5ai/css/inc/tree.less @@ -7,7 +7,7 @@ height: 100%; z-index: 3; overflow: auto; - font-size: 0.85em; + font-size: @smaller-font; padding: 8px; background-color: rgb(241,241,241); border-right: 2px solid rgb(221,221,221); @@ -28,20 +28,12 @@ } .entry { - .blank, .indicator { + .indicator { display: inline-block; width: 16px; height: 25px; float: left; - } - .indicator { - opacity: 0.7; - .transition(all 0.2s ease-in-out); - cursor: pointer; - &:hover { - opacity: 1; - } img { position: relative; left: 0; @@ -52,13 +44,23 @@ .transition(all 0.2s ease-in-out); } &.open { + cursor: pointer; + opacity: 0.7; img { .transform(rotate(90deg)); } } + &.close { + cursor: pointer; + opacity: 0.7; + } &.unknown { + cursor: pointer; opacity: 0.3; } + &.none { + opacity: 0; + } } > a, > a:active, > a.visited { margin-left: 16px; @@ -92,16 +94,8 @@ margin-left: 12px; font-size: 0.9em; color: #ccc; - img { - width: 10px; - height: 10px; - vertical-align: baseline; - } } } - &.file { - display: none; - } &.current { > a, > a:active, > a:visited { border: 1px solid rgb(221,221,221); diff --git a/src/_h5ai/css/styles.less b/src/_h5ai/css/styles.less index 0fd957b1..40923bd8 100644 --- a/src/_h5ai/css/styles.less +++ b/src/_h5ai/css/styles.less @@ -2,63 +2,37 @@ @import "inc/h5bp-norm"; @import "inc/mixins"; +::-moz-selection { background: #68A9FF; color: #fff; text-shadow: none; } +::selection { background: #68A9FF; color: #fff; text-shadow: none; } body { font-family: Ubuntu, sans-serif; font-size: 16px; color: #555; background-color: #fff; - margin: 80px 30px; + margin: 30px; } -@import "inc/nav"; +@smaller-font: 15px; + +@import "inc/topbar"; @import "inc/content"; -@import "inc/table"; @import "inc/extended"; +@import "inc/bottombar"; +@import "inc/l10n"; @import "inc/tree"; @import "inc/context"; -@import "inc/footer"; +@import "inc/apache-autoindex-table"; @import "inc/responsive"; -html.js { - .hideOnJs { - display: none; - } -} -html.no-js { - .hideOnNoJs { - display: none; - } -} -html.h5ai-js { - #h5ai-reference:after { - content: " (js)"; - } -} -html.h5ai-php { - #h5ai-reference:after { - content: " (php)"; - } - - #table { - display: none; - } - - #tree, #content > header, #content > footer { - display: block; - } - - &.no-js { - #extended.details-view, #extended.icons-view { - display: block; - } - } +html.js .hideOnJs, html.no-js .hideOnNoJs { + display: none; } html.oldie { .oldBrowser { - display: inline; + display: inline !important; } #tree { display: none !important; @@ -66,5 +40,4 @@ html.oldie { } -@import "inc/splash"; - +@import "inc/h5ai-info"; diff --git a/src/_h5ai/footer.html b/src/_h5ai/footer.html index f4d6a019..12a8c4d2 100644 --- a/src/_h5ai/footer.html +++ b/src/_h5ai/footer.html @@ -1,32 +1,4 @@ - - - -
-
- - h5ai %BUILD_VERSION% - ⚡ JavaScript is disabled! ⚡ - ⚡ Some features disabled! Works best in modern browsers. ⚡ - - - - en - english - - - - - - - folders - · - files - - - - - -
- - + + \ No newline at end of file diff --git a/src/_h5ai/footer.php b/src/_h5ai/footer.php new file mode 100644 index 00000000..4e22ff8b --- /dev/null +++ b/src/_h5ai/footer.php @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/src/_h5ai/header.html b/src/_h5ai/header.html index 0871acdf..674814af 100644 --- a/src/_h5ai/header.html +++ b/src/_h5ai/header.html @@ -1,34 +1,41 @@ - - - - + + + + Directory index · styled with h5ai - - - + - - -
-
-
-
-
-
- + +
+
+
+
+ + h5ai %BUILD_VERSION% + ⚡ JavaScript is disabled! ⚡ + ⚡ Some features disabled! Works best in modern browsers. ⚡ + + + +
+ + +
+ diff --git a/src/_h5ai/header.php b/src/_h5ai/header.php deleted file mode 100644 index f9c8e79b..00000000 --- a/src/_h5ai/header.php +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - <?php echo $h5ai->getTitle(); ?> - - - - - - - - - - - - - toHtml(); ?> -
- getHeader(); ?> - toHtml(); ?> - getFooter(); ?> -
- diff --git a/src/_h5ai/images/page.png b/src/_h5ai/images/page.png index 0d55aeecbbdb8c17cf1993103774b94923b0f85e..24655400bab7e0b71a2252ba56638baaa5986f3e 100644 GIT binary patch delta 518 zcmV+h0{Q*I1+)Z^Bpd;AQb$4nuFf3k00006VoOIv0RI600RN!9r<0K}7=H(JNliru z+yoC6EEds)!CwFX0kla(K~y-)eUq`y5>XI^zuDbiFo4CprAFrf|Z5Q z#)^uHQ27E@^cKE>vGoDu1uQ5q!Agk=Y-Cy1W8qw~A-_(sbLZZ+eA2=f8db1RQ`<;(txI+wFFm=lLrj@`k1ZwSafP8$bY^PDk7AHU)kl2}$>W zx4?ZM0nAy&o<9IDeQiJ_>5e2KXJEiJ@ClGd+3)u&r@wEtTF-%}&JdS#F1Ah=Ns*b6 zWf`m0%DnMwp65Rsjm8TH(Ivnwpc5WY60_ON27>`{9GmZdE{b9cJbwY60Y`iylCFXG zK-B=P06-K)!Liqpnvw`E?13UQI*5%%Bb8-Inx^b_J2smQ%jNRq&Lo77M-gl? zGrHZb*6TI3N0uba%v^2**w+CLfo_mdzkE?2&ay5T5Ex`xhM8ez@=VRX%4Odu!6b#L zAzw1c|HU944u`5;reE&DbUF?7neCZD9LJ}ssva&Di;rd&K(3r_7$o39k|e+U=PCk# z#^dp7KA%529*>XtPb5jA$z<{c*x`D^S+FL=H{h=4o5BG70V-9xHS4%+ng9R*07*qo IM6N<$g7!c21poj5 delta 661 zcmV;G0&4xV1i}T7Bn<>}LP=Bz2nYy#2xN$nKp1}+bVXQnQ*UN;cVTj60C#tHE@^IS zb7Ns}WiD@WXPfRk8UO$SKS@MER5*>5l22$8K^VnfHe+|$Xwq6J#bs#^4Ive3m5sK9 z7HJ9#!HYyJ2wpsRD^yhCxkbpOpisqwPThr{8Qj^o@1@D%|4 z4#LS~@;U%(et!NQ$*UwsNsf@rEG;eF0q}omXlUpb$&-EuAgOhAbv;ic5|2n;Bq?CS8-`KxJWs9FYN|g&2|yqi4DMK# zW&19-bzoUmO_t@2y}dmNK)?@h`}+De3WdTjfXESm?zOeG)4Hy2_xJbj`a_fe>}G$n z+4qj)j3$%GF#v-Ax?8Y;bUJ<3w(W6E)4l=N_0t7_`t0oNheDz7W@TmNW+W0hAB)A_ zNs{DMDwUCXy*@^Ab8Bl008{`neiaM=4tsD6z{K+M^6 - - - - + + + + - h5ai %BUILD_VERSION% + h5ai %BUILD_VERSION% info page - - - + - +

h5ai

version %BUILD_VERSION%

server supports

    -
  • php version
  • -
  • zipped downloads
  • -
  • thumbnails
  • +
  • php version?
  • +
  • cache?
  • +
  • thumbnails?
  • +
  • temp directory?
  • +
  • zipped downloads?
+
+ + h5ai %BUILD_VERSION% + ⚡ JavaScript is disabled! ⚡ + ⚡ Some features disabled! Works best in modern browsers. ⚡ + + + +
diff --git a/src/_h5ai/js/inc/connector.js b/src/_h5ai/js/inc/connector.js deleted file mode 100644 index 1a57e283..00000000 --- a/src/_h5ai/js/inc/connector.js +++ /dev/null @@ -1,373 +0,0 @@ - -Module.define('conhtml', [jQuery, 'settings', 'path', 'util', 'core', 'localize'], function ($, settings, pathFactory, util, core, localize) { - - var cache = {}, - pathnameStatusCache = {}, - contentTypeRegEx = /^text\/html;h5ai=/, - getPath = function (folder, tableRow) { - - var absHref = util.getAbsHref(folder, tableRow), - path = cache[absHref]; - - if (!path) { - path = pathFactory.create(folder, tableRow); - if (!path.isParentFolder) { - cache[path.absHref] = path; - } - } - - return path; - }, - fetchStatus = function (pathname, callback) { - - if (settings.folderStatus[pathname]) { - callback(settings.folderStatus[pathname]); - return; - } else if (pathnameStatusCache[pathname]) { - callback(pathnameStatusCache[pathname]); - return; - } - - $.ajax({ - url: pathname, - type: 'HEAD', - complete: function (xhr) { - - var status = xhr.status; - - if (status === 200 && contentTypeRegEx.test(xhr.getResponseHeader('Content-Type'))) { - status = 'h5ai'; - } - pathnameStatusCache[pathname] = status; - callback(status); - } - }); - }, - updatePath = function (path) { - - if (path.isFolder && !path.isParentFolder && path.status === undefined) { - fetchStatus(path.absHref, function (status) { - - if (status !== 'h5ai') { - path.status = status; - } - updateHtml(path); - core.linkHoverStates(); - }); - } - }, - updatePaths = function () { - - $.each(cache, function (ref, cached) { - updatePath(cached); - }); - }, - fetchStatusAndContent = function (pathname, includeParent, callback) { - - fetchStatus(pathname, function (status) { - - if (status !== 'h5ai') { - callback(status, {}); - return; - } - - $.ajax({ - url: pathname, - type: 'GET', - dataType: 'html', - error: function (xhr) { - - callback(xhr.status, {}); // since it was checked before this should never happen - }, - success: function (html, status, xhr) { - - var content = {}; - - if (!contentTypeRegEx.test(xhr.getResponseHeader('Content-Type'))) { - callback(xhr.status, {}); // since it was checked before this should never happen - return; - } - - $(html).find('#table td').closest('tr').each(function () { - - var path = getPath(pathname, this); - - if (path.isFolder && (!path.isParentFolder || includeParent)) { - content[path.absHref] = path; - updatePath(path); - } - }); - callback('h5ai', content); - } - }); - }); - }; - - - - - - - var onClick = function (path, context) { - - }, - updateCrumbHtml = function (path) { - - var $html, $a; - - if (path.html.$crumb && path.html.$crumb.data("status") === path.status) { - return path.html.$crumb; - } - - $html = $("
  • >
  • ") - .addClass(path.isFolder ? "folder" : "file"); - - if (path.status) { - $html.data("status", path.status); - } - - $a = $html.find("a") - .attr("href", path.absHref) - .click(function() { onClick(path, "crumb"); }) - .find("img").attr("src", core.image("crumb")).end() - .find("span").text(path.label).end(); - - if (path.isDomain) { - $html.addClass("domain"); - $a.find("img").attr("src", core.image("home")); - } - - if (path.isCurrentFolder) { - $html.addClass("current"); - } - - if (!isNaN(path.status)) { - if (path.status === 200) { - $a.append($("not listable")); - } else { - $a.append($("(" + path.status + ")")); - } - } - - if (path.html.$crumb) { - path.html.$crumb.replaceWith($html); - } - path.html.$crumb = $html; - - return $html; - }, - updateExtendedHtml = function (path) { - - var $html, $a, $label, - imgClass = "", - icon16 = core.icon(path.type), - icon48 = core.icon(path.type, true); - - if (path.html.$extended && path.html.$extended.data("status") === path.status) { - return path.html.$extended; - } - - $html = $("
  • ") - .data("path", path) - .addClass(path.isFolder ? "folder" : "file"); - - if (path.status) { - $html.data("status", path.status); - } - - if (settings.showThumbs === true && $.inArray(path.type, settings.thumbTypes) >= 0) { - imgClass = "class='thumb'"; - var escapedHref = path.absHref.replace(/'/g, "%27").replace(/"/g, "%22"); - icon16 = core.api() + "?action=thumb&href=" + escapedHref + "&width=16&height=16&mode=square"; - icon48 = core.api() + "?action=thumb&href=" + escapedHref + "&width=96&height=46&mode=rational"; - } - - $label = $("" + path.label + ""); - $a = $("") - .attr("href", path.absHref) - .click(function() { onClick(path, "extended"); }) - .appendTo($html) - .append($("" + path.type + "")) - .append($("" + path.type + "")) - .append($label) - .append($("")) - .append($("")); - - $a.hover( - function () { - if ($("#extended").hasClass("icons-view")) { - var $this = $(this); - $(".status.default").hide(); - $(".status.dynamic") - .empty() - .append($this.find(".label").clone()) - .append($("·")) - .append($this.find(".date").clone()) - .show(); - - if (!$this.closest(".entry").hasClass("folder")) { - $(".status.dynamic") - .append($("·")) - .append($this.find(".size").clone()); - } - } - }, - function () { - $(".status.default").show(); - $(".status.dynamic").empty().hide(); - } - ); - - if (path.isParentFolder) { - if (!settings.setParentFolderLabels) { - $label.addClass("l10n-parentDirectory"); - } - $html.addClass("folder-parent"); - } - - if (!isNaN(path.status)) { - if (path.status === 200) { - $html.addClass("page"); - $a.find(".icon.small img").attr("src", core.icon("folder-page")); - $a.find(".icon.big img").attr("src", core.icon("folder-page", true)); - } else { - $html.addClass("error"); - $label.append($(" " + path.status + " ")); - } - } - - if (path.html.$extended) { - path.html.$extended.replaceWith($html); - localize.formatDates(); - } - path.html.$extended = $html; - - return $html; - }, - updateTreeHtml = function (path) { - - var $html, $blank, $a, $indicator, $ul, idx; - - $html = $("
    ") - .data("path", path) - .addClass(path.isFolder ? "folder" : "file"); - - $blank = $("").appendTo($html); - - $a = $("") - .attr("href", path.absHref) - .click(function() { onClick(path, "tree"); }) - .appendTo($html) - .append($("")) - .append($("" + path.label + "")); - - if (path.isFolder) { - // indicator - if (path.status === undefined || !path.isEmpty()) { - $indicator = $("") - .click(function (event) { - - var $entry = $indicator.closest(".entry"); // $html - - if ($indicator.hasClass("unknown")) { - fetchStatusAndContent(path.absHref, false, function (status, content) { - - path.status = status; - path.content = content; - path.treeOpen = true; - $("#tree").get(0).updateScrollbar(true); - updateTreeHtml(path); - $("#tree").get(0).updateScrollbar(); - }); - } else if ($indicator.hasClass("open")) { - path.treeOpen = false; - $indicator.removeClass("open"); - $("#tree").get(0).updateScrollbar(true); - $entry.find("> ul.content").slideUp(function() { - - $("#tree").get(0).updateScrollbar(); - }); - } else { - path.treeOpen = true; - $indicator.addClass("open"); - $("#tree").get(0).updateScrollbar(true); - $entry.find("> ul.content").slideDown(function() { - - $("#tree").get(0).updateScrollbar(); - }); - } - - }); - - if (path.status === undefined) { - $indicator.addClass("unknown"); - } else if (path.treeOpen) { - $indicator.addClass("open"); - } - - $blank.replaceWith($indicator); - } - - // is path the domain? - if (path.isDomain) { - $html.addClass("domain"); - $a.find(".icon img").attr("src", core.icon("folder-home")); - } - - // is path the current folder? - if (path.isCurrentFolder) { - $html.addClass("current"); - $a.find(".icon img").attr("src", core.icon("folder-open")); - } - - // does it have subfolders? - if (!path.isEmpty()) { - $ul = $("
      ").appendTo($html); - $.each(path.content, function (idx, entry) { - $("
    • ").append(updateTreeHtml(entry)).appendTo($ul); - }); - if (path.status === undefined || !path.treeOpen) { - $ul.hide(); - } - } - - // reflect folder status - if (!isNaN(path.status)) { - if (path.status === 200) { - $a.find(".icon img").attr("src", core.icon("folder-page")); - $a.append($("")); - } else { - $html.addClass("error"); - $a.append($("" + path.status + "")); - } - } - } - - if (path.html.$tree) { - path.html.$tree.replaceWith($html); - } - path.html.$tree = $html; - - return $html; - }, - updateHtml = function (path) { - - updateCrumbHtml(path); - updateExtendedHtml(path); - updateTreeHtml(path); - }; - - - - - return { - getPath: getPath, - updatePaths: updatePaths, - fetchStatusAndContent: fetchStatusAndContent, - - updateCrumbHtml: updateCrumbHtml, - updateExtendedHtml: updateExtendedHtml, - updateTreeHtml: updateTreeHtml, - updateHtml: updateHtml - }; -}); diff --git a/src/_h5ai/js/inc/context.js b/src/_h5ai/js/inc/context.js deleted file mode 100644 index 26976eba..00000000 --- a/src/_h5ai/js/inc/context.js +++ /dev/null @@ -1,50 +0,0 @@ - -Module.define('context', [jQuery, 'settings'], function ($, settings) { - - var $context, - qrCodesSize, - showQrCode = function ($a) { - - var absHref = $a.attr('href'), - url = 'http://' + document.domain + absHref; - - $context.find('.qrcode').empty().qrcode({ - render: Modernizr.canvas ? 'canvas' : 'div', - width: qrCodesSize, - height: qrCodesSize, - color: '#333', - text: url - }); - }, - init = function () { - - qrCodesSize = settings.qrCodesSize; - if (!qrCodesSize) { - return; - } - - var hideTimeoutId = null; - - $context = $('
      '); - $context.appendTo('body'); - - $('#extended') - .on('mouseenter', '.entry.file a', function () { - - showQrCode($(this)); - clearTimeout(hideTimeoutId); - $context.stop(true, true).fadeIn(400); - }) - .on('mouseleave', '.entry.file a', function () { - - hideTimeoutId = setTimeout(function () { - - $context.stop(true, true).fadeOut(400); - }, 200); - }); - }; - - return { - init: init - }; -}); diff --git a/src/_h5ai/js/inc/core.js b/src/_h5ai/js/inc/core.js deleted file mode 100644 index 02f5fb2d..00000000 --- a/src/_h5ai/js/inc/core.js +++ /dev/null @@ -1,311 +0,0 @@ - -Module.define('core', [jQuery, 'settings', 'types', 'util'], function ($, settings, types, util) { - - var $window = $(window), - extToFileType = (function (types) { - var map = {}; - $.each(types, function (type, exts) { - $.each(exts, function (idx, ext) { - map[ext] = type; - }); - }); - return map; - }(types)), - hash = function (obj) { - - if ($.isPlainObject(obj)) { - var hashStr = ''; - $.each($.extend({}, hash(), obj), function (key, value) { - if (value) { - hashStr += '/' + encodeURIComponent(key) + '=' + encodeURIComponent(value); - } - }); - hashStr = '#!' + hashStr; - // window.location.hash = hashStr; - return hashStr; - } else { - var result = {}, - parts = document.location.hash.split('/'); - - if (parts.length >= 2 || parts[0] === '#!') { - parts.shift(); - $.each(parts, function (idx, part) { - - var match = /^([^=]*)=(.*?)$/.exec(part); - if (match) { - result[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); - } - }); - } - return typeof obj === 'string' ? result[obj] : result; - } - }, - api = function () { - - return settings.h5aiAbsHref + "php/api.php"; - }, - image = function (id, noPngExt) { - - return settings.h5aiAbsHref + "images/" + id + (noPngExt ? "" : ".png"); - }, - icon = function (id, big) { - - return settings.h5aiAbsHref + "icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png"; - }, - viewmode = function (viewmode) { - - var $viewDetails = $("#viewdetails"), - $viewIcons = $("#viewicons"), - $extended = $("#extended"); - - if (viewmode) { - amplify.store(settings.store.viewmode, viewmode); - } else { - viewmode = amplify.store(settings.store.viewmode); - } - viewmode = $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0]; - hash({view: viewmode}); - - $viewDetails.add($viewIcons).removeClass("current"); - if (viewmode === "details") { - $viewDetails.addClass("current"); - $extended.addClass("details-view").removeClass("icons-view").show(); - } else if (viewmode === "icons") { - $viewIcons.addClass("current"); - $extended.removeClass("details-view").addClass("icons-view").show(); - } else { - $extended.hide(); - } - }, - initTopSpace = function () { - - var $body = $("body"), - $tree = $("#tree"), - adjustTopSpace = function () { - - var winHeight = $window.height(), - navHeight = $("body > nav").outerHeight(), - footerHeight = $("body > footer").outerHeight(), - contentSpacing = 50, - treeSpacing = 0; - - $body.css({ - "margin-top": navHeight + contentSpacing, - "margin-bottom": footerHeight + contentSpacing - }); - - $tree.css({ - top: navHeight + treeSpacing, - height: winHeight - navHeight - footerHeight - 16 - 2 * treeSpacing - }); - - try { - $tree.get(0).updateScrollbar(); - } catch (err) {} - }; - - $window.resize(function () { - adjustTopSpace(); - }); - adjustTopSpace(); - }, - initViews = function () { - - var $navbar = $("#navbar"), - $extended = $("#extended"); - - $("#table").remove(); - - if (settings.viewmodes.length > 1) { - if ($.inArray("icons", settings.viewmodes) >= 0) { - $("
    • view-iconsicons
    • ") - .find("img").attr("src", image("view-icons")).end() - .find("a").click(function (event) { - viewmode("icons"); - event.preventDefault(); - }).end() - .appendTo($navbar); - } - if ($.inArray("details", settings.viewmodes) >= 0) { - $("
    • view-detailsdetails
    • ") - .find("img").attr("src", image("view-details")).end() - .find("a").click(function (event) { - viewmode("details"); - event.preventDefault(); - }).end() - .appendTo($navbar); - } - } - - // status update - $extended.find(".entry a").hover( - function () { - if ($extended.hasClass("icons-view")) { - var $this = $(this); - $(".status.default").hide(); - $(".status.dynamic") - .empty() - .append($this.find(".label").clone()) - .append($("·")) - .append($this.find(".date").clone()) - .show(); - - if (!$this.closest(".entry").hasClass("folder")) { - $(".status.dynamic") - .append($("·")) - .append($this.find(".size").clone()); - } - } - }, - function () { - $(".status.default").show(); - $(".status.dynamic").empty().hide(); - } - ); - }, - shiftTree = function (forceVisible, dontAnimate) { - - var $tree = $("#tree"), - $extended = $("#extended"); - - if ((settings.slideTree && $tree.outerWidth() < $extended.offset().left) || forceVisible) { - if (dontAnimate) { - $tree.stop().css({ left: 0 }); - } else { - $tree.stop().animate({ left: 0 }); - } - } else { - if (dontAnimate) { - $tree.stop().css({ left: 18 - $tree.outerWidth() }); - } else { - $tree.stop().animate({ left: 18 - $tree.outerWidth() }); - } - } - }, - initTree = function () { - - $("#tree").hover( - function () { shiftTree(true); }, - function () { shiftTree(); } - ); - $window.resize(function () { shiftTree(); }); - shiftTree(false, true); - }, - selectLinks = function (href) { - - var elements = []; - $("a[href^='/']").each(function () { - - if ($(this).attr("href") === href) { - elements.push(this); - } - }); - return $(elements); - }, - linkHoverStates = function () { - - if (settings.linkHoverStates) { - $("a[href^='/']:not(.linkedHoverStates)").each(function () { - - var $a = $(this).addClass("linkedHoverStates"), - href = $a.attr("href"); - - $a.hover( - function () { selectLinks(href).addClass("hover"); }, - function () { selectLinks(href).removeClass("hover"); } - ); - }); - } - }, - onIndicatorClick = function (event) { - - var $indicator = $(this), - $entry = $indicator.closest(".entry"), - updateTreeScrollbar = $("#tree").get(0).updateScrollbar; - - if ($indicator.hasClass("unknown")) { - $.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) { - - var $content = $(html); - - $indicator.removeClass("unknown"); - if ($content.find("> li").size() === 0) { - $indicator.replaceWith($("")); - } else { - $indicator.addClass("open"); - $entry.find("> .content").replaceWith($content); - updateTreeScrollbar(); - $content.find(".indicator:not(.initiated)") - .click(onIndicatorClick) - .addClass("initiated"); - } - }); - } else if ($indicator.hasClass("open")) { - $indicator.removeClass("open"); - updateTreeScrollbar(true); - $entry.find("> .content").slideUp(function () { - updateTreeScrollbar(); - }); - } else { - $indicator.addClass("open"); - updateTreeScrollbar(true); - $entry.find("> .content").slideDown(function () { - updateTreeScrollbar(); - }); - } - }, - initIndicators = function () { - - $("#tree .entry.folder .indicator:not(.initiated)") - .click(onIndicatorClick) - .addClass("initiated"); - }, - getFileType = function (filename) { - - var dotidx = filename.lastIndexOf('.'), - ext = dotidx >= 0 ? filename.substr(dotidx) : filename; - - return extToFileType[ext.toLowerCase()] || "unknown"; - }, - formatSizes = function () { - - $("#extended .entry .size").each(function () { - - var $this = $(this), - bytes = $this.data("bytes"), - formattedSize = bytes >= 0 ? util.formatSize(bytes) : ""; - - $this.text(formattedSize); - }); - }, - setTotals = function () { - - var $extended = $("#extended"); - - $(".folderTotal").text($extended.find(".entry.folder:not(.folder-parent)").length); - $(".fileTotal").text($extended.find(".entry.file").length); - }, - init = function () { - - initViews(); - viewmode(); - initTopSpace(); - initTree(); - linkHoverStates(); - formatSizes(); - setTotals(); - initIndicators(); - }; - - return { - init: init, - hash: hash, - api: api, - image: image, - icon: icon, - shiftTree: shiftTree, - linkHoverStates: linkHoverStates, - initIndicators: initIndicators, - getFileType: getFileType - }; -}); diff --git a/src/_h5ai/js/inc/core/entry.js b/src/_h5ai/js/inc/core/entry.js new file mode 100644 index 00000000..dc5a1917 --- /dev/null +++ b/src/_h5ai/js/inc/core/entry.js @@ -0,0 +1,16 @@ + +module.define('core/entry', [jQuery, 'core/parser', 'model/entry'], function ($, parser, Entry) { + + var absHref = document.location.pathname; + + parser.parse(absHref, $('body')); + $('#data-apache-autoindex').remove(); + + var entry = Entry.get(absHref); + entry.status = 'h5ai'; + if (entry.parent) { + entry.parent.isParentFolder = true; + } + + return entry; +}); diff --git a/src/_h5ai/js/inc/core/event.js b/src/_h5ai/js/inc/core/event.js new file mode 100644 index 00000000..f8e84334 --- /dev/null +++ b/src/_h5ai/js/inc/core/event.js @@ -0,0 +1,25 @@ + +module.define('core/event', [amplify], function (amplify) { + + var sub = function (topic, callback) { + + amplify.subscribe(topic, callback); + }, + + unsub = function (topic, callback) { + + amplify.unsubscribe(topic, callback); + }, + + pub = function (topic, data) { + + // console.log('EVENT PUB', topic, data); + amplify.publish(topic, data); + }; + + return { + sub: sub, + unsub: unsub, + pub: pub + }; +}); diff --git a/src/_h5ai/js/inc/core/format.js b/src/_h5ai/js/inc/core/format.js new file mode 100644 index 00000000..c2008664 --- /dev/null +++ b/src/_h5ai/js/inc/core/format.js @@ -0,0 +1,80 @@ + +module.define('core/format', [moment], function (moment) { + + var reParseSize = /^\s*([\.\d]+)\s*([kmgt]?)b?\s*$/i, + treshhold = 1000.0, + kilo = 1000.0, + sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB'], + + parseSize = function (str) { + + var match = reParseSize.exec(str), + val, unit; + + if (!match) { + return null; + } + + val = parseFloat(match[1]); + unit = match[2].toLowerCase(); + if (unit === 'k') { + val *= kilo; + } else if (unit === 'm') { + val *= kilo * kilo; + } else if (unit === 'g') { + val *= kilo * kilo * kilo; + } else if (unit === 't') { + val *= kilo * kilo * kilo * kilo; + } + return val; + }, + + formatSize = function (size) { + + if (!_.isNumber(size) || size < 0) { + return ''; + } + + var i = 0, + maxI = sizeUnits.length - 1; + + while (size >= treshhold && i < maxI) { + size /= kilo; + i += 1; + } + return (i <= 1 ? Math.round(size) : size.toFixed(1)).toString() + ' ' + sizeUnits[i]; + }, + + defaultDateFormat = 'YYYY-MM-DD HH:mm', + + setDefaultDateFormat = function (dateFormat) { + + defaultDateFormat = dateFormat; + }, + + parseDate = function (str, dateFormat) { + + try { // problems with ie < 9 :( + return moment(str, dateFormat || defaultDateFormat).valueOf() || null; + } catch (err) {} + + return Date.parse(str).valueOf() || null; + }, + + formatDate = function (millis, dateFormat) { + + if (!_.isNumber(millis) || !millis) { + return ''; + } + + return moment(millis).format(dateFormat || defaultDateFormat); + }; + + return { + parseSize: parseSize, + formatSize: formatSize, + setDefaultDateFormat: setDefaultDateFormat, + parseDate: parseDate, + formatDate: formatDate + }; +}); diff --git a/src/_h5ai/js/inc/core/parser.js b/src/_h5ai/js/inc/core/parser.js new file mode 100644 index 00000000..72943ae6 --- /dev/null +++ b/src/_h5ai/js/inc/core/parser.js @@ -0,0 +1,9 @@ + +module.define('core/parser', [jQuery], function ($) { + + if ($('#data-generic-json').length) { + return module.require('parser/generic-json'); + } + + return module.require('parser/apache-autoindex'); +}); diff --git a/src/_h5ai/js/inc/core/resource.js b/src/_h5ai/js/inc/core/resource.js new file mode 100644 index 00000000..add1636a --- /dev/null +++ b/src/_h5ai/js/inc/core/resource.js @@ -0,0 +1,22 @@ + +module.define('core/resource', ['core/settings'], function (settings) { + + var api = function () { + + return settings.h5aiAbsHref + 'php/api.php'; + }, + image = function (id, noPngExt) { + + return settings.h5aiAbsHref + 'images/' + id + (noPngExt ? '' : '.png'); + }, + icon = function (id, big) { + + return settings.h5aiAbsHref + 'icons/' + (big ? '48x48' : '16x16') + '/' + id + '.png'; + }; + + return { + api: api, + image: image, + icon: icon + }; +}); diff --git a/src/_h5ai/js/inc/core/settings.js b/src/_h5ai/js/inc/core/settings.js new file mode 100644 index 00000000..dc7bd240 --- /dev/null +++ b/src/_h5ai/js/inc/core/settings.js @@ -0,0 +1,32 @@ + +module.define('core/config', [H5AI_CONFIG], function (config) { + + var defaults = { + rootAbsHref: '/', + h5aiAbsHref: '/_h5ai/', + }; + + return { + settings: _.extend({}, defaults, config.options), + types: _.extend({}, config.types), + langs: _.extend({}, config.langs) + }; +}); + + +module.define('core/settings', ['core/config'], function (config) { + + return config.settings; +}); + + +module.define('core/types', ['core/config'], function (config) { + + return config.types; +}); + + +module.define('core/langs', ['core/config'], function (config) { + + return config.langs; +}); diff --git a/src/_h5ai/js/inc/core/store.js b/src/_h5ai/js/inc/core/store.js new file mode 100644 index 00000000..04d297b1 --- /dev/null +++ b/src/_h5ai/js/inc/core/store.js @@ -0,0 +1,18 @@ + +module.define('core/store', [amplify], function (amplify) { + + var put = function (key, value) { + + amplify.store(key, value); + }, + + get = function (key) { + + return amplify.store(key); + }; + + return { + put: put, + get: get + }; +}); diff --git a/src/_h5ai/js/inc/ext/crumb.js b/src/_h5ai/js/inc/ext/crumb.js new file mode 100644 index 00000000..205f76fc --- /dev/null +++ b/src/_h5ai/js/inc/ext/crumb.js @@ -0,0 +1,84 @@ + +module.define('ext/crumb', [jQuery, 'core/settings', 'core/resource', 'core/entry'], function ($, allsettings, resource, entry) { + + var defaults = { + enabled: true + }, + + settings = _.extend({}, defaults, allsettings.crumb), + + template = '
    • ' + + '' + + '>' + + '' + + '' + + '
    • ', + pageHintTemplate = 'has index page', + statusHintTemplate = '', + + // updates the crumb for this single entry + update = function (entry) { + + if (entry.$crumb && entry.$crumb.data('status') === entry.status) { + return entry.$crumb; + } + + var $html = $(template), + $a = $html.find('a'); + + $html + .addClass(entry.isFolder() ? 'folder' : 'file') + .data('status', entry.status); + + $a + .attr('href', entry.absHref) + .find('span').text(entry.label).end(); + + if (entry.isDomain()) { + $html.addClass('domain'); + $a.find('img').attr('src', resource.image('home')); + } + + if (entry.isCurrentFolder()) { + $html.addClass('current'); + } + + if (_.isNumber(entry.status)) { + if (entry.status === 200) { + $a.append($(pageHintTemplate)); + } else { + $a.append($(statusHintTemplate).text('(' + entry.status + ')')); + } + } + + if (entry.$crumb) { + entry.$crumb.replaceWith($html); + } + entry.$crumb = $html; + + return $html; + }, + + // creates the complete crumb from entry down to the root + init = function (entry) { + + if (!settings.enabled) { + return; + } + + var crumb = entry.getCrumb(), + $ul = $('#navbar'); + + _.each(crumb, function (e) { + + $ul.append(update(e)); + + e.fetchStatus(function (e) { + + update(e); + }); + }); + }; + + init(entry); +}); diff --git a/src/_h5ai/js/inc/ext/custom.js b/src/_h5ai/js/inc/ext/custom.js new file mode 100644 index 00000000..2154026d --- /dev/null +++ b/src/_h5ai/js/inc/ext/custom.js @@ -0,0 +1,42 @@ + +module.define('ext/custom', [jQuery, 'core/settings'], function ($, allsettings) { + + var defaults = { + enabled: false, + header: '_h5ai.header.html', + footer: '_h5ai.footer.html' + }, + + settings = _.extend({}, defaults, allsettings.custom), + + init = function () { + + if (!settings.enabled) { + return; + } + + if (_.isString(settings.header)) { + $.ajax({ + url: settings.header, + dataType: 'html', + success: function (data) { + + $('
      ' + data + '
      ').prependTo('#content'); + } + }); + } + + if (_.isString(settings.footer)) { + $.ajax({ + url: settings.footer, + dataType: 'html', + success: function (data) { + + $('').appendTo('#content'); + } + }); + } + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/ext/filter.js b/src/_h5ai/js/inc/ext/filter.js new file mode 100644 index 00000000..b81d9c77 --- /dev/null +++ b/src/_h5ai/js/inc/ext/filter.js @@ -0,0 +1,123 @@ + +module.define('ext/filter', [jQuery, 'core/settings', 'core/resource'], function ($, allsettings, resource) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings.filter), + + template = '
    • ' + + '' + + 'filter' + + '' + + '' + + '
    • ', + noMatchTemplate = '
      no match
      ', + + $filter, $input, $noMatch, + + filter = function (re) { + + var match = [], + noMatch = [], + duration = 200; + + if (re) { + $('#extended .entry').each(function () { + + var label = $(this).find('.label').text(); + + if (label.match(re)) { + match.push(this); + } else { + noMatch.push(this); + } + }); + } else { + match = $('#extended .entry'); + } + + if ($(match).length) { + $noMatch.hide(); + } else { + setTimeout(function () { $noMatch.show(); }, duration); + } + $(match).fadeIn(duration); + $(noMatch).fadeOut(duration); + }, + + checkState = function (focus) { + + var val = $input.val(); + + if (val || focus) { + $filter.addClass('current'); + } else { + $filter.removeClass('current'); + } + }, + + escapeRegExp = function (sequence) { + + return sequence.replace(/[\-\[\]{}()*+?.,\\$\^|#\s]/g, '\\$&'); + // return sequence.replace(/[|()\[{.+*?^$\\]/g,"\\$0"); + }, + + parseFilterSequence = function (sequence) { + + if (sequence.substr(0, 3) === 're:') { + return new RegExp(sequence.substr(3)); + } + + sequence = $.map($.trim(sequence).split(/\s+/), function (part) { + + return escapeRegExp(part); + }).join('|'); + + return new RegExp(sequence); + }, + + update = function () { + + var val = $input.val(); + + if (val) { + filter(parseFilterSequence(val)); + } else { + filter(); + } + checkState($input.is(':focus')); + }, + + init = function () { + + if (!settings.enabled) { + return; + } + + $filter = $(template); + $input = $filter.find('input'); + $noMatch = $(noMatchTemplate).appendTo($('#extended')); + + $filter + .on('click', function () { + + $input.focus(); + }) + .appendTo($('#navbar')); + + $input + .on('focus', function () { + + checkState(true); + }) + .on('blur', function () { + + checkState(false); + }) + .on('keyup', update); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/ext/folderstatus.js b/src/_h5ai/js/inc/ext/folderstatus.js new file mode 100644 index 00000000..bdfc7ebe --- /dev/null +++ b/src/_h5ai/js/inc/ext/folderstatus.js @@ -0,0 +1,14 @@ + +module.define('ext/folderstatus', [jQuery, 'core/settings'], function ($, allsettings) { + + var defaults = { + enabled: true, + folders: {} + }, + + settings = _.extend({}, defaults, allsettings.folderstatus), + + folders = settings.enabled ? settings.folders : defaults.folders; + + return folders; +}); diff --git a/src/_h5ai/js/inc/localize.js b/src/_h5ai/js/inc/ext/l10n.js similarity index 54% rename from src/_h5ai/js/inc/localize.js rename to src/_h5ai/js/inc/ext/l10n.js index e3069e33..376f0745 100644 --- a/src/_h5ai/js/inc/localize.js +++ b/src/_h5ai/js/inc/ext/l10n.js @@ -1,26 +1,29 @@ -Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, settings, langs, core) { +module.define('ext/l10n', [jQuery, 'core/settings', 'core/langs', 'core/format', 'core/store'], function ($, allsettings, langs, format, store) { - var currentDateFormat = settings.dateFormat, - formatDates = function (dateFormat) { - - if (dateFormat) { - currentDateFormat = dateFormat; - } - - $('#extended .entry .date').each(function () { - - var $this = $(this), - time = $this.data('time'), - formattedDate = time ? moment(time).format(currentDateFormat) : ''; - - $this.text(formattedDate); - }); + var defaults = { + enabled: true, + lang: "en", + useBrowserLang: true, + defaultDateFormat: 'YYYY-MM-DD HH:mm' }, + + settings = _.extend({}, defaults, allsettings.l10n), + + template = '' + + 'en - english' + + '
        ' + + '', + langOptionTemplate = '
      • ', + + storekey = 'h5ai.language', + + currentLang = null, + localize = function (langs, lang, useBrowserLang) { - var storedLang = amplify.store(settings.store.lang), - browserLang, selected, key; + var storedLang = store.get(storekey), + browserLang, key; if (langs[storedLang]) { lang = storedLang; @@ -39,38 +42,45 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se lang = 'en'; } - selected = langs[lang]; - if (selected) { - $.each(selected, function (key, value) { + currentLang = langs[lang]; + if (currentLang) { + $.each(currentLang, function (key, value) { $('.l10n-' + key).text(value); }); $('.lang').text(lang); $('.langOption').removeClass('current'); $('.langOption.' + lang).addClass('current'); - core.hash({lang: lang}); } - formatDates(selected.dateFormat || settings.dateFormat); + format.setDefaultDateFormat(currentLang.dateFormat || settings.defaultDateFormat); + + $('#extended .entry .date').each(function () { + + var $this = $(this); + + $this.text(format.formatDate($this.data('time'))); + }); }, + initLangSelector = function (langs) { - var $langOptions = $('#langSelector .langOptions'), - sortedLangsKeys = [], - $ul; + var $langSelector = $(template).appendTo('#bottombar .right'), + $langOptions = $langSelector.find('.langOptions'), + $ul = $langOptions.find('ul'), + sortedLangsKeys = []; $.each(langs, function (lang) { sortedLangsKeys.push(lang); }); sortedLangsKeys.sort(); - $ul = $('
          '); $.each(sortedLangsKeys, function (idx, lang) { - $('
        • ') + $(langOptionTemplate) .addClass(lang) .text(lang + ' - ' + langs[lang].lang) .appendTo($ul) .click(function () { - amplify.store(settings.store.lang, lang); + store.put(storekey, lang); localize(langs, lang, false); }); }); @@ -78,7 +88,7 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se .append($ul) .scrollpanel(); - $('#langSelector').hover( + $langSelector.hover( function () { $langOptions .css('top', '-' + $langOptions.outerHeight() + 'px') @@ -93,15 +103,16 @@ Module.define('localize', [jQuery, 'settings', 'langs', 'core'], function ($, se } ); }, + init = function () { + if (!settings.enabled) { + return; + } + initLangSelector(langs); localize(langs, settings.lang, settings.useBrowserLang); }; - return { - init: init, - formatDates: formatDates - }; - + init(); }); diff --git a/src/_h5ai/js/inc/ext/link-hover-states.js b/src/_h5ai/js/inc/ext/link-hover-states.js new file mode 100644 index 00000000..ea65755f --- /dev/null +++ b/src/_h5ai/js/inc/ext/link-hover-states.js @@ -0,0 +1,44 @@ + +module.define('ext/link-hover-states', [jQuery, 'core/settings'], function ($, allsettings) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings['link-hover-states']), + + selector = "a[href^='/']", + + selectLinks = function (href) { + + return $(_.filter($(selector), function (el) { + + return $(el).attr('href') === href; + })); + }, + + onMouseEnter = function () { + + var href = $(this).attr('href'); + + selectLinks(href).addClass('hover'); + }, + + onMouseLeave = function () { + + var href = $(this).attr('href'); + + selectLinks(href).removeClass('hover'); + }, + + init = function () { + + if (settings.enabled) { + $('body') + .on('mouseenter', selector, onMouseEnter) + .on('mouseleave', selector, onMouseLeave); + } + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/ext/qrcode.js b/src/_h5ai/js/inc/ext/qrcode.js new file mode 100644 index 00000000..62b15304 --- /dev/null +++ b/src/_h5ai/js/inc/ext/qrcode.js @@ -0,0 +1,56 @@ + +module.define('ext/qrcode', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) { + + var defaults = { + enabled: false, + size: 150 + }, + + settings = _.extend({}, defaults, allsettings.qrcode), + + template = '
          ', + + $context, hideTimeoutId, + + update = function (entry) { + + $context.find('.qrcode').empty().qrcode({ + render: Modernizr.canvas ? 'canvas' : 'div', + width: settings.size, + height: settings.size, + color: '#333', + text: 'http://' + document.domain + entry.absHref + }); + }, + + onMouseenter = function (entry) { + + if (!entry.isFolder()) { + update(entry); + clearTimeout(hideTimeoutId); + $context.stop(true, true).fadeIn(400); + } + }, + + onMouseleave = function (entry) { + + hideTimeoutId = setTimeout(function () { + + $context.stop(true, true).fadeOut(400); + }, 200); + }, + + init = function () { + + if (!settings.enabled) { + return; + } + + $context = $(template).appendTo('body'); + + event.sub('entry.mouseenter', onMouseenter); + event.sub('entry.mouseleave', onMouseleave); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/ext/select.js b/src/_h5ai/js/inc/ext/select.js new file mode 100644 index 00000000..2cb6ada2 --- /dev/null +++ b/src/_h5ai/js/inc/ext/select.js @@ -0,0 +1,114 @@ + +module.define('ext/select', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings.select), + + x = 0, + y = 0, + $document = $(document), + $selectionRect = $('
          '), + + publish = function () { + + var entries = _.map($('#extended .entry.selected'), function (entryElement) { + + return $(entryElement).data('entry'); + }); + + event.pub('selection', entries); + }, + + selectionUpdate = function (event) { + + var l = Math.min(x, event.pageX), + t = Math.min(y, event.pageY), + w = Math.abs(x - event.pageX), + h = Math.abs(y - event.pageY), + selRect; + + event.preventDefault(); + $selectionRect.css({left: l, top: t, width: w, height: h}); + + selRect = $selectionRect.fracs('rect'); + $('#extended .entry').removeClass('selecting').each(function () { + + var $entry = $(this), + rect = $entry.find('a').fracs('rect'), + inter = selRect.intersection(rect); + if (inter && !$entry.hasClass('folder-parent')) { + $entry.addClass('selecting'); + } + }); + }, + + selectionEnd = function (event) { + + event.preventDefault(); + $document.off('mousemove', selectionUpdate); + $selectionRect.hide().css({left: 0, top: 0, width: 0, height: 0}); + $('#extended .entry.selecting.selected').removeClass('selecting').removeClass('selected'); + $('#extended .entry.selecting').removeClass('selecting').addClass('selected'); + publish(); + }, + + selectionStart = function (event) { + + var view = $(document).fracs('viewport'); + + x = event.pageX; + y = event.pageY; + // only on left button and don't block the scrollbars + if (event.button !== 0 || x >= view.right || y >= view.bottom) { + return; + } + + event.preventDefault(); + $(':focus').blur(); + if (!event.ctrlKey) { + $('#extended .entry').removeClass('selected'); + publish(); + } + $selectionRect.show().css({left: x, top: y, width: 0, height: 0}); + + $document + .on('mousemove', selectionUpdate) + .one('mouseup', selectionEnd); + }, + + noSelection = function (event) { + + event.stopImmediatePropagation(); + return false; + }, + + noSelectionUnlessCtrl = function (event) { + + if (!event.ctrlKey) { + noSelection(event); + } + }, + + init = function () { + + if (!settings.enabled) { + return; + } + + $selectionRect.hide().appendTo($('body')); + + // $('#topbar,#bottombar,#tree,input').on('mousedown', noSelection); + // $('#content').on('mousedown', 'a', noSelectionUnlessCtrl); + // $document.on('mousedown', selectionStart); + + $document + .on('mousedown', '.noSelection', noSelection) + .on('mousedown', '.noSelectionUnlessCtrl,input,a', noSelectionUnlessCtrl) + .on('mousedown', selectionStart); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/sort.js b/src/_h5ai/js/inc/ext/sort.js similarity index 78% rename from src/_h5ai/js/inc/sort.js rename to src/_h5ai/js/inc/ext/sort.js index 2afac511..912849c1 100644 --- a/src/_h5ai/js/inc/sort.js +++ b/src/_h5ai/js/inc/ext/sort.js @@ -1,7 +1,16 @@ -Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core) { +module.define('ext/sort', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) { - var type = function (entry) { + var defaults = { + enabled: false, + order: 'na' + }, + + settings = _.extend({}, defaults, allsettings.sort), + + storekey = 'h5ai.sortorder', + + type = function (entry) { var $entry = $(entry); @@ -54,17 +63,21 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core) var order = orders[id]; + store.put(storekey, id); + $all.removeClass('ascending').removeClass('descending'); order.head.addClass(order.clas); $('#extended .entry').detach().sort(order.fn).appendTo($('#extended > ul')); - core.hash({sort: id}); }, init = function () { - var $ascending = $('ascending'), - $descending = $('descending'), - initialOrder = core.hash('sort'), + if (!settings.enabled) { + return; + } + + var $ascending = $('ascending'), + $descending = $('descending'), $header = $('#extended li.header'), $label = $header.find('a.label'), $date = $header.find('a.date'), @@ -104,7 +117,7 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core) } }; - sortBy(initialOrder || settings.sortorder); + sortBy(store.get(storekey) || settings.order); $label .append($ascending.clone()).append($descending.clone()) @@ -128,7 +141,5 @@ Module.define('sort', [jQuery, 'settings', 'core'], function ($, settings, core) }); }; - return { - init: init - }; + init(); }); diff --git a/src/_h5ai/js/inc/ext/statusbar.js b/src/_h5ai/js/inc/ext/statusbar.js new file mode 100644 index 00000000..e7cf4a29 --- /dev/null +++ b/src/_h5ai/js/inc/ext/statusbar.js @@ -0,0 +1,76 @@ + +module.define('ext/statusbar', [jQuery, 'core/settings', 'core/format', 'core/event', 'core/entry'], function ($, allsettings, format, event, entry) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings.statusbar), + + template = '' + + '' + + ' folders' + + '·' + + ' files' + + '' + + '' + + '', + sepTemplate = '·', + + $statusDynamic, + $statusDefault, + + update = function (html) { + + if (html) { + $statusDefault.hide(); + $statusDynamic.empty().append(html).show(); + } else { + $statusDynamic.empty().hide(); + $statusDefault.show(); + } + }, + + init = function (entry) { + + if (!settings.enabled) { + return; + } + + var $statusbar = $(template), + $folderTotal = $statusbar.find('.folderTotal'), + $fileTotal = $statusbar.find('.fileTotal'); + + $statusDefault = $statusbar.find('.status.default'); + $statusDynamic = $statusbar.find('.status.dynamic'); + + var stats = entry.getStats(); + $folderTotal.text(stats.folders); + $fileTotal.text(stats.files); + + update(); + + event.sub('statusbar', update); + $('#bottombar > .center').append($statusbar); + + + + event.sub('entry.mouseenter', function (entry) { + + var $span = $('').append(entry.label).append(sepTemplate).append(format.formatDate(entry.time)); + + if (!entry.isFolder()) { + $span.append(sepTemplate).append(format.formatSize(entry.size)); + } + + update($span); + }); + + event.sub('entry.mouseleave', function (entry) { + + update(); + }); + }; + + init(entry); +}); diff --git a/src/_h5ai/js/inc/ext/thumbnails.js b/src/_h5ai/js/inc/ext/thumbnails.js new file mode 100644 index 00000000..2e37619f --- /dev/null +++ b/src/_h5ai/js/inc/ext/thumbnails.js @@ -0,0 +1,59 @@ + +module.define('ext/thumbnails', [jQuery, 'core/settings', 'core/resource', 'core/entry'], function ($, allsettings, resource, entry) { + + var defaults = { + enabled: false, + types: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"], + delay: 1000 + }, + + settings = _.extend({}, defaults, allsettings.thumbnails), + + requestThumb = function ($img, data) { + + $.getJSON(resource.api(), data, function (json) { + + if (json.code === 0) { + $img.addClass('thumb').attr('src', json.absHref); + } + }); + }, + + checkEntry = function (entry) { + + if (entry.$extended && $.inArray(entry.type, settings.types) >= 0) { + + var $imgSmall = entry.$extended.find('.icon.small img'); + var $imgBig = entry.$extended.find('.icon.big img'); + + requestThumb($imgSmall, { + action: 'thumbsrc', + href: entry.absHref, + width: 16, + height: 16, + mode: 'square' + }); + requestThumb($imgBig, { + action: 'thumbsrc', + href: entry.absHref, + width: 100, + height: 48, + mode: 'rational' + }); + } + }, + + init = function (entry) { + + if (!settings.enabled) { + return; + } + + setTimeout(function () { + + _.each(entry.content, checkEntry); + }, settings.delay); + }; + + init(entry); +}); diff --git a/src/_h5ai/js/inc/ext/title.js b/src/_h5ai/js/inc/ext/title.js new file mode 100644 index 00000000..d49081f1 --- /dev/null +++ b/src/_h5ai/js/inc/ext/title.js @@ -0,0 +1,27 @@ + +module.define('ext/title', [jQuery, 'core/settings', 'core/entry'], function ($, allsettings, entry) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings.title), + + init = function (entry) { + + if (!settings.enabled) { + return; + } + + var labels = _.pluck(entry.getCrumb(), 'label'), + title = labels.join(' > '); + + if (labels.length > 1) { + title = labels[labels.length - 1] + ' - ' + title; + } + + document.title = title; + }; + + init(entry); +}); diff --git a/src/_h5ai/js/inc/ext/tree.js b/src/_h5ai/js/inc/ext/tree.js new file mode 100644 index 00000000..19476af6 --- /dev/null +++ b/src/_h5ai/js/inc/ext/tree.js @@ -0,0 +1,227 @@ + +module.define('ext/tree', [jQuery, 'core/settings', 'core/resource', 'core/event', 'core/entry', 'core/parser'], function ($, allsettings, resource, event, entry, parser) { + + var defaults = { + enabled: false, + slide: true + }, + + settings = _.extend({}, defaults, allsettings.tree), + + template = '
          ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + statusHintTemplate = '', + + // updates the tree for this single entry + update = function (entry) { + + var $html = $(template), + $indicator = $html.find('.indicator'), + $a = $html.find('a'), + $img = $html.find('.icon img'), + $label = $html.find('.label'); + + $html + .addClass(entry.isFolder() ? 'folder' : 'file') + .data('entry', entry) + .data('status', entry.status); + + $a.attr('href', entry.absHref); + $img.attr('src', resource.icon(entry.type)); + $label.text(entry.label); + + if (entry.isFolder()) { + + var subfolders = entry.getSubfolders(); + + // indicator + if (!entry.status || (entry.status === 'h5ai' && !entry.isContentFetched) || subfolders.length) { + + $indicator.removeClass('none'); + + if (!entry.status || (entry.status === 'h5ai' && !entry.isContentFetched)) { + $indicator.addClass('unknown'); + } else if (entry.isContentVisible) { + $indicator.addClass('open'); + } else { + $indicator.addClass('close'); + } + } + + // is it the domain? + if (entry.isDomain()) { + $html.addClass('domain'); + $img.attr('src', resource.icon('folder-home')); + } + + // is it the current folder? + if (entry.isCurrentFolder()) { + $html.addClass('current'); + $img.attr('src', resource.icon('folder-open')); + } + + // does it have subfolders? + if (subfolders.length) { + var $ul = $('
            ').appendTo($html); + _.each(subfolders, function (e) { + $('
          • ').append(update(e)).appendTo($ul); + }); + if (!entry.isContentVisible) { + $ul.hide(); + } + } + + // reflect folder status + if (_.isNumber(entry.status)) { + if (entry.status === 200) { + $img.attr('src', resource.icon('folder-page')); + } else { + $html.addClass('error'); + $a.append($(statusHintTemplate).text(entry.status)); + } + } + } + + + if (entry.$tree) { + entry.$tree.replaceWith($html); + } + entry.$tree = $html; + + return $html; + }, + + createOnIndicatorClick = function (parser) { + + var $tree = $('#tree'), + tree = $tree.get(0), + slide = function (entry, $indicator, $content, down) { + + entry.isContentVisible = down; + $indicator.removeClass('open close').addClass(down ? 'open' : 'close'); + tree.updateScrollbar(true); + $content[down ? 'slideDown' : 'slideUp'](function () { + + tree.updateScrollbar(); + }); + }; + + return function () { + + var $indicator = $(this), + $entry = $indicator.closest('.entry'), + entry = $entry.data('entry'), + $content = $entry.find('> ul.content'); + + if ($indicator.hasClass('unknown')) { + + entry.fetchContent(parser, function (entry) { + + entry.isContentVisible = false; + + var $entry = update(entry), + $indicator = $entry.find('> .indicator'), + $content = $entry.find('> ul.content'); + + if (!$indicator.hasClass('none')) { + slide(entry, $indicator, $content, true); + } + }); + + } else if ($indicator.hasClass('open')) { + + slide(entry, $indicator, $content, false); + + } else if ($indicator.hasClass('close')) { + + slide(entry, $indicator, $content, true); + } + }; + }, + + shiftTree = function (forceVisible, dontAnimate) { + + var $tree = $("#tree"), + $extended = $("#extended"), + left = ((settings.slide && $tree.outerWidth() < $extended.offset().left) || forceVisible || !$extended.is(':visible')) ? 0 : 18 - $tree.outerWidth(); + + if (dontAnimate) { + $tree.stop().css({ left: left }); + } else { + $tree.stop().animate({ left: left }); + } + }, + + fetchTree = function (entry, parser, callback) { + + entry.isContentVisible = true; + entry.fetchContent(parser, function (entry) { + + if (entry.parent) { + fetchTree(entry.parent, parser, callback); + } else { + callback(entry); + } + }); + }, + + adjustSpacing = function () { + + var $tree = $('#tree'), + tree = $tree[0], + winHeight = $(window).height(), + navHeight = $('#topbar').outerHeight(), + footerHeight = $('#bottombar').outerHeight(); + + $tree.css({ + top: navHeight, + height: winHeight - navHeight - footerHeight - 16 + }); + + if (tree.updateScrollbar) { + tree.updateScrollbar(); + } + }, + + // creates the complete tree from entry down to the root + init = function (entry, parser) { + + if (!settings.enabled) { + return; + } + + var $tree = $('
            ').appendTo($('body')); + + fetchTree(entry, parser, function (root) { + + $tree + .append(update(root)) + .scrollpanel() + .show(); + + adjustSpacing(); + shiftTree(false, true); + setTimeout(function () { $tree.get(0).updateScrollbar(); }, 1); + }); + + $tree + .on('click', '.indicator', createOnIndicatorClick(parser)) + .on('mouseenter', function () { shiftTree(true); }) + .on('mouseleave', function () { shiftTree(); }); + + event.sub('ready', adjustSpacing); + $(window).on('resize', function () { + adjustSpacing(); + shiftTree(); + }); + }; + + init(entry, parser); +}); diff --git a/src/_h5ai/js/inc/ext/zipped-download.js b/src/_h5ai/js/inc/ext/zipped-download.js new file mode 100644 index 00000000..b0975c7b --- /dev/null +++ b/src/_h5ai/js/inc/ext/zipped-download.js @@ -0,0 +1,133 @@ + +module.define('ext/zipped-download', [jQuery, 'core/settings', 'core/resource', 'core/event'], function ($, allsettings, resource, event) { + + var defaults = { + enabled: false + }, + + settings = _.extend({}, defaults, allsettings['zipped-download']), + + downloadBtnTemplate = '
          • ' + + '' + + 'download' + + 'download' + + '' + + '
          • ', + authTemplate = '
            ' + + '' + + '' + + '
            ', + + selectedHrefsStr = '', + $download, $img, $downloadAuth, $downloadUser, $downloadPassword, + + failed = function () { + + $download.addClass('failed'); + setTimeout(function () { + $download.removeClass('failed'); + }, 1000); + }, + + handleResponse = function (response) { + + $download.removeClass('current'); + $img.attr('src', resource.image('download')); + + if (response) { + if (response.status === 'ok') { + setTimeout(function () { // wait here so the img above can be updated in time + + window.location = resource.api() + '?action=getzip&id=' + response.id; + }, 200); + } else { + if (response.code === 401) { + $downloadAuth + .css({ + left: $download.offset().left, + top: $download.offset().top + $download.outerHeight() + }) + .show(); + $downloadUser.focus(); + } + failed(); + } + } else { + failed(); + } + }, + + requestZipping = function (hrefsStr) { + + $download.addClass('current'); + $img.attr('src', resource.image('loading.gif', true)); + $.ajax({ + url: resource.api(), + data: { + action: 'zip', + hrefs: hrefsStr + }, + type: 'POST', + dataType: 'json', + beforeSend: function (xhr) { + + var user = $downloadUser.val(), + password = $downloadPassword.val(); + + if (user) { + xhr.setRequestHeader('Authorization', 'Basic ' + Base64.encode(user + ':' + password)); + } + }, + success: function (response) { + + handleResponse(response); + }, + error: function () { + + handleResponse(); + } + }); + }, + + onSelection = function (entries) { + + var $downloadBtn = $('#download'); + + selectedHrefsStr = ''; + if (entries.length) { + selectedHrefsStr = _.map(entries, function (entry) { + + return entry.absHref; + }).join(':'); + $downloadBtn.show(); + } else { + $downloadBtn.hide(); + $downloadAuth.hide(); + } + }, + + init = function () { + + if (!settings.enabled) { + return; + } + + $download = $(downloadBtnTemplate) + .appendTo($('#navbar')) + .find('a').on('click', function (event) { + + event.preventDefault(); + $downloadAuth.hide(); + requestZipping(selectedHrefsStr); + }); + $img = $download.find('img'); + + $downloadAuth = $(authTemplate).appendTo($('body')); + $downloadUser = $downloadAuth.find('#download-auth-user'); + $downloadPassword = $downloadAuth.find('#download-auth-password'); + + event.sub('selection', onSelection); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/extended.js b/src/_h5ai/js/inc/extended.js deleted file mode 100644 index 5fac0f57..00000000 --- a/src/_h5ai/js/inc/extended.js +++ /dev/null @@ -1,130 +0,0 @@ - -Module.define('extended', [jQuery, 'settings', 'conhtml', 'util', 'core'], function ($, settings, conhtml, util, core) { - - var initBreadcrumb = function () { - - var $ul = $("body > nav ul"), - pathname = "/", - path = conhtml.getPath(pathname), - pathnameParts = document.location.pathname.split("/"), - lastPart = "", - title = document.domain; - - $ul.append(conhtml.updateCrumbHtml(path)); - - $.each(pathnameParts, function (idx, part) { - if (part !== "") { - pathname += part + "/"; - $ul.append(conhtml.updateCrumbHtml(conhtml.getPath(pathname))); - lastPart = part + " - "; - title += " > " + part; - } - }); - - document.title = util.checkedDecodeUri(lastPart + title); - }, - initExtendedView = function () { - - var $ul, $li; - - $ul = $("
              "); - $li = $("
            • ") - .appendTo($ul) - .append($("")) - .append($("")) - .append($("")) - .append($("")); - - // entries - $("#table td").closest("tr").each(function () { - var path = conhtml.getPath(document.location.pathname, this); - $ul.append(conhtml.updateExtendedHtml(path)); - }); - - $("#extended").append($ul); - - // empty - if ($ul.children(".entry:not(.folder-parent)").size() === 0) { - $("#extended").append($("
              empty
              ")); - } - - // no match - $("#extended").append($("
              no match
              ")); - }, - customize = function () { - - if (settings.customHeader) { - $.ajax({ - url: settings.customHeader, - dataType: "html", - success: function (data) { - $("#content > header").append($(data)).show(); - } - }); - } - - if (settings.customFooter) { - $.ajax({ - url: settings.customFooter, - dataType: "html", - success: function (data) { - $("#content > footer").prepend($(data)).show(); - } - }); - } - }, - fetchPath = function (pathname, callback) { - - conhtml.fetchStatusAndContent(pathname, false, function (status, content) { - - var path = conhtml.getPath(pathname); - - path.status = status; - path.content = content; - callback(path); - }); - }, - fetchTree = function (pathname, callback, childPath) { - - fetchPath(pathname, function (path) { - - var parent = util.splitPath(pathname).parent; - - path.treeOpen = true; - if (childPath) { - path.content[childPath.absHref] = childPath; - } - if (parent === null) { - callback(path); - } else { - fetchTree(parent, callback, path); - } - }); - }, - populateTree = function () { - - fetchTree(document.location.pathname, function (path) { - $("#tree") - .append(conhtml.updateTreeHtml(path)) - .scrollpanel() - .show(); - core.shiftTree(false, true); - core.linkHoverStates(); - setTimeout(function () { $("#tree").get(0).updateScrollbar(); }, 1); - }); - }, - init = function () { - - initBreadcrumb(); - initExtendedView(); - customize(); - conhtml.updatePaths(); - if (settings.showTree) { - populateTree(); - } - }; - - return { - init: init - }; -}); diff --git a/src/_h5ai/js/inc/finder.js b/src/_h5ai/js/inc/finder.js deleted file mode 100644 index 9122edd3..00000000 --- a/src/_h5ai/js/inc/finder.js +++ /dev/null @@ -1,106 +0,0 @@ - -Module.define('finder', [jQuery, 'settings', 'util', 'core'], function ($, settings, util, core) { - - var filter = function (re) { - - var match = [], - noMatch = []; - - if (re) { - $('#extended .entry').each(function () { - - var label = $(this).find('.label').text(); - - if (label.match(re)) { - match.push(this); - } else { - noMatch.push(this); - } - }); - } else { - match = $('#extended .entry'); - } - - if ($(match).length) { - $('#extended .no-match').hide(); - } else { - setTimeout(function () { - - $('#extended .no-match').show(); - }, 200); - } - $(match).fadeIn(200); - $(noMatch).fadeOut(200); - }, - checkState = function (focus) { - - var $filter = $('#filter'), - $input = $filter.find('input'), - val = $input.val(); - - if (val || focus) { - $filter.addClass('current'); - } else { - $filter.removeClass('current'); - } - core.hash({filter: val}); - }, - parseFilterSequence = function (sequence) { - - if (sequence.substr(0,3) === 're:') { - return new RegExp(sequence.substr(3)); - } - - sequence = $.map($.trim(sequence).split(/\s+/), function (part) { - - return util.reEscape(part); - }).join('|'); - return new RegExp(sequence); - }, - init = function () { - - if (settings.showFilter) { - $('
            • filter
            • ') - .on('click', function () { - - var $input = $(this).find('input'); - $input.focus(); - }) - .find('img').attr('src', core.image('filter')).end() - .find('input') - .on('focus', function () { - - checkState(true); - }) - .on('blur', function () { - - checkState(false); - }) - .on('keyup', function () { - - var $input = $(this), - val = $input.val(); - - if (val) { - filter(parseFilterSequence(val)); - } else { - filter(); - } - checkState($input.is(':focus')); - }) - .end() - .appendTo($('#navbar')); - - var initialFilter = core.hash('filter'); - if (initialFilter) { - $('#filter input').val(initialFilter); - checkState(false); - } - } - }; - - return { - init: init, - filter: filter - }; -}); diff --git a/src/_h5ai/js/inc/splash.js b/src/_h5ai/js/inc/h5ai-info.js similarity index 66% rename from src/_h5ai/js/inc/splash.js rename to src/_h5ai/js/inc/h5ai-info.js index ac56b976..c15052eb 100644 --- a/src/_h5ai/js/inc/splash.js +++ b/src/_h5ai/js/inc/h5ai-info.js @@ -1,5 +1,5 @@ -Module.define('splash', [jQuery, 'core'], function ($, core) { +module.define('h5ai-info', [jQuery, 'core/resource'], function ($, resource) { var setCheckResult = function (id, result) { @@ -11,16 +11,19 @@ Module.define('splash', [jQuery, 'core'], function ($, core) { $ele.addClass('test-failed').text('no'); } }, + handleChecksResponse = function (response) { - setCheckResult('#test-php', response && response.php); - setCheckResult('#test-zips', response && response.zips); - setCheckResult('#test-thumbs', response && response.thumbs); + _.each(['php', 'cache', 'thumbs', 'temp', 'zips'], function (test) { + + setCheckResult('#test-' + test, response && response[test]); + }) }, + checks = function () { $.ajax({ - url: core.api(), + url: resource.api(), data: { action: 'checks' }, @@ -36,12 +39,11 @@ Module.define('splash', [jQuery, 'core'], function ($, core) { } }); }, + init = function () { checks(); }; - return { - init: init - }; + init(); }); diff --git a/src/_h5ai/js/inc/h5ai-main.js b/src/_h5ai/js/inc/h5ai-main.js new file mode 100644 index 00000000..c1828a65 --- /dev/null +++ b/src/_h5ai/js/inc/h5ai-main.js @@ -0,0 +1,21 @@ + +module.define('h5ai-main', [jQuery, 'core/event'], function ($, event) { + + + event.pub('beforeView'); + + module.require('view/extended'); + module.require('view/viewmode'); + module.require('view/spacing'); + + $('#h5ai-reference').append(module.require('core/parser').id === 'apache-autoindex' ? ' (js)' : ' (php)'); + + event.pub('beforeExt'); + + _.each(module.getIds(/^ext\/.+/), function (id) { + + module.require(id); + }); + + event.pub('ready'); +}); diff --git a/src/_h5ai/js/inc/h5ai.js b/src/_h5ai/js/inc/h5ai.js deleted file mode 100644 index 526e5dba..00000000 --- a/src/_h5ai/js/inc/h5ai.js +++ /dev/null @@ -1,38 +0,0 @@ - -Module.define('h5ai', [jQuery, 'core', 'extended', 'localize', 'sort', 'finder', 'zip', 'context', 'splash'], function ($, core, extended, localize, sort, finder, zip, context, splash) { - - var h5ai = {}; - - h5ai.init = function () { - - var $html = $('html'); - - h5ai.isJs = $html.hasClass('h5ai-js'); - h5ai.isPhp = $html.hasClass('h5ai-php'); - h5ai.isSplash = $html.hasClass('h5ai-splash'); - - if (h5ai.isJs || h5ai.isPhp) { - if (h5ai.isJs) { - extended.init(); - } - - core.init(); - localize.init(); - sort.init(); - finder.init(); - zip.init(); - context.init(); - - if (h5ai.isPhp) { - $('#tree').scrollpanel(); - core.shiftTree(false, true); - } - } - - if (h5ai.isSplash) { - splash.init(); - } - }; - - return h5ai; -}); diff --git a/src/_h5ai/js/inc/html.js b/src/_h5ai/js/inc/html.js deleted file mode 100644 index e69de29b..00000000 diff --git a/src/_h5ai/js/inc/lib/jquery.mousewheel-3.0.6.js b/src/_h5ai/js/inc/lib/jquery.mousewheel-3.0.6.js new file mode 100644 index 00000000..38b60951 --- /dev/null +++ b/src/_h5ai/js/inc/lib/jquery.mousewheel-3.0.6.js @@ -0,0 +1,84 @@ +/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.0.6 + * + * Requires: 1.2.2+ + */ + +(function($) { + +var types = ['DOMMouseScroll', 'mousewheel']; + +if ($.event.fixHooks) { + for ( var i=types.length; i; ) { + $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; + } +} + +$.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) { + for ( var i=types.length; i; ) { + this.addEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = handler; + } + }, + + teardown: function() { + if ( this.removeEventListener ) { + for ( var i=types.length; i; ) { + this.removeEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = null; + } + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + + +function handler(event) { + var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; + event = $.event.fix(orgEvent); + event.type = "mousewheel"; + + // Old school scrollwheel delta + if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } + if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } + + // New school multidimensional scroll (touchpads) deltas + deltaY = delta; + + // Gecko + if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = -1*delta; + } + + // Webkit + if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } + if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } + + // Add event and delta to the front of the arguments + args.unshift(event, delta, deltaX, deltaY); + + return ($.event.dispatch || $.event.handle).apply(this, args); +} + +})(jQuery); diff --git a/src/_h5ai/js/inc/lib/jquery.mousewheel.js b/src/_h5ai/js/inc/lib/jquery.mousewheel.js deleted file mode 100644 index 2d699030..00000000 --- a/src/_h5ai/js/inc/lib/jquery.mousewheel.js +++ /dev/null @@ -1,84 +0,0 @@ -/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) - * Licensed under the MIT License (LICENSE.txt). - * - * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. - * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. - * Thanks to: Seamus Leahy for adding deltaX and deltaY - * - * Version: 3.0.5 - * - * Requires: 1.2.2+ - */ - -(function($) { - -var types = ['DOMMouseScroll', 'mousewheel']; - -if ($.event.fixHooks) { - for ( var i=types.length; i; ) { - $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; - } -} - -$.event.special.mousewheel = { - setup: function() { - if ( this.addEventListener ) { - for ( var i=types.length; i; ) { - this.addEventListener( types[--i], handler, false ); - } - } else { - this.onmousewheel = handler; - } - }, - - teardown: function() { - if ( this.removeEventListener ) { - for ( var i=types.length; i; ) { - this.removeEventListener( types[--i], handler, false ); - } - } else { - this.onmousewheel = null; - } - } -}; - -$.fn.extend({ - mousewheel: function(fn) { - return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); - }, - - unmousewheel: function(fn) { - return this.unbind("mousewheel", fn); - } -}); - - -function handler(event) { - var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; - event = $.event.fix(orgEvent); - event.type = "mousewheel"; - - // Old school scrollwheel delta - if ( event.wheelDelta ) { delta = event.wheelDelta/120; } - if ( event.detail ) { delta = -event.detail/3; } - - // New school multidimensional scroll (touchpads) deltas - deltaY = delta; - - // Gecko - if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { - deltaY = 0; - deltaX = -1*delta; - } - - // Webkit - if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } - if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } - - // Add event and delta to the front of the arguments - args.unshift(event, delta, deltaX, deltaY); - - return ($.event.dispatch || $.event.handle).apply(this, args); -} - -})(jQuery); diff --git a/src/_h5ai/js/inc/lib/module.js b/src/_h5ai/js/inc/lib/module.js new file mode 100644 index 00000000..c8c59b9d --- /dev/null +++ b/src/_h5ai/js/inc/lib/module.js @@ -0,0 +1,196 @@ +/*! + * module.js + * author: Lars Jung + * license: MIT + */ + +(function (global, name) { + 'use strict'; + + var self = {}, + previous = global[name], + + noConflict = function () { + + if (global[name] === self) { + global[name] = previous; + } + return self; + }, + + err = function (message) { + + throw name + ' exception: ' + message; + }, + + definitions = {}, + modules = {}, + + findDepsUnsafe = function (ids) { + + var self = this; + var deps = []; + + if (_.isString(ids)) { + + var def = definitions[ids]; + if (def) { + _.each(def.deps, function (id) { + + deps = deps.concat(findDepsUnsafe(id)); + }); + deps.push(def.id); + } else { + deps.push(ids); + } + } else if (_.isArray(ids)) { + + _.each(ids, function (id) { + + deps = deps.concat(findDepsUnsafe(id)); + }); + } + + return _.uniq(deps); + }, + + findDeps = function (ids) { + + if (ids) { + try { + return findDepsUnsafe(ids); + } catch (e) { + err('cyclic dependencies for ids "' + ids + '"'); + } + } else { + var res = {}; + _.each(definitions, function (def, id) { + + res[id] = findDeps(id); + }); + return res; + } + }, + + log = function (showInvDeps) { + + var allDeps = findDeps(), + allInvDeps = {}, + out = ''; + + if (!showInvDeps) { + _.each(allDeps, function (deps, id) { + + deps.pop(); + out += (_.has(modules, id) ? '* ' : ' ') + id + ' -> [ ' + deps.join(', ') + ' ]\n'; + }); + } else { + _.each(definitions, function (def) { + + var invDeps = []; + _.each(allDeps, function (depId, id) { + + if (_.inArray(def.id, depId) >= 0) { + invDeps.push(id); + } + }); + allInvDeps[def.id] = invDeps; + }); + + _.each(allInvDeps, function (invDeps, id) { + + invDeps.shift(); + out += (_.has(modules, id) ? '* ' : ' ') + id + ' <- [ ' + invDeps.join(', ') + ' ]\n'; + }); + } + + return out; + }, + + define = function (id, deps, fn) { + + if (_.isFunction(deps)) { + fn = deps; + deps = []; + } + if (!_.isString(id)) { + err('id must be a string "' + id + '"'); + } + if (!_.isArray(deps)) { + err('dependencies must be an array "' + deps + '"'); + } + if (!_.isFunction(fn)) { + err('constructor must be a function "' + fn + '"'); + } + if (definitions[id]) { + err('id already defined "' + id + '"'); + } + + definitions[id] = { + id: id, + deps: deps, + fn: fn + }; + }, + + getIds = function (regexp) { + + var ids = _.map(definitions, function (def) { + + return def.id; + }); + + if (!_.isRegExp(regexp)) { + return ids; + } + + return _.filter(ids, function (id) { + + return regexp.test(id); + }); + }, + + isDefined = function (id) { + + return _.isString(id) ? !!definitions[id] : !!id; + }, + + require = function (id) { + + if (!_.isString(id)) { + return id; + } + + if (_.has(modules, id)) { + return modules[id]; + } + + var def = definitions[id]; + if (!def) { + err('id not defined "' + id + '"'); + } + + var deps = _.map(def.deps, function (depId) { + + return require(depId); + }); + + var obj = def.fn.apply(this, deps); + modules[id] = obj; + return obj; + }; + + if (!_) { + err(name + ' depends on underscore'); + } + + self.noConflict = noConflict; + self.log = log; + self.define = define; + self.require = require; + self.getIds = getIds; + self.isDefined = isDefined; + + global[name] = self; + +}(this, 'module')); diff --git a/src/_h5ai/js/inc/main.js b/src/_h5ai/js/inc/main.js index ee2186ac..bd69baf2 100644 --- a/src/_h5ai/js/inc/main.js +++ b/src/_h5ai/js/inc/main.js @@ -1,36 +1,48 @@ -(function () { -'use strict'; -/*jslint browser: true, confusion: true, regexp: true, vars: true, white: true */ -/*global Modernizr, jQuery, amplify, Base64, H5AI_CONFIG */ +(function ($) { + 'use strict'; + /*jshint browser: true */ + /*global _, amplify, Base64, H5AI_CONFIG, jQuery, Modernizr, module, moment */ - // @include "module.js" + // @include "core/entry.js" + // @include "core/event.js" + // @include "core/format.js" + // @include "core/parser.js" + // @include "core/resource.js" + // @include "core/settings.js" + // @include "core/store.js" - // @include "settings.js" + // @include "model/entry.js" - // @include "util.js" - // @include "core.js" - // @include "localize.js" - // @include "sort.js" - // @include "zip.js" - // @include "finder.js" - // @include "context.js" + // @include "parser/apache-autoindex.js" + // @include "parser/generic-json.js" - // @include "path.js" - // @include "connector.js" - // @include "html.js" - // @include "extended.js" + // @include "view/extended.js" + // @include "view/spacing.js" + // @include "view/viewmode.js" - // @include "splash.js" + // @include "ext/crumb.js" + // @include "ext/custom.js" + // @include "ext/filter.js" + // @include "ext/folderstatus.js" + // @include "ext/l10n.js" + // @include "ext/link-hover-states.js" + // @include "ext/qrcode.js" + // @include "ext/select.js" + // @include "ext/sort.js" + // @include "ext/statusbar.js" + // @include "ext/thumbnails.js" + // @include "ext/title.js" + // @include "ext/tree.js" + // @include "ext/zipped-download.js" - // @include "h5ai.js" + // @include "h5ai-info.js" + // @include "h5ai-main.js" - jQuery(function () { + $(function () { - var h5ai = Module.require('h5ai'); - - h5ai.init(); + module.require($('body').attr('id')); }); -}()); +}(jQuery)); diff --git a/src/_h5ai/js/inc/model/entry.js b/src/_h5ai/js/inc/model/entry.js new file mode 100644 index 00000000..ee31e5ff --- /dev/null +++ b/src/_h5ai/js/inc/model/entry.js @@ -0,0 +1,282 @@ + +module.define('model/entry', [jQuery, 'core/types'], function ($, types) { + + var domain = document.domain, + location = document.location.pathname, + + + // utils + + reEndsWithSlash = /\/$/, + + pathEndsWithSlash = function (sequence) { + + return reEndsWithSlash.test(sequence); + }, + + createLabel = function (sequence) { + + if (sequence.length > 1 && reEndsWithSlash.test(sequence)) { + sequence = sequence.slice(0, -1); + } + try { + sequence = decodeURI(sequence); + } catch (err) {} + return sequence; + }, + + + reSplitPath = /^\/([^\/]+\/?)$/, + reSplitPath2 = /^(\/(?:.*\/)*?([^\/]+)\/)([^\/]+\/?)$/, + + splitPath = function (sequence) { + + var match; + + sequence = sequence.replace(/\/+/g, '/'); + if (sequence === '/') { + return { + parent: null, + parentname: null, + name: '/' + }; + } + match = reSplitPath2.exec(sequence); + if (match) { + return { + parent: match[1], + parentname: match[2], + name: match[3] + }; + } + match = reSplitPath.exec(sequence); + if (match) { + return { + parent: '/', + parentname: '/', + name: match[1] + }; + } + }, + + + extToFileType = (function (types) { + var map = {}; + $.each(types, function (type, exts) { + $.each(exts, function (idx, ext) { + map[ext] = type; + }); + }); + return map; + }(types)), + + getFileType = function (sequence) { + + if (pathEndsWithSlash(sequence)) { + return 'folder'; + } + + var dotidx = sequence.lastIndexOf('.'), + ext = dotidx >= 0 ? sequence.substr(dotidx) : sequence; + + return extToFileType[ext.toLowerCase()] || 'unknown'; + }, + + + reContentType = /^text\/html;h5ai=/, + + ajaxRequest = function (self, parser, callback) { + + $.ajax({ + url: self.absHref, + type: parser ? 'GET' : 'HEAD', + complete: function (xhr) { + + if (xhr.status === 200 && reContentType.test(xhr.getResponseHeader('Content-Type'))) { + self.status = 'h5ai'; + if (parser) { + parser.parse(self.absHref, xhr.responseText); + } + } else { + self.status = xhr.status; + } + + callback(self); + } + }); + }, + + + + + // Entry + + cache = {}, + + Entry = function (absHref) { + + var split = splitPath(absHref); + + cache[absHref] = this; + + this.absHref = absHref; + this.type = getFileType(absHref); + this.label = createLabel(absHref === '/' ? domain : split.name); + this.time = null; + this.size = null; + this.parent = null; + this.status = null; + this.content = {}; + + if (split.parent) { + this.parent = cache[split.parent] || new Entry(split.parent); + this.parent.content[this.absHref] = this; + } + }, + + get = function (absHref, time, size, status) { + + absHref = absHref || location; + + var self = cache[absHref] || new Entry(absHref); + + if (_.isNumber(time)) { + self.time = time; + } + if (_.isNumber(size)) { + self.size = size; + } + if (status) { + self.status = status; + } + + return self; + }, + + folderstatus = module.isDefined('ext/folderstatus') ? module.require('ext/folderstatus') : {}, + + fetchStatus = function (absHref, callback) { + + var self = cache[absHref] || new Entry(absHref); + + if (self.status || !self.isFolder()) { + callback(self); + } else if (folderstatus[absHref]) { + self.status = folderstatus[absHref]; + callback(self); + } else { + ajaxRequest(self, null, callback); + } + }, + + fetchContent = function (absHref, parser, callback) { + + var self = cache[absHref] || new Entry(absHref); + + if (self.isContentFetched || _.keys(self.content).length > 1) { + self.isContentFetched = true; + callback(self); + } else { + fetchStatus(absHref, function (self) { + + self.isContentFetched = true; + if (self.status === 'h5ai') { + ajaxRequest(self, parser, callback); + } else { + callback(self); + } + }); + } + }; + + + _.extend(Entry.prototype, { + + isFolder: function () { + + return pathEndsWithSlash(this.absHref); + }, + + isCurrentFolder: function () { + + return this.absHref === location; + }, + + isDomain: function () { + + return this.absHref === '/'; + }, + + isEmpty: function () { + + return _.keys(this.content).length === 0; + }, + + fetchStatus: function (callback) { + + return fetchStatus(this.absHref, callback); + }, + + fetchContent: function (parser, callback) { + + return fetchContent(this.absHref, parser, callback); + }, + + getCrumb: function () { + + var entry = this, + crumb = [entry]; + + while (entry.parent) { + entry = entry.parent; + crumb.unshift(entry); + } + + return crumb; + }, + + getSubfolders: function () { + + return _.sortBy(_.filter(this.content, function (entry) { + + return entry.isFolder(); + }), function (entry) { + + return entry.absHref; + }); + }, + + getStats: function () { + + var folders = 0, + files = 0; + + _.each(this.content, function (entry) { + + if (entry.isFolder()) { + folders += 1; + } else { + files += 1; + } + }); + + var depth = 0, + entry = this; + + while (entry.parent) { + depth += 1; + entry = entry.parent; + } + + return { + folders: folders, + files: files, + depth: depth + }; + } + }); + + return { + get: get + }; +}); diff --git a/src/_h5ai/js/inc/module.js b/src/_h5ai/js/inc/module.js deleted file mode 100644 index 138acef0..00000000 --- a/src/_h5ai/js/inc/module.js +++ /dev/null @@ -1,174 +0,0 @@ - -var Module = window.Module = (function ($) { - - var definitions = {}, - modules = {}, - - err = function (message) { - - $.error('module: ' + message); - }, - - uniq = function (array) { - - var set = {}, - uniq = []; - - $.each(array, function (idx, element) { - - if (!set[element]) { - set[element] = true; - uniq.push(element); - } - }); - return uniq; - }, - - depsIntern = function (ids) { - - var self = this; - var deps = []; - - if (typeof ids === 'string') { - - var def = definitions[ids]; - if (def) { - $.each(def.deps, function (idx, id) { - - deps = deps.concat(depsIntern(id)); - }); - deps.push(def.id); - } else { - deps.push(ids); - } - } else if ($.isArray(ids)) { - - $.each(ids, function (idx, id) { - - deps = deps.concat(depsIntern(id)); - }); - } - - return uniq(deps); - }, - - deps = function (ids) { - - if (ids) { - try { - return depsIntern(ids); - } catch (e) { - err('cyclic dependencies for ids "' + ids + '"'); - } - } else { - var res = {}; - $.each(definitions, function (id, def) { - - res[id] = deps(id); - }); - return res; - } - }, - - log = function () { - - var allDeps = deps(), - allInvDeps = {}; - - $.each(definitions, function (id, def) { - - var invDeps = []; - $.each(allDeps, function (i, depId) { - - if ($.inArray(id, depId) >= 0) { - invDeps.push(i); - } - }); - allInvDeps[id] = invDeps; - }); - - $.each(allDeps, function (id, deps) { - - deps.pop(); - console.log(id + ' -> [ ' + deps.join(', ') + ' ]'); - }); - - console.log('\n'); - $.each(allInvDeps, function (id, invDeps) { - - invDeps.shift(); - console.log(id + ' <- [ ' + invDeps.join(', ') + ' ]'); - }); - }, - - defs = function () { - - return $.extend({}, definitions); - }, - - mods = function () { - - return $.extend({}, modules); - }, - - define = function (id, deps, fn) { - - if ($.isFunction(deps)) { - fn = deps; - deps = []; - } - if (typeof id !== 'string') { - err('id must be a string "' + id + '"'); - } - if (!$.isArray(deps)) { - err('dependencies must be an array "' + deps + '"'); - } - if (!$.isFunction(fn)) { - err('constructor must be a function "' + fn + '"'); - } - if (definitions[id]) { - err('id already defined "' + id + '"'); - } - - definitions[id] = { - id: id, - deps: deps, - fn: fn - }; - }, - - require = function (id) { - - if (typeof id !== 'string') { - return id; - } - - if (modules[id]) { - return modules[id]; - } - - var def = definitions[id]; - if (!def) { - err('id not defined "' + id + '"'); - } - - var deps = $.map(def.deps, function (depId) { - - return require(depId); - }); - - var obj = def.fn.apply(this, deps); - modules[id] = obj; - return obj; - }; - - return { - deps: deps, - log: log, - defs: defs, - mods: mods, - define: define, - require: require - }; - -}(jQuery)); diff --git a/src/_h5ai/js/inc/parser/apache-autoindex.js b/src/_h5ai/js/inc/parser/apache-autoindex.js new file mode 100644 index 00000000..77237ac8 --- /dev/null +++ b/src/_h5ai/js/inc/parser/apache-autoindex.js @@ -0,0 +1,42 @@ + +module.define('parser/apache-autoindex', [jQuery, 'core/format', 'model/entry'], function ($, format, Entry) { + + var parseTableRow = function (absHref, tr) { + + var $tds = $(tr).find('td'), + $a = $tds.eq(1).find('a'), + label = $a.text(), + time = format.parseDate($tds.eq(2).text(), 'DD-MMM-YYYY HH:mm'), + size = format.parseSize($tds.eq(3).text()); + + absHref = absHref + $a.attr('href'); + + return label === 'Parent Directory' ? null : Entry.get(absHref, time, size); + }, + + parseTable = function (absHref, table) { + + return _.compact(_.map($(table).find('td').closest('tr'), function (tr) { + + return parseTableRow(absHref, tr); + })); + }, + + parse = function (absHref, html) { + + var id = '#data-apache-autoindex', + $html = $(html), + $id = $html.filter(id); + + if (!$id.length) { + $id = $html.find(id); + } + + return parseTable(absHref, $id.find('table')); + }; + + return { + id: 'apache-autoindex', + parse: parse + }; +}); diff --git a/src/_h5ai/js/inc/parser/generic-json.js b/src/_h5ai/js/inc/parser/generic-json.js new file mode 100644 index 00000000..cdacb072 --- /dev/null +++ b/src/_h5ai/js/inc/parser/generic-json.js @@ -0,0 +1,48 @@ + +module.define('parser/generic-json', [jQuery, 'core/settings', 'model/entry'], function ($, settings, Entry) { + + // expectes an hash of the form + // { + // entries: [ + // {absHref: String, time: Number, size: Number, status: Number or "h5ai"} + // ] + // } + + var parseJson = function (absHref, json) { + + _.each(json.entries, function (jsonEntry) { + + Entry.get(jsonEntry.absHref, jsonEntry.time, jsonEntry.size, jsonEntry.status); + }); + + if (json.hasOwnProperty('customHeader')) { + settings.custom.header = json.customHeader; + } + if (json.hasOwnProperty('customFooter')) { + settings.custom.footer = json.customFooter; + } + }, + + parseJsonStr = function (absHref, jsonStr) { + + return parseJson(absHref, JSON.parse($.trim(jsonStr) || '{}')); + }, + + parse = function (absHref, html) { + + var id = '#data-generic-json', + $html = $(html), + $id = $html.filter(id); + + if (!$id.length) { + $id = $html.find(id); + } + + return parseJsonStr(absHref, $id.text()); + }; + + return { + id: 'generic-json', + parse: parse + }; +}); diff --git a/src/_h5ai/js/inc/path.js b/src/_h5ai/js/inc/path.js deleted file mode 100644 index 0e401432..00000000 --- a/src/_h5ai/js/inc/path.js +++ /dev/null @@ -1,98 +0,0 @@ - -Module.define('path', [jQuery, 'settings', 'util', 'core'], function ($, settings, util, core) { - - var create = function (folder, tableRow) { - - var path = {}, - $tds, $a, time, size, splits; - - // path.parentFolder: undefined - // path.label: undefined - // path.type: undefined - // path.href: undefined - // path.time: undefined - // path.size: undefined - // path.absHref: undefined - // path.isFolder: undefined - // path.isParentFolder: undefined - // path.isCurrentFolder: undefined - // path.isDomain: undefined - - path.status = undefined; // undefined, 'h5ai' or HTTP response code - path.content = undefined; // associative array path.absHref -> path - path.html = { - $crumb: undefined, - $extended: undefined, - $tree: undefined - }; - path.treeOpen = false; - - if (!util.pathEndsWithSlash(folder)) { - folder += '/'; - } - - if (tableRow) { - $tds = $(tableRow).find('td'); - $a = $tds.eq(1).find('a'); - time = Date.parse($tds.eq(2).text()) || 0; - size = util.parseSize($tds.eq(3).text()); - - path.parentFolder = folder; - path.label = $a.text(); - path.type = util.pathEndsWithSlash(path.label) ? 'folder' : core.getFileType(path.label); - path.href = $a.attr('href'); - path.time = time; - path.size = size; - } else { - splits = util.splitPath(folder); - - path.parentFolder = splits.parent || ''; - path.label = util.checkedDecodeUri(splits.name); - if (path.label === '/') { - path.label = util.checkedDecodeUri(document.domain); - } - path.type = 'folder'; - path.href = splits.name; - path.time = 0; - path.size = -1; - } - - if (util.pathEndsWithSlash(path.label)) { - path.label = path.label.slice(0, -1); - } - - path.isFolder = (path.type === 'folder'); - path.isParentFolder = (path.label === 'Parent Directory'); - if (path.isParentFolder) { - path.isFolder = true; - path.type = 'folder-parent'; - } - path.absHref = path.isParentFolder ? path.href : path.parentFolder + path.href; - path.isCurrentFolder = (path.absHref === document.location.pathname); - path.isDomain = (path.absHref === '/'); - - if (path.isParentFolder && settings.setParentFolderLabels) { - if (path.isDomain) { - path.label = util.checkedDecodeUri(document.domain); - } else { - splits = util.splitPath(path.parentFolder); - path.label = util.checkedDecodeUri(splits.parentname); - } - } - - path.isEmpty = function () { - - return !path.content || $.isEmptyObject(path.content); - }; - path.onClick = function (context) { - - core.triggerPathClick(path, context); - }; - - return path; - }; - - return { - create: create - }; -}); diff --git a/src/_h5ai/js/inc/settings.js b/src/_h5ai/js/inc/settings.js deleted file mode 100644 index 089ffbe9..00000000 --- a/src/_h5ai/js/inc/settings.js +++ /dev/null @@ -1,57 +0,0 @@ - -Module.define('config', [jQuery, H5AI_CONFIG], function ($, config) { - - var defaults = { - store: { - viewmode: 'h5ai.pref.viewmode', - lang: 'h5ai.pref.lang' - }, - callbacks: { - pathClick: [] - }, - - rootAbsHref: '/', - h5aiAbsHref: '/_h5ai/', - customHeader: null, - customFooter: null, - viewmodes: ['details', 'icons'], - sortorder: 'na', - showTree: true, - slideTree: true, - folderStatus: {}, - lang: 'en', - useBrowserLang: true, - setParentFolderLabels: true, - linkHoverStates: true, - dateFormat: 'yyyy-MM-dd HH:mm', - showThumbs: false, - thumbTypes: ['bmp', 'gif', 'ico', 'image', 'jpg', 'png', 'tiff'], - zippedDownload: false, - qrCodesSize: null, - showFilter: false - }; - - return { - settings: $.extend({}, defaults, config.options), - types: $.extend({}, config.types), - langs: $.extend({}, config.langs) - }; -}); - - -Module.define('settings', ['config'], function (config) { - - return config.settings; -}); - - -Module.define('types', ['config'], function (config) { - - return config.types; -}); - - -Module.define('langs', ['config'], function (config) { - - return config.langs; -}); diff --git a/src/_h5ai/js/inc/util.js b/src/_h5ai/js/inc/util.js deleted file mode 100644 index e9e3b454..00000000 --- a/src/_h5ai/js/inc/util.js +++ /dev/null @@ -1,117 +0,0 @@ - -Module.define('util', [jQuery], function ($) { - - var reSplitPath = /^\/([^\/]+\/?)$/, - reSplitPath2 = /^(\/(?:.*\/)*?([^\/]+)\/)([^\/]+\/?)$/, - rePathEndsWithSlash = /\/$/, - reParseSize = /^\s*([\.\d]+)\s*([kmg]?)b?\s*$/i, - kilo = 1000.0, - sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB'], - - splitPath = function (pathname) { - - var match; - - if (pathname === '/') { - return { - parent: null, - parentname: null, - name: '/' - }; - } - match = reSplitPath2.exec(pathname); - if (match) { - return { - parent: match[1], - parentname: match[2], - name: match[3] - }; - } - match = reSplitPath.exec(pathname); - if (match) { - return { - parent: '/', - parentname: '/', - name: match[1] - }; - } - }, - pathEndsWithSlash = function (pathname) { - - return rePathEndsWithSlash.test(pathname); - }, - getAbsHref = function (folder, tableRow) { - - var $a, isParentFolder, href; - - if (!pathEndsWithSlash(folder)) { - folder += '/'; - } - if (!tableRow) { - return folder; - } - $a = $(tableRow).find('td').eq(1).find('a'); - isParentFolder = ($a.text() === 'Parent Directory'); - href = $a.attr('href'); - return isParentFolder ? undefined : folder + href; - }, - parseSize = function (str) { - - var match = reParseSize.exec(str), - val, unit; - - if (!match) { - return -1; - } - - val = parseFloat(match[1]); - unit = match[2].toLowerCase(); - if (unit === 'k') { - val *= kilo; - } else if (unit === 'm') { - val *= kilo * kilo; - } else if (unit === 'g') { - val *= kilo * kilo * kilo; - } else if (unit === 't') { - val *= kilo * kilo * kilo * kilo; - } - return val; - }, - formatSize = function (size) { - - var th = 1000.0, - i = 0, - maxI = sizeUnits.length - 1; - - if (isNaN(size)) { - return size; - } - - while (size >= th && i < maxI) { - size /= kilo; - i += 1; - } - return (i <= 1 ? Math.round(size) : size.toFixed(1)).toString() + ' ' + sizeUnits[i]; - }, - checkedDecodeUri = function (uri) { - - try { - return decodeURI(uri); - } catch (err) {} - return uri; - }, - reEscape = function (sequence) { - - return sequence.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); - }; - - return { - splitPath: splitPath, - pathEndsWithSlash: pathEndsWithSlash, - getAbsHref: getAbsHref, - parseSize: parseSize, - formatSize: formatSize, - checkedDecodeUri: checkedDecodeUri, - reEscape: reEscape - }; -}); diff --git a/src/_h5ai/js/inc/view/extended.js b/src/_h5ai/js/inc/view/extended.js new file mode 100644 index 00000000..7b2432c8 --- /dev/null +++ b/src/_h5ai/js/inc/view/extended.js @@ -0,0 +1,135 @@ + +module.define('view/extended', [jQuery, 'core/settings', 'core/resource', 'core/format', 'core/event', 'core/entry'], function ($, allsettings, resource, format, event, entry) { + + var defaults = { + modes: ['details', 'icons'], + setParentFolderLabels: false + }, + + settings = _.extend({}, defaults, allsettings.view), + + template = '
            • ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
            • ', + hintTemplate = '', + listTemplate = '
                ' + + '
              • ' + + '' + + '' + + '' + + '' + + '
              • ' + + '
              ', + emptyTemplate = '
              empty
              ', + + + + // updates this single entry + update = function (entry) { + + if (entry.$extended && entry.status && entry.$extended.data('status') === entry.status) { + return entry.$extended; + } + + var $html = $(template), + $a = $html.find('a'), + $imgSmall = $html.find('.icon.small img'), + $imgBig = $html.find('.icon.big img'), + $label = $html.find('.label'), + $date = $html.find('.date'), + $size = $html.find('.size'), + icon16 = resource.icon(entry.type), + icon48 = resource.icon(entry.type, true), + escapedHref = entry.absHref.replace(/'/g, "%27").replace(/"/g, "%22"); + + $html + .addClass(entry.isFolder() ? 'folder' : 'file') + .data('entry', entry) + .data('status', entry.status); + + if (entry.isParentFolder) { + icon16 = resource.icon('folder-parent'); + icon48 = resource.icon('folder-parent', true); + if (!settings.setParentFolderLabels) { + $label.addClass('l10n-parentDirectory'); + } + $html.addClass('folder-parent'); + } + + $a.attr('href', entry.absHref); + $imgSmall.attr('src', icon16).attr('alt', entry.type); + $imgBig.attr('src', icon48).attr('alt', entry.type); + $label.text(entry.label); + $date.data('time', entry.time).text(format.formatDate(entry.time)); + $size.data('bytes', entry.size).text(format.formatSize(entry.size)); + + if (entry.isFolder() && _.isNumber(entry.status)) { + if (entry.status === 200) { + $html.addClass('page'); + $imgSmall.attr('src', resource.icon('folder-page')); + $imgBig.attr('src', resource.icon('folder-page', true)); + } else { + $html.addClass('error'); + $label.append($(hintTemplate).text(' ' + entry.status + ' ')); + } + } + + if (entry.$extended) { + entry.$extended.replaceWith($html); + } + entry.$extended = $html; + + return $html; + }, + + onMouseenter = function () { + + var entry = $(this).closest('.entry').data('entry'); + event.pub('entry.mouseenter', entry); + }, + + onMouseleave = function () { + + var entry = $(this).closest('.entry').data('entry'); + event.pub('entry.mouseleave', entry); + }, + + // creates the view for entry content + init = function (entry) { + + var $extended = $('#extended'), + $ul = $(listTemplate); + + if (entry.parent) { + $ul.append(update(entry.parent)); + } + + _.each(entry.content, function (e) { + + $ul.append(update(e)); + + e.fetchStatus(function (e) { + + update(e); + }); + }); + + $extended.append($ul); + + if (entry.isEmpty()) { + $extended.append($(emptyTemplate)); + } + + $extended + .on('mouseenter', '.entry a', onMouseenter) + .on('mouseleave', '.entry a', onMouseleave); + }; + + init(entry); +}); diff --git a/src/_h5ai/js/inc/view/spacing.js b/src/_h5ai/js/inc/view/spacing.js new file mode 100644 index 00000000..77e37784 --- /dev/null +++ b/src/_h5ai/js/inc/view/spacing.js @@ -0,0 +1,35 @@ + +module.define('view/spacing', [jQuery, 'core/settings', 'core/event'], function ($, allsettings, event) { + + var defaults = { + maxWidth: 960, + top: 50, + right: "auto", + bottom: 50, + left: "auto" + }, + + settings = _.extend({}, defaults, allsettings.spacing), + + adjustSpacing = function () { + + $('#content').css({ + 'margin-top': settings.top + $('#topbar').outerHeight(), + 'margin-bottom': settings.bottom + $('#bottombar').outerHeight() + }); + }, + + init = function () { + + $('#content').css({ + 'max-width': settings.maxWidth, + 'margin-right': settings.right, + 'margin-left': settings.left + }); + + event.sub('ready', adjustSpacing); + $(window).on('resize', adjustSpacing); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/view/viewmode.js b/src/_h5ai/js/inc/view/viewmode.js new file mode 100644 index 00000000..2e199d0a --- /dev/null +++ b/src/_h5ai/js/inc/view/viewmode.js @@ -0,0 +1,77 @@ + +module.define('view/viewmode', [jQuery, 'core/settings', 'core/resource', 'core/store'], function ($, allsettings, resource, store) { + + var defaults = { + modes: ['details', 'icons'], + setParentFolderLabels: false + }, + + settings = _.extend({}, defaults, allsettings.view), + + storekey = 'h5ai.viewmode', + + templates = { + details: '
            • ' + + '' + + 'view-details' + + 'details' + + '' + + '
            • ', + icons: '
            • ' + + '' + + 'view-icons' + + 'icons' + + '' + + '
            • ' + }, + + update = function (viewmode) { + + var $viewDetails = $('#viewdetails'), + $viewIcons = $('#viewicons'), + $extended = $('#extended'); + + if (viewmode) { + store.put(storekey, viewmode); + } else { + viewmode = store.get(storekey); + } + viewmode = $.inArray(viewmode, settings.modes) >= 0 ? viewmode : settings.modes[0]; + + $viewDetails.add($viewIcons).removeClass('current'); + if (viewmode === 'details') { + $viewDetails.addClass('current'); + $extended.addClass('details-view').removeClass('icons-view').show(); + } else if (viewmode === 'icons') { + $viewIcons.addClass('current'); + $extended.removeClass('details-view').addClass('icons-view').show(); + } else { + $extended.hide(); + } + }, + + init = function () { + + var $navbar = $('#navbar'), + $extended = $('#extended'); + + settings.modes = _.intersection(settings.modes, defaults.modes); + + if (settings.modes.length > 1) { + _.each(['icons', 'details'], function (view) { + if ($.inArray(view, settings.modes) >= 0) { + $(templates[view]) + .appendTo($navbar) + .on('click', 'a', function (event) { + update(view); + event.preventDefault(); + }); + } + }); + } + + update(); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/zip.js b/src/_h5ai/js/inc/zip.js deleted file mode 100644 index cd9e76ae..00000000 --- a/src/_h5ai/js/inc/zip.js +++ /dev/null @@ -1,187 +0,0 @@ - -Module.define('zip', [jQuery, 'settings', 'core'], function ($, settings, core) { - - var x = 0, - y = 0, - $document = $(document), - $selectionRect = $('#selection-rect'), - selectedHrefsStr = '', - $download, $img, $downloadAuth, $downloadUser, $downloadPassword, - - updateDownloadBtn = function () { - - var $selected = $('#extended a.selected'), - $downloadBtn = $('#download'); - - selectedHrefsStr = ''; - if ($selected.length) { - $selected.each(function () { - - var href = $(this).attr('href'); - selectedHrefsStr = selectedHrefsStr ? selectedHrefsStr + ':' + href : href; - }); - $downloadBtn.show(); - } else { - $downloadBtn.hide(); - $downloadAuth.hide(); - } - }, - selectionUpdate = function (event) { - - var l = Math.min(x, event.pageX), - t = Math.min(y, event.pageY), - w = Math.abs(x - event.pageX), - h = Math.abs(y - event.pageY), - selRect; - - event.preventDefault(); - $selectionRect.css({left: l, top: t, width: w, height: h}); - - selRect = $selectionRect.fracs('rect'); - $('#extended a').removeClass('selecting').each(function () { - - var $a = $(this), - rect = $a.fracs('rect'), - inter = selRect.intersection(rect); - if (inter && !$a.closest('.entry').hasClass('folder-parent')) { - $a.addClass('selecting'); - } - }); - }, - selectionEnd = function (event) { - - event.preventDefault(); - $document.off('mousemove', selectionUpdate); - $selectionRect.hide().css({left: 0, top: 0, width: 0, height: 0}); - $('#extended a.selecting.selected').removeClass('selecting').removeClass('selected'); - $('#extended a.selecting').removeClass('selecting').addClass('selected'); - updateDownloadBtn(); - }, - selectionStart = function (event) { - - var view = $(document).fracs('viewport'); - - x = event.pageX; - y = event.pageY; - // only on left button and don't block the scrollbars - if (event.button !== 0 || x >= view.right || y >= view.bottom) { - return; - } - - event.preventDefault(); - $(':focus').blur(); - if (!event.ctrlKey) { - $("#extended a").removeClass("selected"); - updateDownloadBtn(); - } - $selectionRect.show().css({left: x, top: y, width: 0, height: 0}); - - $document - .on("mousemove", selectionUpdate) - .one("mouseup", selectionEnd); - }, - noSelection = function (event) { - - event.stopImmediatePropagation(); - return false; - }, - noSelectionUnlessCtrl = function (event) { - - if (!event.ctrlKey) { - noSelection(event); - } - }, - failed = function () { - - $download.addClass('failed'); - setTimeout(function () { - $download.removeClass('failed'); - }, 1000); - }, - handleResponse = function (response) { - - - $download.removeClass('current'); - $img.attr('src', core.image("download")); - - if (response) { - if (response.status === 'ok') { - window.location = core.api() + '?action=getzip&id=' + response.id; - } else { - if (response.code === 401) { - $downloadAuth - .css({ - left: $download.offset().left, - top: $download.offset().top + $download.outerHeight() - }) - .show(); - $downloadUser.focus(); - } - failed(); - } - } else { - failed(); - } - }, - requestZipping = function (hrefsStr) { - - $download.addClass('current'); - $img.attr('src', core.image("loading.gif", true)); - $.ajax({ - url: core.api(), - data: { - action: 'zip', - hrefs: selectedHrefsStr - }, - type: 'POST', - dataType: 'json', - beforeSend: function (xhr) { - - var user = $downloadUser.val(), - password = $downloadPassword.val(); - - if (user) { - xhr.setRequestHeader ('Authorization', 'Basic ' + Base64.encode(user + ':' + password)); - } - }, - success: function (response) { - - handleResponse(response); - }, - error: function () { - - handleResponse(); - } - }); - }, - init = function () { - - if (settings.zippedDownload) { - $('
            • downloaddownload
            • ') - .find('img').attr('src', core.image('download')).end() - .find('a').click(function (event) { - - event.preventDefault(); - $downloadAuth.hide(); - requestZipping(selectedHrefsStr); - }).end() - .appendTo($('#navbar')); - $('
              ') - .appendTo($('body')); - - $download = $('#download'); - $downloadAuth = $('#download-auth'); - $downloadUser = $('#download-auth-user'); - $downloadPassword = $('#download-auth-password'); - $img = $download.find('img'); - - $('body>nav,body>footer,#tree,input').on('mousedown', noSelection); - $('#content').on('mousedown', 'a', noSelectionUnlessCtrl); - $document.on('mousedown', selectionStart); - } - }; - - return { - init: init - }; -}); diff --git a/src/_h5ai/js/modernizr-2.5.3.min.js b/src/_h5ai/js/modernizr-2.5.3.min.js new file mode 100644 index 00000000..a985ad0b --- /dev/null +++ b/src/_h5ai/js/modernizr-2.5.3.min.js @@ -0,0 +1,4 @@ +/* Modernizr 2.5.3 (Custom Build) | MIT & BSD + * Build: http://www.modernizr.com/download/#-opacity-rgba-canvas-history-audio-video-shiv-cssclasses-prefixes + */ +;window.Modernizr=function(a,b,c){function v(a){j.cssText=a}function w(a,b){return v(m.join(a+";")+(b||""))}function x(a,b){return typeof a===b}function y(a,b){return!!~(""+a).indexOf(b)}function z(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:x(f,"function")?f.bind(d||b):f}return!1}var d="2.5.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={},o={},p={},q=[],r=q.slice,s,t={}.hasOwnProperty,u;!x(t,"undefined")&&!x(t.call,"undefined")?u=function(a,b){return t.call(a,b)}:u=function(a,b){return b in a&&x(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=r.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(r.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(r.call(arguments)))};return e}),n.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},n.history=function(){return!!a.history&&!!history.pushState},n.rgba=function(){return v("background-color:rgba(150,255,150,.5)"),y(j.backgroundColor,"rgba")},n.opacity=function(){return w("opacity:.55"),/^0.55$/.test(j.opacity)},n.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},n.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c};for(var A in n)u(n,A)&&(s=A.toLowerCase(),e[s]=n[A](),q.push((e[s]?"":"no-")+s));return v(""),i=k=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e._prefixes=m,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+q.join(" "):""),e}(this,this.document); \ No newline at end of file diff --git a/src/_h5ai/js/modernizr.min.js b/src/_h5ai/js/modernizr.min.js deleted file mode 100644 index 68440dfe..00000000 --- a/src/_h5ai/js/modernizr.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/* Modernizr 2.0.6 (Custom Build) | MIT & BSD - * Build: http://www.modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-iepp-cssclasses-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load - */ -;window.Modernizr=function(a,b,c){function G(){e.input=function(a){for(var b=0,c=a.length;b",a,""].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},v=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=B(e[d],"function"),B(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),w,x={}.hasOwnProperty,y;!B(x,c)&&!B(x.call,c)?y=function(a,b){return x.call(a,b)}:y=function(a,b){return b in a&&B(a.constructor.prototype[b],c)};var F=function(a,c){var d=a.join(""),f=c.length;u(d,function(a,c){var d=b.styleSheets[b.styleSheets.length-1],g=d.cssRules&&d.cssRules[0]?d.cssRules[0].cssText:d.cssText||"",h=a.childNodes,i={};while(f--)i[h[f].id]=h[f];e.csstransforms3d=i.csstransforms3d.offsetLeft===9,e.generatedcontent=i.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(g)&&g.indexOf(c.split(" ")[0])===0},f,c)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","csstransforms3d","generatedcontent"]);q.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},q.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},q.canvastext=function(){return!!e.canvas&&!!B(b.createElement("canvas").getContext("2d").fillText,"function")},q.postmessage=function(){return!!a.postMessage},q.websqldatabase=function(){var b=!!a.openDatabase;return b},q.indexedDB=function(){for(var b=-1,c=p.length;++b7)},q.history=function(){return!!a.history&&!!history.pushState},q.draganddrop=function(){return v("dragstart")&&v("drop")},q.websockets=function(){for(var b=-1,c=p.length;++b";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++bgetOptions(); function fail($code, $msg, $cond = true) { @@ -31,11 +24,6 @@ function checkKeys($keys) { } -require_h5ai("/php/inc/H5ai.php"); -$h5ai = new H5ai(); -$options = $h5ai->getOptions(); - - list($action) = checkKeys(array("action")); @@ -64,11 +52,11 @@ if ($action === "httpcodes") { else if ($action === "thumb") { - fail(0, "thumbs are disabled", !$options["showThumbs"]); + fail(0, "thumbs are disabled", !$options["thumbnails"]["enabled"]); list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode")); - require_h5ai("/php/inc/Thumbnail.php"); - require_h5ai("/php/inc/Image.php"); + H5ai::req_once("/php/inc/Thumbnail.php"); + H5ai::req_once("/php/inc/Image.php"); $srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref); @@ -90,28 +78,42 @@ else if ($action === "thumb") { } -else if ($action === "tree") { +else if ($action === "thumbsrc") { - list($href) = checkKeys(array("href")); + if (!$options["thumbnails"]["enabled"]) { + echo json_encode(array("code" => 1, "absHref" => null)); + exit; + } - require_h5ai("/php/inc/Tree.php"); + list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode")); - $absHref = trim($href); - $absPath = $h5ai->getAbsPath($absHref); + H5ai::req_once("/php/inc/Thumbnail.php"); + H5ai::req_once("/php/inc/Image.php"); - $tree = new TreeEntry($h5ai, $absPath, $absHref); - $tree->loadContent(); + $srcAbsPath = $h5ai->getRootAbsPath() . rawurldecode($srcAbsHref); - echo $tree->contentToHtml(); + if (!Thumbnail::isUsable()) { + echo json_encode(array("code" => 2, "absHref" => null)); + exit; + } + + $thumbnail = new Thumbnail($h5ai, $srcAbsHref, $mode, $width, $height); + $thumbnail->create(1); + if (!file_exists($thumbnail->getPath())) { + echo json_encode(array("code" => 3, "absHref" => null)); + exit; + } + + echo json_encode(array("code" => 0, "absHref" => $thumbnail->getHref())); } else if ($action === "zip") { - fail(0, "zipped download is disabled", !$options["zippedDownload"]); + fail(0, "zipped download is disabled", !$options["zipped-download"]["enabled"]); list($hrefs) = checkKeys(array("hrefs")); - require_h5ai("/php/inc/ZipIt.php"); + H5ai::req_once("/php/inc/ZipIt.php"); $zipit = new ZipIt($h5ai); @@ -147,8 +149,10 @@ else if ($action === "checks") { $response = array( 'php' => $h5ai->checks["php"], - 'zips' => $h5ai->checks["php"] && $h5ai->checks["zip"], - 'thumbs' => $h5ai->checks["php"] && $h5ai->checks["gd"] + 'cache' => $h5ai->checks["php"] && $h5ai->checks["cache"], + 'thumbs' => $h5ai->checks["php"] && $h5ai->checks["cache"] && $h5ai->checks["gd"], + 'temp' => $h5ai->checks["php"] && $h5ai->checks["temp"], + 'zips' => $h5ai->checks["php"] && $h5ai->checks["temp"] && $h5ai->checks["zip"] ); echo json_encode($response); } diff --git a/src/_h5ai/php/inc/Crumb.php b/src/_h5ai/php/inc/Crumb.php deleted file mode 100644 index 76ac81b8..00000000 --- a/src/_h5ai/php/inc/Crumb.php +++ /dev/null @@ -1,55 +0,0 @@ -h5ai = $h5ai; - $this->parts = array(); - - $href = $h5ai->getAbsHref(); - while ($href !== "/") { - $this->parts[] = $href; - $href = safe_dirname($href, true); - } - $this->parts[] = "/"; - - $this->parts = array_reverse($this->parts); - } - - - public function toHtml() { - - $html = ""; - $idx = 0; - foreach($this->parts as $href) { - $idx++; - $classes = "crumb folder" . ($idx === 1 ? " domain" : "") . ($idx === count($this->parts) ? " current" : ""); - $image = $this->h5ai->image($idx === 1 ? "home" : "crumb"); - $label = $this->h5ai->getLabel($href); - $hint = ""; - - $code = $this->h5ai->getHttpCode($href); - $classes .= " checkedHttpCode"; - if ($code !== "h5ai") { - if ($code === 200) { - $hint = "page"; - } else { - $hint = "(" . $code . ")"; - } - } - - $html .= "
            • \n"; - $html .= "\t\n"; - $html .= "\t\t>" . $label . "" . $hint . "\n"; - $html .= "\t\n"; - $html .= "
            • \n"; - } - return $html; - } -} - -?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/Customize.php b/src/_h5ai/php/inc/Customize.php deleted file mode 100644 index 967770f0..00000000 --- a/src/_h5ai/php/inc/Customize.php +++ /dev/null @@ -1,35 +0,0 @@ -getAbsPath(); - $options = $h5ai->getOptions(); - $this->customHeader = $options["customHeader"] ? $absPath . "/" . $options["customHeader"] : false; - $this->customFooter = $options["customFooter"] ? $absPath . "/" . $options["customFooter"] : false; - } - - - public function getHeader() { - - return $this->getContent($this->customHeader, "header"); - } - - - public function getFooter() { - - return $this->getContent($this->customFooter, "footer"); - } - - - private function getContent($file, $tag) { - - return (is_string($file) && file_exists($file)) ? ("<$tag>" . file_get_contents($file) . "") : ""; - } -} - -?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/Entry.php b/src/_h5ai/php/inc/Entry.php new file mode 100644 index 00000000..0f53d1ee --- /dev/null +++ b/src/_h5ai/php/inc/Entry.php @@ -0,0 +1,105 @@ +absHref, $entry2->absHref); + }); + } + + + + + public $h5ai, $absPath, $absHref, $date, $size, $isFolder, $parent; + + + private function __construct($h5ai, $absPath, $absHref) { + + $this->h5ai = $h5ai; + + $this->absPath = H5ai::normalize_path($absPath); + + $this->isFolder = is_dir($this->absPath); + $this->absHref = H5ai::normalize_path($absHref, $this->isFolder); + + $this->date = filemtime($this->absPath); + + if ($this->isFolder) { + $this->size = null; + } else { + $this->size = filesize($this->absPath); + } + + $this->parent = null; + if ($this->absHref !== "/") { + $this->parent = Entry::get($this->h5ai, H5ai::normalize_path(dirname($this->absPath)), H5ai::normalize_path(dirname($this->absHref), true)); + } + + Entry::$cache[$this->absHref] = $this; + } + + + public function toJsonObject($withStatus) { + + $obj = array( + "absHref" => $this->absHref, + "time" => ($this->date * 1000), + "size" => $this->size + ); + + if ($withStatus && $this->isFolder) { + $obj["status"] = $this->h5ai->getHttpCode($this->absHref); + } + + return $obj; + } + + + public function getParent() { + + return $this->parent; + } + + + public function getContent() { + + $content = array(); + + if ($this->h5ai->getHttpCode($this->absHref) !== "h5ai") { + return $content; + } + + $files = $this->h5ai->readDir($this->absPath); + foreach ($files as $file) { + $entry = Entry::get($this->h5ai, $this->absPath . "/" . $file, $this->absHref . rawurlencode($file)); + $content[$entry->absPath] = $entry; + } + + return $content; + } +} + +?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/Extended.php b/src/_h5ai/php/inc/Extended.php deleted file mode 100644 index fd4ad5c0..00000000 --- a/src/_h5ai/php/inc/Extended.php +++ /dev/null @@ -1,152 +0,0 @@ -h5ai = $h5ai; - $this->label = $label !== null ? $label : $this->h5ai->getLabel($absHref); - $this->absPath = $this->h5ai->normalizePath($absPath, false); - $this->isFolder = is_dir($this->absPath); - $this->absHref = $this->h5ai->normalizePath($absHref, $this->isFolder); - - $this->date = filemtime($this->absPath); - - if ($this->isFolder) { - $this->type = $type !== null ? $type : "folder"; - $this->size = ""; - } else { - $this->type = $type !== null ? $type : $this->h5ai->getType($this->absPath); - $this->size = filesize($this->absPath); - } - } - - - public function isFolder() { - - return $this->isFolder; - } - - - public function toHtml() { - - $classes = "entry " . ($this->isFolder ? "folder " : "file ") . $this->type; - $imgClass = ""; - $img = $this->type; - $smallImg = $this->h5ai->icon($this->type); - $bigImg = $this->h5ai->icon($this->type, true); - $hint = ""; - - if ($this->isFolder && $this->type !== "folder-parent") { - $code = $this->h5ai->getHttpCode($this->absHref); - $classes .= " checkedHttpCode"; - if ($code !== "h5ai") { - if ($code === 200) { - $img = "folder-page"; - $smallImg = $this->h5ai->icon("folder-page"); - $bigImg = $this->h5ai->icon("folder-page", true); - } else { - $classes .= " error"; - $hint = " " . $code . " "; - } - } - } - if ($this->h5ai->showThumbs() && in_array($this->type, $this->h5ai->getThumbTypes())) { - $imgClass = " class='thumb' "; - $thumbnail = new Thumbnail($this->h5ai, $this->absHref, "square", 16, 16); - $thumbnail->create(); - $smallImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref(); - $thumbnail = new Thumbnail($this->h5ai,$this->absHref, "rational", 96, 46); - $thumbnail->create(); - $bigImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref(); - } - - $html = "\t
            • \n"; - $html .= "\t\t\n"; - $html .= "\t\t\t" . $img . "\n"; - $html .= "\t\t\t" . $img . "\n"; - $html .= "\t\t\t" . $this->label . $hint . "\n"; - $html .= "\t\t\t\n"; - $html .= "\t\t\t" . $this->size . "\n"; - $html .= "\t\t\n"; - $html .= "\t
            • \n"; - return $html; - } -} - - -class Extended { - - private $h5ai, $parent, $content; - - - public function __construct($h5ai) { - - $this->h5ai = $h5ai; - $this->parent = null; - $this->content = array(); - $this->loadContent(); - } - - - private function loadContent() { - - if ($this->h5ai->getAbsHref() !== "/") { - $options = $this->h5ai->getOptions(); - $parentPath = safe_dirname($this->h5ai->getAbsPath()); - $parentHref = safe_dirname($this->h5ai->getAbsHref(), true); - $label = $options["setParentFolderLabels"] === true ? $this->h5ai->getLabel($parentHref) : "Parent Directory"; - $this->parent = new Entry($this->h5ai, $parentPath, $parentHref, "folder-parent", $label); - } - - $this->content = array(); - - $files = $this->h5ai->readDir($this->h5ai->getAbsPath()); - foreach ($files as $file) { - $absPath = $this->h5ai->getAbsPath() . "/" . $file; - $absHref = $this->h5ai->getAbsHref() . rawurlencode($file); - $this->content[$absPath] = new Entry($this->h5ai, $absPath, $absHref); - } - } - - - public function toHtml() { - - $html = "
              \n"; - $html .= "
                \n"; - $html .= $this->generateHeaders(); - if ($this->parent !== null) { - $html .= $this->parent->toHtml(); - } - foreach($this->content as $entry) { - $html .= $entry->toHtml(); - } - $html .= "
              \n"; - if (count($this->content) === 0) { - $html .= "
              empty
              "; - } - $html .= "
              no match
              "; - $html .="
              "; - return $html; - } - - - private function generateHeaders() { - - $html = "\t
            • \n"; - $html .= "\t\t\n"; - $html .= "\t\tName\n"; - $html .= "\t\tLast modified\n"; - $html .= "\t\tSize\n"; - $html .= "\t
            • \n"; - return $html; - } -} - -?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/H5ai.php b/src/_h5ai/php/inc/H5ai.php index 24196a0a..f00c50a6 100644 --- a/src/_h5ai/php/inc/H5ai.php +++ b/src/_h5ai/php/inc/H5ai.php @@ -1,58 +1,43 @@ checks = array( - "php" => version_compare(PHP_VERSION, "5.2.0") >= 0, - "zip" => class_exists("ZipArchive"), - "gd" => GD_VERSION != "GD_VERSION" - ); - - $this->h5aiAbsPath = H5AI_ABS_PATH; - - global $H5AI_CONFIG; - $this->rootAbsPath = $H5AI_CONFIG["ROOT_ABS_PATH"]; - $this->ignore = $H5AI_CONFIG["IGNORE"]; - $this->ignoreRE = $H5AI_CONFIG["IGNORE_PATTERNS"]; - - $this->config = $this->loadConfig($this->h5aiAbsPath . "/config.js"); - $this->options = $this->config["options"]; - $this->types = $this->config["types"]; - $this->langs = $this->config["langs"]; - - $this->cache = new Cache($this->h5aiAbsPath . "/cache"); - - $this->rootAbsHref = $this->options["rootAbsHref"]; - $this->h5aiAbsHref = $this->options["h5aiAbsHref"]; - $this->domain = getenv("HTTP_HOST"); - - $this->absHref = $this->normalizePath(preg_replace('/\\?.*/', '', getenv("REQUEST_URI")), true); - $this->absPath = $this->getAbsPath($this->absHref); - - $this->view = $this->options["viewmodes"][0]; - if (!in_array($this->view, H5ai::$VIEWMODES)) { - $this->view = H5ai::$VIEWMODES[0]; - } + $path = str_replace("\\", "/", $path); + return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : "")); } - private function loadConfig($file) { + public static final function req_once($lib) { + + require_once(H5AI_ABS_PATH . $lib); + } + + + public static final function starts_with($sequence, $start) { + + return strcasecmp(substr($sequence, 0, strlen($start)), $start) === 0; + } + + + public static final function ends_with($sequence, $end) { + + return strcasecmp(substr($sequence, -strlen($end)), $end) === 0; + } + + + private static final function load_config($file) { $str = file_exists($file) ? file_get_contents($file) : ""; @@ -66,9 +51,43 @@ class H5ai { } - public function getH5aiAbsPath() { - return $this->h5aiAbsPath; + + private $h5aiAbsPath, + $rootAbsPath, $ignore, $ignoreRE, + $config, $options, + $cache, + $rootAbsHref, $h5aiAbsHref, + $absHref, $absPath; + + + public function __construct() { + + $this->h5aiAbsPath = H5ai::normalize_path(H5AI_ABS_PATH); + + global $H5AI_CONFIG; + $this->rootAbsPath = H5ai::normalize_path($H5AI_CONFIG["ROOT_ABS_PATH"]); + $this->ignore = $H5AI_CONFIG["IGNORE"]; + $this->ignoreRE = $H5AI_CONFIG["IGNORE_PATTERNS"]; + + $this->config = H5ai::load_config($this->h5aiAbsPath . "/config.js"); + $this->options = $this->config["options"]; + + $this->rootAbsHref = H5ai::normalize_path($this->options["rootAbsHref"], true); + $this->h5aiAbsHref = H5ai::normalize_path($this->options["h5aiAbsHref"], true); + + $this->absHref = H5ai::normalize_path(preg_replace('/\\?.*/', '', getenv("REQUEST_URI")), true); + $this->absPath = $this->getAbsPath($this->absHref); + + $this->cache = new Cache($this->h5aiAbsPath . "/cache"); + + $this->checks = array( + "php" => version_compare(PHP_VERSION, "5.2.0") >= 0, + "zip" => class_exists("ZipArchive"), + "gd" => GD_VERSION != "GD_VERSION", + "cache" => is_writable($this->h5aiAbsPath . "/cache"), + "temp" => is_writable(sys_get_temp_dir()) + ); } @@ -78,6 +97,12 @@ class H5ai { } + public function getH5aiAbsPath() { + + return $this->h5aiAbsPath; + } + + public function getRootAbsHref() { return $this->rootAbsHref; @@ -90,54 +115,18 @@ class H5ai { } - public function getDomain() { - - return $this->domain; - } - - - public function getView() { - - return $this->view; - } - - public function api() { return $this->h5aiAbsHref . "php/api.php"; } - public function image($id) { - - return $this->h5aiAbsHref . "images/" . $id . ".png"; - } - - - public function icon($id, $big = false) { - - return $this->h5aiAbsHref . "icons/" . ($big ? "48x48" : "16x16") . "/" . $id . ".png"; - } - - public function getOptions() { return $this->options; } - public function getLangs() { - - return $this->langs; - } - - - public function normalizePath($path, $endWithSlash) { - - return preg_match("#^(\w:)?/$#", $path) ? $path : (preg_replace('#/$#', '', $path) . ($endWithSlash ? "/" : "")); - } - - public function getAbsHref($absPath = null, $endWithSlash = true) { if ($absPath === null) { @@ -152,7 +141,7 @@ class H5ai { $encodedParts[] = rawurlencode($part); } - return $this->normalizePath($this->rootAbsHref . implode("/", $encodedParts), $endWithSlash); + return H5ai::normalize_path($this->rootAbsHref . implode("/", $encodedParts), $endWithSlash); } @@ -164,51 +153,14 @@ class H5ai { $absHref = substr($absHref, strlen($this->rootAbsHref)); - return $this->normalizePath($this->rootAbsPath . "/" . rawurldecode($absHref), false); - } - - - public function showThumbs() { - - return $this->options["showThumbs"] === true; - } - - - public function getThumbTypes() { - - return $this->options["thumbTypes"]; - } - - - public function getTitle() { - - $title = $this->domain . rawurldecode($this->absHref); - $title = preg_replace("/\/$/", "", $title); - $title = preg_replace("/\//", " > ", $title); - if ($this->absHref !== "/") { - $title = basename($this->absPath) . " - " . $title; - } - return $title; - } - - - public function getType($absPath) { - - foreach($this->types as $type => $exts) { - foreach($exts as $ext) { - if ($this->endsWith($absPath, $ext)) { - return $type; - } - } - } - return "unknown"; + return H5ai::normalize_path($this->rootAbsPath . "/" . rawurldecode($absHref)); } public function ignoreThisFile($file) { // always ignore - if ($file === "." || $file === ".." || $this->startsWith($file, '.ht')) { + if ($file === "." || $file === ".." || H5ai::starts_with($file, '.ht')) { return true; } @@ -242,24 +194,6 @@ class H5ai { } - public function getLabel($absHref) { - - return $absHref === "/" ? $this->domain : rawurldecode(basename($absHref)); - } - - - public function startsWith($sequence, $start) { - - return strcasecmp(substr($sequence, 0, strlen($start)), $start) === 0; - } - - - public function endsWith($sequence, $end) { - - return strcasecmp(substr($sequence, -strlen($end)), $end) === 0; - } - - public function getHttpCode($absHref) { //return $this->cachedHttpCode($absHref); @@ -271,12 +205,7 @@ class H5ai { $cached = $this->cache->get($absHref); if ($cached === false) { - $folderStatus = $this->options["folderStatus"]; - if (array_key_exists($absHref, $folderStatus)) { - $code = $folderStatus[$absHref]; - } else { - $code = $this->fetchHttpCode($absHref); - } + $code = $this->fetchHttpCode($absHref); $cached = array("href" => $absHref, "code" => $code); $this->cache->set($absHref, $cached); } @@ -286,6 +215,17 @@ class H5ai { public function fetchHttpCode($absHref) { + if (!is_dir($this->getAbsPath($absHref))) { + return null; + } + + if ($this->options["folderstatus"]["enabled"]) { + $folders = $this->options["folderstatus"]["folders"]; + if (array_key_exists($absHref, $folders)) { + return $folders[$absHref]; + } + } + $contentType = "Content-Type:"; $h5aiContentType = "Content-Type: text/html;h5ai="; $host = getenv("HTTP_HOST"); @@ -307,16 +247,53 @@ class H5ai { $content = fgets($socket); $code = intval(trim(substr($content, 9, 4))); if ($code === 200) { - while (! $this->startsWith($content, $contentType)) { + while (! H5ai::starts_with($content, $contentType)) { $content = fgets($socket); } - if ($this->startsWith($content, $h5aiContentType)) { + if (H5ai::starts_with($content, $h5aiContentType)) { $code = "h5ai"; } } fclose($socket); + return $code; } + + + private function fileExists($file) { + + return is_string($file) && file_exists($file); + } + + + public function getGenericJson() { + + $header = $this->options["custom"]["header"]; + $footer = $this->options["custom"]["footer"]; + $header = $this->fileExists($header ? $this->absPath . "/" . $header : null) ? $header : null; + $footer = $this->fileExists($footer ? $this->absPath . "/" . $footer : null) ? $footer : null; + + // collect and sort entries + $folder = Entry::get($this, $this->absPath, $this->absHref); + while ($folder !== null) { + $folder->getContent(); + $folder = $folder->getParent(); + } + Entry::sort(); + + $entries = array(); + foreach(Entry::getCache() as $entry) { + $entries[] = $entry->toJsonObject(true); + } + + $json = array( + "entries" => $entries, + "customHeader" => $header, + "customFooter" => $footer + ); + + return json_encode($json) . "\n"; + } } ?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/Image.php b/src/_h5ai/php/inc/Image.php index ae71db64..2eeca492 100644 --- a/src/_h5ai/php/inc/Image.php +++ b/src/_h5ai/php/inc/Image.php @@ -51,7 +51,15 @@ class Image { $this->sourceFile = $filename; - list($this->width, $this->height, $this->type) = getimagesize($this->sourceFile); + list($this->width, $this->height, $this->type) = @getimagesize($this->sourceFile); + + if (!$this->width || !$this->height) { + $this->sourceFile = null; + $this->width = null; + $this->height = null; + $this->type = null; + return; + } $this->source = imagecreatefromstring(file_get_contents($this->sourceFile)); } @@ -99,6 +107,10 @@ class Image { private function magic($destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight, $canWidth = null, $canHeight = null, $color = null) { + if (is_null($this->source)) { + return; + } + if (!is_null($canWidth) && !is_null($canHeight)) { $this->dest = imagecreatetruecolor($canWidth, $canHeight); } else { @@ -134,6 +146,10 @@ class Image { public function squareThumb($width) { + if (is_null($this->source)) { + return; + } + $a = min($this->width, $this->height); $x = intval(($this->width - $a) / 2); $y = intval(($this->height - $a) / 2); @@ -144,6 +160,10 @@ class Image { public function rationalThumb($width, $height) { + if (is_null($this->source)) { + return; + } + $r = 1.0 * $this->width / $this->height; $h = $height; @@ -164,6 +184,10 @@ class Image { public function centerThumb($width, $height, $color = null) { + if (is_null($this->source)) { + return; + } + $r = 1.0 * $this->width / $this->height; $h = $height; @@ -187,6 +211,10 @@ class Image { public function freeThumb($width, $height) { + if (is_null($this->source)) { + return; + } + $w = intval($width); $h = intval($height); diff --git a/src/_h5ai/php/inc/Thumbnail.php b/src/_h5ai/php/inc/Thumbnail.php index 6085f368..e8a1b3f4 100644 --- a/src/_h5ai/php/inc/Thumbnail.php +++ b/src/_h5ai/php/inc/Thumbnail.php @@ -1,6 +1,6 @@ h5ai = $h5ai; - - $this->label = $this->h5ai->getLabel($absHref); - $this->absPath = $this->h5ai->normalizePath($absPath, false); - $this->isFolder = is_dir($this->absPath); - $this->absHref = $this->h5ai->normalizePath($absHref, $this->isFolder); - - $this->type = $type !== null ? $type : ($this->isFolder ? "folder" : $this->h5ai->getType($this->absPath)); - $this->content = null; - } - - - public function loadContent() { - - $this->content = array(); - - if ($this->h5ai->getHttpCode($this->absHref) !== "h5ai") { - return; - } - - $files = $this->h5ai->readDir($this->absPath); - foreach ($files as $file) { - $tree = new TreeEntry($this->h5ai, $this->absPath . "/" . $file, $this->absHref . rawurlencode($file)); - - if ($tree->isFolder) { - $this->content[$tree->absPath] = $tree; - } - } - - $this->sort(); - } - - - public function cmpTrees($t1, $t2) { - - if ($t1->isFolder && !$t2->isFolder) { - return -1; - } - if (!$t1->isFolder && $t2->isFolder) { - return 1; - } - return strcasecmp($t1->absPath, $t2->absPath); - } - - - public function sort() { - - if ($this->content !== null) { - uasort($this->content, array($this, "cmpTrees")); - } - } - - - public function toHtml() { - - $classes = "entry " . $this->type . ($this->absHref === $this->h5ai->getAbsHref() ? " current" : ""); - $icon = $this->type; - if ($this->absHref === "/") { - $icon = "folder-home"; - } - $hint = ""; - $code = "h5ai"; - - if ($this->isFolder) { - $code = $this->h5ai->getHttpCode($this->absHref); - $classes .= " checkedHttpCode"; - if ($code !== "h5ai") { - if ($code === 200) { - $icon = "folder-page"; - $hint = "page"; - } else { - $classes .= " error"; - $hint = " " . $code . " "; - } - } - } - - $html = "
              \n"; - if ($this->content !== null && count($this->content) === 0 || $code !== "h5ai") { - $html .= "\n"; - } else { - $indicatorState = $this->content === null ? " unknown" : " open"; - $html .= ">\n"; - } - $html .= "\n"; - $html .= "" . $icon . ""; - $html .= "" . $this->label . "" . $hint . "\n"; - $html .= "\n"; - $html .= $this->contentToHtml(); - $html .= "
              \n"; - return $html; - } - - - public function contentToHtml() { - - $html = "
                \n"; - if ($this->content !== null) { - foreach($this->content as $tree) { - $html .= "
              • " . $tree->toHtml() . "
              • "; - } - } - $html .= "
              \n"; - return $html; - } - - - public function getRoot() { - - if ($this->absHref === "/") { - return $this; - }; - - $tree = new TreeEntry($this->h5ai, safe_dirname($this->absPath), safe_dirname($this->absHref, true)); - $tree->loadContent(); - $tree->content[$this->absPath] = $this; - - return $tree->getRoot(); - } -} - - -class Tree { - - private $h5ai; - - - public function __construct($h5ai) { - - $this->h5ai = $h5ai; - } - - - public function toHtml() { - - $options = $this->h5ai->getOptions(); - if ($options["showTree"] === false) { - return ""; - } - - $tree = new TreeEntry($this->h5ai, $this->h5ai->getAbsPath(), $this->h5ai->getAbsHref()); - $tree->loadContent(); - $root = $tree->getRoot(); - return "
              \n" . $root->toHtml() . "
              \n"; - } -} - - -?> \ No newline at end of file diff --git a/src/_h5ai/php/inc/ZipIt.php b/src/_h5ai/php/inc/ZipIt.php index 597abd0b..41b9b416 100644 --- a/src/_h5ai/php/inc/ZipIt.php +++ b/src/_h5ai/php/inc/ZipIt.php @@ -28,7 +28,7 @@ class ZipIt { $zip->addEmptyDir("/"); foreach ($hrefs as $href) { - $d = safe_dirname($href, true); + $d = H5ai::normalize_path(dirname($href, true)); $n = basename($href); $code = $this->h5ai->getHttpCode($d); if ($code == 401) { @@ -82,7 +82,7 @@ class ZipIt { } } } - return code; + return $code; } } diff --git a/src/_h5ai/php/main.php b/src/_h5ai/php/main.php deleted file mode 100644 index 2e4af69b..00000000 --- a/src/_h5ai/php/main.php +++ /dev/null @@ -1,28 +0,0 @@ - \ No newline at end of file diff --git a/src/h5ai.htaccess b/src/h5ai.htaccess index c98fe61a..71f62c3f 100644 --- a/src/h5ai.htaccess +++ b/src/h5ai.htaccess @@ -6,21 +6,25 @@ # Options +Indexes # Options +FollowSymLinks -# pure JavaScript version + HeaderName /_h5ai/header.html -# PHP version -# HeaderName /_h5ai/header.php - +# pure JavaScript version ReadmeName /_h5ai/footer.html +# PHP version +# ReadmeName /_h5ai/footer.php + + IndexIgnore _h5ai* -IndexOptions Type=text/html;h5ai=%BUILD_VERSION% IndexOptions Charset=UTF-8 +IndexOptions FancyIndexing +IndexOptions FoldersFirst +IndexOptions HTMLTable +IndexOptions NameWidth=* +IndexOptions SuppressDescription IndexOptions SuppressHTMLPreamble IndexOptions SuppressRules -IndexOptions SuppressDescription -IndexOptions NameWidth=* -IndexOptions HTMLTable +IndexOptions Type=text/html;h5ai=%BUILD_VERSION% IndexOptions XHTML diff --git a/src/index.php b/src/index.php new file mode 100644 index 00000000..597cb4d0 --- /dev/null +++ b/src/index.php @@ -0,0 +1,59 @@ + + + + + + + + + + Directory index · styled with h5ai + + + + + + + + + +
              + +
              +
              +
              +
              +
              + + h5ai %BUILD_VERSION% + ⚡ JavaScript is disabled! ⚡ + ⚡ Some features disabled! Works best in modern browsers. ⚡ + + + +
              + + + + + \ No newline at end of file