diff --git a/README.md b/README.md index 0c31883b..59474975 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,33 @@ * Q&A group: h5ai is provided under the terms of the [MIT License](http://github.com/lrsjng/h5ai/blob/master/LICENSE.txt). -It uses the [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228) (GPL license). + + +## h5ai profits from these great projects + +* [AmplifyJS](http://amplifyjs.com) (MIT/GPL) +* [Datejs](http://www.datejs.com) (MIT) +* [Faenza icon set](http://tiheum.deviantart.com/art/Faenza-Icons-173323228) (GPL) +* [HTML5 ★ Boilerplate](http://html5boilerplate.com) +* [jQuery](http://jquery.com) (MIT/GPL) +* [jQuery.mousewheel](http://github.com/brandonaaron/jquery-mousewheel) (MIT) +* [modernizr](http://www.modernizr.com) (MIT/BSD) ## Changelog - ### v0.16 · *2011-11-??* * sorts translations in `options.js` * improves HTML head sections -* refactors JavaScript a lot +* refactors JavaScript and PHP a lot * improves/fixes file selection for zipped download -* zipped download is disabled by default now -* fixed scrollbar and header/footer links issues (didn't work when zipped download enabled) +* fixes scrollbar and header/footer links issues (didn't work when zipped download enabled) +* adds support for ctrl-select +* `dateFormat` in `options.js` changed, now affecting JS and PHP version +* `dateFormat` is localizable by adding it to a translation in `options.js` +* PHP version is now configurable via `php/config.php` (set custom doc root and other PHP related things) +* image thumbs and zipped download is now disabled by default now ### v0.15.2 · *2011-09-18* diff --git a/src/h5ai/js/inc/Extended.js b/src/h5ai/js/inc/Extended.js index 1de1bec1..03d46a4e 100644 --- a/src/h5ai/js/inc/Extended.js +++ b/src/h5ai/js/inc/Extended.js @@ -52,9 +52,9 @@ H5aiJs.factory.Extended = function () { // header sort icons if (order.ascending) { - $icon = $("ascending"); + $icon = $("ascending"); } else { - $icon = $("descending"); + $icon = $("descending"); } if (order.column === "date") { $li.find("a.date").prepend($icon); diff --git a/src/h5ai/js/inc/H5ai.js b/src/h5ai/js/inc/H5ai.js index 6b3d1adb..924cd603 100644 --- a/src/h5ai/js/inc/H5ai.js +++ b/src/h5ai/js/inc/H5ai.js @@ -13,6 +13,7 @@ H5aiJs.factory.H5ai = function (options, langs) { pathClick: [] }, + h5aiAbsHref: "/h5ai", viewmodes: ["details", "icons"], sortorder: { column: "name", @@ -25,15 +26,22 @@ H5aiJs.factory.H5ai = function (options, langs) { useBrowserLang: true, setParentFolderLabels: true, linkHoverStates: true, - - dateFormat: "Y-m-d H:i", - ignore: ["h5ai", "h5ai.header.html", "h5ai.footer.html"], - ignoreRE: ["/^\\./"], + dateFormat: "yyyy-MM-dd HH:mm", showThumbs: true, - zippedDownload: true }, settings = $.extend({}, defaults, options), + api = function () { + return settings.h5aiAbsHref + "/php/api.php"; + }, + image = function (id) { + + return settings.h5aiAbsHref + "/images/" + id + ".png"; + }, + icon = function (id, big) { + + return settings.h5aiAbsHref + "/icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png"; + }, pathClick = function (fn) { if ($.isFunction(fn)) { @@ -173,6 +181,17 @@ H5aiJs.factory.H5ai = function (options, langs) { $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) { @@ -182,8 +201,8 @@ H5aiJs.factory.H5ai = function (options, langs) { href = $a.attr("href"); $a.hover( - function () { $("a[href='" + href + "']").addClass("hover"); }, - function () { $("a[href='" + href + "']").removeClass("hover"); } + function () { selectLinks(href).addClass("hover"); }, + function () { selectLinks(href).removeClass("hover"); } ); }); } @@ -191,6 +210,7 @@ H5aiJs.factory.H5ai = function (options, langs) { localize = function (langs, lang, useBrowserLang) { var storedLang = amplify.store(settings.store.lang), + dateFormat = settings.dateFormat, browserLang, selected, key; if (langs[storedLang]) { @@ -217,6 +237,17 @@ H5aiJs.factory.H5ai = function (options, langs) { $(".langOption").removeClass("current"); $(".langOption." + lang).addClass("current"); } + + dateFormat = selected.dateFormat || dateFormat; + $("#extended .entry .date").each(function () { + + var $this = $(this), + time = $this.data("time"), + formattedDate = time ? new Date(time).toString(dateFormat) : ""; + + $this.text(formattedDate); + }); + }, initLangSelector = function (langs) { @@ -261,7 +292,7 @@ H5aiJs.factory.H5ai = function (options, langs) { $entry = $indicator.closest(".entry"); if ($indicator.hasClass("unknown")) { - $.get("/h5ai/php/treecontent.php", { "href": $entry.find("> a").attr("href") }, function (html) { + $.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) { var $content = $(html); @@ -313,7 +344,7 @@ H5aiJs.factory.H5ai = function (options, langs) { href = $(this).attr("href"); query = query ? query + ":" + href : href; }); - query = "/h5ai/php/zipcontent.php?hrefs=" + query; + query = api() + "?action=zip&hrefs=" + query; $("#download").show().find("a").attr("href", query); } else { $("#download").hide().find("a").attr("href", "#"); @@ -356,8 +387,8 @@ H5aiJs.factory.H5ai = function (options, langs) { x = event.pageX; y = event.pageY; - if (x >= view.right || y >= view.bottom) { - // don't block the scrollbars + // only on left button and don't block the scrollbars + if (event.button !== 0 || x >= view.right || y >= view.bottom) { return; } @@ -417,6 +448,9 @@ H5aiJs.factory.H5ai = function (options, langs) { return { settings: settings, + api: api, + image: image, + icon: icon, shiftTree: shiftTree, linkHoverStates: linkHoverStates, pathClick: pathClick, diff --git a/src/h5ai/js/inc/Html.js b/src/h5ai/js/inc/Html.js index 79e5977e..86159622 100644 --- a/src/h5ai/js/inc/Html.js +++ b/src/h5ai/js/inc/Html.js @@ -2,16 +2,7 @@ H5aiJs.factory.Html = function () { - var imagesPath = "/h5ai/images", - iconsPath = "/h5ai/icons", - image = function (id) { - - return imagesPath + "/" + id + ".png"; - }, - icon = function (id, big) { - - return iconsPath + "/" + (big ? "48x48" : "16x16") + "/" + id + ".png"; - }, + var thumbExts = ["bmp", "gif", "ico", "image", "jpg", "jpeg", "png", "tiff"], onClick = function (path, context) { H5aiJs.h5ai.triggerPathClick(path, context); @@ -32,14 +23,14 @@ H5aiJs.factory.Html = function () { $html.data("status", path.status); } - $a = $(">" + path.label + "") + $a = $(">" + path.label + "") .appendTo($html) .attr("href", path.absHref) .click(function() { onClick(path, "crumb"); }); if (path.isDomain) { $html.addClass("domain"); - $a.find("img").attr("src", image("home")); + $a.find("img").attr("src", H5aiJs.h5ai.image("home")); } if (path.isCurrentFolder) { @@ -48,7 +39,7 @@ H5aiJs.factory.Html = function () { if (!isNaN(path.status)) { if (path.status === 200) { - $("not listable").appendTo($a); + $("not listable").appendTo($a); } else { $("(" + path.status + ")").appendTo($a); } @@ -63,7 +54,11 @@ H5aiJs.factory.Html = function () { }, updateExtendedHtml = function (path) { - var $html, $a, $label; + var $html, $a, $label, + formattedDate = path.date ? path.date.toString(H5aiJs.h5ai.settings.dateFormat) : "", + ext = path.absHref.substr((path.absHref.lastIndexOf('.') + 1)), + icon16 = path.icon16, + icon48 = path.icon48; if (path.html.$extended && path.html.$extended.data("status") === path.status) { return path.html.$extended; @@ -77,15 +72,20 @@ H5aiJs.factory.Html = function () { $html.data("status", path.status); } + if (H5aiJs.h5ai.settings.showThumbs && $.inArray(ext.toLowerCase(), thumbExts) >= 0) { + icon16 = H5aiJs.h5ai.api() + "?action=thumb&href=" + path.absHref + "&width=16&height=16&mode=square"; + icon48 = H5aiJs.h5ai.api() + "?action=thumb&href=" + path.absHref + "&width=96&height=46&mode=rational"; + } + $label = $("" + path.label + ""); $a = $("") .attr("href", path.absHref) .click(function() { onClick(path, "extended"); }) .appendTo($html) - .append($("" + path.alt + "")) - .append($("" + path.alt + "")) + .append($("" + path.alt + "")) + .append($("" + path.alt + "")) .append($label) - .append($("" + path.date + "")) + .append($("")) .append($("" + path.size + "")); $a.hover( @@ -123,8 +123,8 @@ H5aiJs.factory.Html = function () { if (!isNaN(path.status)) { if (path.status === 200) { $html.addClass("page"); - $a.find(".icon.small img").attr("src", icon("folder-page")); - $a.find(".icon.big img").attr("src", icon("folder-page", true)); + $a.find(".icon.small img").attr("src", H5aiJs.h5ai.icon("folder-page")); + $a.find(".icon.big img").attr("src", H5aiJs.h5ai.icon("folder-page", true)); } else { $html.addClass("error"); $label.append($(" " + path.status + " ")); @@ -158,7 +158,7 @@ H5aiJs.factory.Html = function () { if (path.isFolder) { // indicator if (path.status === undefined || !path.isEmpty()) { - $indicator = $("") + $indicator = $("") .click(function (event) { var $entry = $indicator.closest(".entry"); // $html @@ -205,13 +205,13 @@ H5aiJs.factory.Html = function () { // is path the domain? if (path.isDomain) { $html.addClass("domain"); - $a.find(".icon img").attr("src", icon("folder-home")); + $a.find(".icon img").attr("src", H5aiJs.h5ai.icon("folder-home")); } // is path the current folder? if (path.isCurrentFolder) { $html.addClass("current"); - $a.find(".icon img").attr("src", icon("folder-open")); + $a.find(".icon img").attr("src", H5aiJs.h5ai.icon("folder-open")); } // does it have subfolders? @@ -228,8 +228,8 @@ H5aiJs.factory.Html = function () { // reflect folder status if (!isNaN(path.status)) { if (path.status === 200) { - $a.find(".icon img").attr("src", icon("folder-page")); - $a.append($("")); + $a.find(".icon img").attr("src", H5aiJs.h5ai.icon("folder-page")); + $a.append($("")); } else { $html.addClass("error"); $a.append($("" + path.status + "")); diff --git a/src/h5ai/js/inc/Path.js b/src/h5ai/js/inc/Path.js index 03c1d5ba..9cf72a2f 100644 --- a/src/h5ai/js/inc/Path.js +++ b/src/h5ai/js/inc/Path.js @@ -11,7 +11,9 @@ H5aiJs.factory.Path = function (folder, tableRow) { // parentFolder: undefined, // label: undefined, + // dateOrgStr: undefined, // date: undefined, + // time: undefined, // size: undefined, // href: undefined, // absHref: undefined, @@ -31,7 +33,7 @@ H5aiJs.factory.Path = function (folder, tableRow) { $tree: undefined }; this.treeOpen = false; - + if (!H5aiJs.pathCache.pathEndsWithSlash(folder)) { folder += "/"; } @@ -43,7 +45,9 @@ H5aiJs.factory.Path = function (folder, tableRow) { this.parentFolder = folder; this.label = $a.text(); - this.date = $tds.eq(2).text(); + this.dateOrgStr = $tds.eq(2).text(); + this.date = Date.parse(this.dateOrgStr); + this.time = this.date ? this.date.getTime() : 0; this.size = $tds.eq(3).text(); this.href = $a.attr("href"); this.alt = $img.attr("alt"); @@ -56,11 +60,13 @@ H5aiJs.factory.Path = function (folder, tableRow) { if (this.label === "/") { this.label = checkedDecodeUri(document.domain) + "/"; } - this.date = ""; + this.dateOrgStr = ""; + this.date = null; + this.time = 0; this.size = ""; this.href = splits[1]; this.alt = "[DIR]"; - this.icon16 = "/h5ai/icons/16x16/folder.png"; + this.icon16 = H5aiJs.h5ai.icon("folder"); } if (H5aiJs.pathCache.pathEndsWithSlash(this.label)) { @@ -84,7 +90,7 @@ H5aiJs.factory.Path = function (folder, tableRow) { }; H5aiJs.factory.Path.prototype = { - + isEmpty: function () { return !this.content || $.isEmptyObject(this.content); diff --git a/src/h5ai/js/inc/lib/date.js b/src/h5ai/js/inc/lib/date.js new file mode 100644 index 00000000..77f49864 --- /dev/null +++ b/src/h5ai/js/inc/lib/date.js @@ -0,0 +1,104 @@ +/** + * Version: 1.0 Alpha-1 + * Build Date: 13-Nov-2007 + * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved. + * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/ + */ +Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}}; +Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;idate)?1:(this=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;} +var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);} +if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);} +if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);} +if(x.hour||x.hours){this.addHours(x.hour||x.hours);} +if(x.month||x.months){this.addMonths(x.month||x.months);} +if(x.year||x.years){this.addYears(x.year||x.years);} +if(x.day||x.days){this.addDays(x.day||x.days);} +return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(valuemax){throw new RangeError(value+" is not a valid value for "+name+".");} +return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;} +if(!x.second&&x.second!==0){x.second=-1;} +if(!x.minute&&x.minute!==0){x.minute=-1;} +if(!x.hour&&x.hour!==0){x.hour=-1;} +if(!x.day&&x.day!==0){x.day=-1;} +if(!x.month&&x.month!==0){x.month=-1;} +if(!x.year&&x.year!==0){x.year=-1;} +if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());} +if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());} +if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());} +if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());} +if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());} +if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());} +if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());} +if(x.timezone){this.setTimezone(x.timezone);} +if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);} +return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;} +var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}} +return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();}; +Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;} +return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;} +if(!last&&q[1].length===0){last=true;} +if(!last){var qx=[];for(var j=0;j0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}} +if(rx[1].length1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];} +if(args){for(var i=0,px=args.shift();i2)?n:(n+(((n+2000)Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");} +var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});} +return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;} +for(var i=0;igetOptions(); + + +if ($action === "httpcodes") { + + list($hrefs) = checkKeys(array("hrefs")); + + function getHttpCodes($h5ai, $hrefs) { + + $codes = array(); + foreach ($hrefs as $href) { + $href = trim($href); + if (strlen($href) > 0) { + $codes[$href] = $h5ai->getHttpCode($href); + } + } + return $codes; + } + + $hrefs = preg_split("/;/", $hrefs); + $codes = getHttpCodes($h5ai, $hrefs); + + echo count($codes) === 0 ? "{}" : json_encode($codes); +} + + +else if ($action === "thumb") { + + fail(0, "thumbs are disabled", !$options["showThumbs"]); + list($srcAbsHref, $width, $height, $mode) = checkKeys(array("href", "width", "height", "mode")); + + require_once "inc/Thumbnail.php"; + require_once "inc/Image.php"; + + $srcAbsPath = $h5ai->getDocRoot() . rawurldecode($srcAbsHref); + + if (!Thumbnail::isUsable()) { + Image::showImage($srcAbsPath); + exit; + } + + $thumbnail = new Thumbnail($h5ai, $srcAbsHref, $mode, $width, $height); + $thumbnail->create(1); + if (file_exists($thumbnail->getPath())) { + Image::showImage($thumbnail->getPath()); + } else { + $image = new Image(); + $image->setSource($srcAbsPath); + $image->thumb($mode, $width, $height); + $image->showDest(); + } +} + + +else if ($action === "tree") { + + list($href) = checkKeys(array("href")); + + require_once "inc/Tree.php"; + + $absHref = trim($href); + $absPath = $h5ai->getAbsPath($absHref); + + $tree = new TreeEntry($h5ai, $absPath, $absHref); + $tree->loadContent(); + + echo $tree->contentToHtml(); +} + + +else if ($action === "zip") { + + fail(0, "zipped download is disabled", !$options["zippedDownload"]); + list($hrefs) = checkKeys(array("hrefs")); + + require_once "inc/ZipIt.php"; + + $zipit = new ZipIt($h5ai); + + $hrefs = explode(":", trim($hrefs)); + $zipFile = $zipit->zip($hrefs); + + if ($zipFile === false) { + fail(2, "something went wrong while building the zip"); + } + + header("Content-Disposition: attachment; filename=\"h5ai-selection.zip\""); + header("Content-Type: application/force-download"); + header("Content-Length: " . filesize($zipFile)); + header("Connection: close"); + readfile($zipFile); +} + + +else { + fail(1, "unsupported 'action' specified"); +} + + +?> \ No newline at end of file diff --git a/src/h5ai/php/config.php b/src/h5ai/php/config.php new file mode 100644 index 00000000..dba64056 --- /dev/null +++ b/src/h5ai/php/config.php @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/h5ai/php/httpcode.php b/src/h5ai/php/httpcode.php deleted file mode 100644 index 73383f53..00000000 --- a/src/h5ai/php/httpcode.php +++ /dev/null @@ -1,23 +0,0 @@ - 0) { - $codes[$href] = $h5ai->getHttpCode($href); - } - } - return $codes; -} - -$h5ai = new H5ai(); -$hrefs = preg_split("/;/", array_key_exists("hrefs", $_REQUEST) ? $_REQUEST[ "hrefs" ] : ""); -$codes = getHttpCodes($h5ai, $hrefs); - -echo count($codes) === 0 ? "{}" : json_encode($codes); - -?> \ No newline at end of file diff --git a/src/h5ai/php/cache.php b/src/h5ai/php/inc/Cache.php similarity index 100% rename from src/h5ai/php/cache.php rename to src/h5ai/php/inc/Cache.php diff --git a/src/h5ai/php/crumb.php b/src/h5ai/php/inc/Crumb.php similarity index 88% rename from src/h5ai/php/crumb.php rename to src/h5ai/php/inc/Crumb.php index e96a8f49..fd1fd78c 100644 --- a/src/h5ai/php/crumb.php +++ b/src/h5ai/php/inc/Crumb.php @@ -25,7 +25,7 @@ class Crumb { foreach($this->parts as $href) { $idx++; $classes = "crumb folder" . ($idx === 1 ? " domain" : "") . ($idx === count($this->parts) ? " current" : ""); - $image = "/h5ai/images/" . ($idx === 1 ? "home.png" : "crumb.png"); + $image = $this->h5ai->image($idx === 1 ? "home" : "crumb"); $label = $this->h5ai->getLabel($href); $hint = ""; @@ -33,7 +33,7 @@ class Crumb { $classes .= " checkedHttpCode"; if ($code !== "h5ai") { if ($code === 200) { - $hint = "page"; + $hint = "page"; } else { $hint = "(" . $code . ")"; } diff --git a/src/h5ai/php/customize.php b/src/h5ai/php/inc/Customize.php similarity index 65% rename from src/h5ai/php/customize.php rename to src/h5ai/php/inc/Customize.php index 58341b56..f64e6b49 100644 --- a/src/h5ai/php/customize.php +++ b/src/h5ai/php/inc/Customize.php @@ -10,12 +10,12 @@ class Customize { public function getHeader() { - return $this->getContent($this->h5ai->getAbsPath() . "/" . "h5ai.header.html", "header"); + return $this->getContent($this->h5ai->getAbsPath() . "/h5ai.header.html", "header"); } public function getFooter() { - return $this->getContent($this->h5ai->getAbsPath() . "/" . "h5ai.footer.html", "footer"); + return $this->getContent($this->h5ai->getAbsPath() . "/h5ai.footer.html", "footer"); } private function getContent($file, $tag) { diff --git a/src/h5ai/php/extended.php b/src/h5ai/php/inc/Extended.php similarity index 90% rename from src/h5ai/php/extended.php rename to src/h5ai/php/inc/Extended.php index daba91eb..67b00b8d 100644 --- a/src/h5ai/php/extended.php +++ b/src/h5ai/php/inc/Extended.php @@ -1,6 +1,6 @@ type; $img = $this->type; - $smallImg = "/h5ai/icons/16x16/" . $this->type . ".png"; - $bigImg = "/h5ai/icons/48x48/" . $this->type . ".png"; + $smallImg = $this->h5ai->icon($this->type); + $bigImg = $this->h5ai->icon($this->type, true); $hint = ""; - $dateLabel = date($dateFormat, $this->date); if ($this->isFolder && $this->type !== "folder-parent") { $code = $this->h5ai->getHttpCode($this->absHref); @@ -70,8 +69,8 @@ class Entry { if ($code !== "h5ai") { if ($code === 200) { $img = "folder-page"; - $smallImg = "/h5ai/icons/16x16/folder-page.png"; - $bigImg = "/h5ai/icons/48x48/folder-page.png"; + $smallImg = $this->h5ai->icon("folder-page"); + $bigImg = $this->h5ai->icon("folder-page", true); } else { $classes .= " error"; $hint = " " . $code . " "; @@ -80,10 +79,10 @@ class Entry { } if ($this->h5ai->showThumbs() && in_array($this->type, $this->thumbTypes)) { $classes .= " thumb"; - $thumbnail = new Thumbnail($this->absPath, "square", 16, 16); + $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->absPath, "rational", 96, 46); + $thumbnail = new Thumbnail($this->h5ai,$this->absHref, "rational", 96, 46); $thumbnail->create(); $bigImg = file_exists($thumbnail->getPath()) ? $thumbnail->getHref() : $thumbnail->getLiveHref(); } @@ -93,7 +92,7 @@ class Entry { $html .= "\t\t\t" . $img . "\n"; $html .= "\t\t\t" . $img . "\n"; $html .= "\t\t\t" . $this->label . $hint . "\n"; - $html .= "\t\t\t" . $dateLabel . "\n"; + $html .= "\t\t\t\n"; $html .= "\t\t\t" . $this->formatSize($this->size) . "\n"; $html .= "\t\t\n"; $html .= "\t\n"; @@ -198,8 +197,8 @@ class Extended { public function generateHeaders() { - $asc = "ascending"; - $desc = "descending"; + $asc = "ascending"; + $desc = "descending"; $so = $this->h5ai->getSortOrder(); $order = $so["ascending"] ? $asc : $desc; diff --git a/src/h5ai/php/h5ai.php b/src/h5ai/php/inc/H5ai.php similarity index 86% rename from src/h5ai/php/h5ai.php rename to src/h5ai/php/inc/H5ai.php index b50ebfbb..4e332956 100644 --- a/src/h5ai/php/h5ai.php +++ b/src/h5ai/php/inc/H5ai.php @@ -1,34 +1,37 @@ "name", "ascending" => true); private static $VIEWMODES = array("details", "icons"); - private $docRoot, $domain, $options, $types, $cache, $absHref, $absPath, $ignore, $ignoreRE, $sortOrder, $dateFormat, $view; + private $docRoot, $h5aiRoot, $h5aiAbsHref, $domain, $options, $types, $cache, $absHref, $absPath, $ignore, $ignoreRE, $sortOrder, $dateFormat, $view; public function __construct() { - $this->docRoot = getenv("DOCUMENT_ROOT"); - $this->domain = getenv("HTTP_HOST"); + global $H5AI_CONFIG; - $this->options = $this->loadOptions($this->docRoot . "/h5ai/options.js"); - $this->types = $this->loadTypes($this->docRoot . "/h5ai/types.txt"); - $this->cache = new Cache($this->docRoot . "/h5ai/cache"); + $this->docRoot = $H5AI_CONFIG["DOCUMENT_ROOT"]; + $this->h5aiRoot = $H5AI_CONFIG["H5AI_ROOT"]; + $this->ignore = $H5AI_CONFIG["IGNORE"]; + $this->ignoreRE = $H5AI_CONFIG["IGNORE_PATTERNS"]; + + $this->options = $this->loadOptions($this->h5aiRoot . "/options.js"); + $this->types = $this->loadTypes($this->h5aiRoot . "/types.txt"); + $this->cache = new Cache($this->h5aiRoot . "/cache"); + + $this->h5aiAbsHref = $this->options["options"]["h5aiAbsHref"]; + $this->domain = getenv("HTTP_HOST"); $this->absHref = $this->normalizePath(preg_replace('/\\?.*/', '', getenv("REQUEST_URI")), true); $this->absPath = $this->normalizePath($this->docRoot . rawurldecode($this->absHref), false); - $this->ignore = $this->options["options"]["ignore"]; - $this->ignoreRE = $this->options["options"]["ignoreRE"]; - $defaultSortOrder = $this->options["options"]["sortorder"]; $this->sortOrder = array( "column" => array_key_exists("col", $_REQUEST) ? $_REQUEST["col"] : $defaultSortOrder["column"], "ascending" => array_key_exists("asc", $_REQUEST) ? $_REQUEST["asc"] !== "false" : $defaultSortOrder["ascending"] ); - $this->dateFormat = $this->options["options"]["dateFormat"]; $this->view = array_key_exists("view", $_REQUEST) ? $_REQUEST["view"] : $this->options["options"]["viewmodes"][0]; if (!in_array($this->view, H5ai::$VIEWMODES)) { $this->view = H5ai::$VIEWMODES[0]; @@ -71,6 +74,16 @@ class H5ai { return $this->docRoot; } + public function getH5aiRoot() { + + return $this->h5aiRoot; + } + + public function getH5aiAbsHref() { + + return $this->h5aiAbsHref; + } + public function getDomain() { return $this->domain; @@ -81,6 +94,21 @@ class H5ai { 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["options"]; diff --git a/src/h5ai/php/image.php b/src/h5ai/php/inc/Image.php similarity index 98% rename from src/h5ai/php/image.php rename to src/h5ai/php/inc/Image.php index 09634639..4572fc49 100644 --- a/src/h5ai/php/image.php +++ b/src/h5ai/php/inc/Image.php @@ -17,6 +17,14 @@ class Image { } + public static function showImage($filename) { + + $image = file_get_contents($filename); + header("content-type: image"); + echo $image; + } + + public function __construct($filename = null) { $this->sourceFile = null; @@ -43,8 +51,9 @@ class Image { $this->releaseSource(); $this->releaseDest(); - if (is_null($filename)) + if (is_null($filename)) { return; + } $this->sourceFile = $filename; @@ -94,14 +103,6 @@ class Image { } - public static function showImage($filename) { - - $image = file_get_contents($filename); - header("content-type: image"); - echo $image; - } - - private function magic($destX, $destY, $srcX, $srcY, $destWidth, $destHeight, $srcWidth, $srcHeight, $canWidth = null, $canHeight = null, $color = null) { if (!is_null($canWidth) && !is_null($canHeight)) { diff --git a/src/h5ai/php/inc/Thumbnail.php b/src/h5ai/php/inc/Thumbnail.php new file mode 100644 index 00000000..153c41b1 --- /dev/null +++ b/src/h5ai/php/inc/Thumbnail.php @@ -0,0 +1,59 @@ +h5ai = $h5ai; + $this->srcAbsHref = $absHref; + $this->srcAbsPath = $this->h5ai->getDocRoot() . urldecode($absHref); + $this->width = $width; + $this->height = $height; + $this->mode = $mode; + $this->name = sha1("$this->srcAbsPath-$this->width-$this->height-$this->mode"); + $this->href = $this->h5ai->getH5aiAbsHref() . "/cache/thumb-" . $this->name . ".jpg"; + $this->path = $this->h5ai->getDocRoot() . $this->href; + $this->liveHref = $this->h5ai->api() . "?action=thumb&href=" . $this->srcAbsHref . "&width=" . $this->width . "&height=" . $this->height . "&mode=" . $this->mode; + } + + public function create($force = 0) { + + if ( + $force === 2 + || ($force === 1 && !file_exists($this->path)) + || (file_exists($this->path) && filemtime($this->srcAbsPath) >= filemtime($this->path)) + ) { + $image = new Image(); + $image->setSource($this->srcAbsPath); + $image->thumb($this->mode, $this->width, $this->height); + $image->saveDest($this->path); + } + } + + public function getHref() { + + return $this->href; + } + + public function getPath() { + + return $this->path; + } + + public function getLiveHref() { + + return $this->liveHref; + } +} + +?> \ No newline at end of file diff --git a/src/h5ai/php/tree.php b/src/h5ai/php/inc/Tree.php similarity index 90% rename from src/h5ai/php/tree.php rename to src/h5ai/php/inc/Tree.php index 270e3a9e..659e53e2 100644 --- a/src/h5ai/php/tree.php +++ b/src/h5ai/php/inc/Tree.php @@ -57,9 +57,9 @@ class TreeEntry { public function toHtml() { $classes = "entry " . $this->type . ($this->absHref === $this->h5ai->getAbsHref() ? " current" : ""); - $img = $this->type; + $icon = $this->type; if ($this->absHref === "/") { - $img = "folder-home"; + $icon = "folder-home"; } $hint = ""; $code = "h5ai"; @@ -69,8 +69,8 @@ class TreeEntry { $classes .= " checkedHttpCode"; if ($code !== "h5ai") { if ($code === 200) { - $img = "folder-page"; - $hint = "page"; + $icon = "folder-page"; + $hint = "page"; } else { $classes .= " error"; $hint = " " . $code . " "; @@ -83,10 +83,10 @@ class TreeEntry { $html .= "\n"; } else { $indicatorState = $this->content === null ? " unknown" : " open"; - $html .= ">\n"; + $html .= ">\n"; } $html .= "\n"; - $html .= "" . $img . "\n"; + $html .= "" . $icon . "\n"; $html .= "" . $this->label . "" . $hint . "\n"; $html .= "\n"; $html .= $this->contentToHtml(); diff --git a/src/h5ai/php/zipit.php b/src/h5ai/php/inc/ZipIt.php similarity index 99% rename from src/h5ai/php/zipit.php rename to src/h5ai/php/inc/ZipIt.php index 54cfec38..c4be9ec9 100644 --- a/src/h5ai/php/zipit.php +++ b/src/h5ai/php/inc/ZipIt.php @@ -43,7 +43,7 @@ class ZipIt { } private function zipDir($zip, $localDir, $dir) { - + if ($this->h5ai->getHttpCode($this->h5ai->getAbsHref($localDir)) === "h5ai") { $zip->addEmptyDir($dir); $files = $this->h5ai->readDir($localDir); diff --git a/src/h5ai/php/main.php b/src/h5ai/php/main.php index d8a5fdba..a11e837a 100644 --- a/src/h5ai/php/main.php +++ b/src/h5ai/php/main.php @@ -1,10 +1,11 @@ create(1); - if (file_exists($thumbnail->getPath())) { - Image::showImage($thumbnail->getPath()); - } else { - $image = new Image(); - $image->setSource($src); - $image->thumb($mode, $width, $height); - $image->showDest(); - } - -?> \ No newline at end of file diff --git a/src/h5ai/php/thumbnail.php b/src/h5ai/php/thumbnail.php deleted file mode 100644 index b7fbcf96..00000000 --- a/src/h5ai/php/thumbnail.php +++ /dev/null @@ -1,56 +0,0 @@ -src = $src; - $this->width = $width; - $this->height = $height; - $this->mode = $mode; - $this->name = sha1("$this->src-$this->width-$this->height-$this->mode"); - $this->href = "/h5ai/cache/thumb-" . $this->name . ".jpg"; - $this->path = getenv("DOCUMENT_ROOT") . $this->href; - $this->liveHref = "/h5ai/php/thumb.php?src=" . $this->src . "&width=" . $this->width . "&height=" . $this->height . "&mode=" . $this->mode; - } - - public function create($force = 0) { - - if ( - $force === 2 - || ($force === 1 && !file_exists($this->path)) - || (file_exists($this->path) && filemtime($this->src) >= filemtime($this->path)) - ) { - $image = new Image(); - $image->setSource($this->src); - $image->thumb($this->mode, $this->width, $this->height); - $image->saveDest($this->path); - } - } - - public function getHref() { - - return $this->href; - } - - public function getPath() { - - return $this->path; - } - - public function getLiveHref() { - - return $this->liveHref; - } -} - -?> \ No newline at end of file diff --git a/src/h5ai/php/treecontent.php b/src/h5ai/php/treecontent.php deleted file mode 100644 index 5a23340a..00000000 --- a/src/h5ai/php/treecontent.php +++ /dev/null @@ -1,20 +0,0 @@ -getAbsPath($absHref); - -$tree = new TreeEntry($h5ai, $absPath, $absHref); -$tree->loadContent(); - -echo $tree->contentToHtml(); - -?> \ No newline at end of file diff --git a/src/h5ai/php/zipcontent.php b/src/h5ai/php/zipcontent.php deleted file mode 100644 index fe68ea60..00000000 --- a/src/h5ai/php/zipcontent.php +++ /dev/null @@ -1,27 +0,0 @@ -zip($hrefs); - -if ($zipFile !== false) { - header("Content-Disposition: attachment; filename=\"h5ai-selection.zip\""); - header("Content-Type: application/force-download"); - header("Content-Length: " . filesize($zipFile)); - header("Connection: close"); - readfile($zipFile); -} else { - echo "2: something went wrong while building the zip"; -} - -?> \ No newline at end of file