Another partial commit.

This commit is contained in:
Lars Jung 2012-10-07 13:48:27 +02:00
parent abb9b7bd0e
commit cb9341451b
15 changed files with 88 additions and 453 deletions

View file

@ -58,12 +58,14 @@ To create an fresh zipball run
* adds drag'n'drop upload (PHP)
* adds file deletion (PHP)
* cleans and improves PHP code
* PHP no longer respects htaccess restrictions (so be careful)
* PHP ignore patterns might include paths now
* improves separation between aai and php mode
* adds optional binary prefixes for file sizes
* improves filter: autofocus on keypress, clear on `ESC`
* adds ctrl-click file selection
* adds Piwik analytics support
* temp download packages are now stored in the `_h5ai/cache` and deleted as soon as possible
* temp download packages are now stored in the `cache`-folder and deleted as soon as possible
* localization now in separate files
* updates translations
* adds `he` translation by [Tomer Cohen](https://github.com/tomer)

View file

@ -1,125 +0,0 @@
modulejs.define('core/ajax', ['$', 'amplify', 'base64', 'core/resource'], function ($, amplify, base64, resource) {
var reContentType = /^text\/html;h5ai=/,
getStatus = function (href, withContent, callback) {
$.ajax({
url: href,
type: withContent ? 'GET' : 'HEAD',
complete: function (xhr) {
var res = {
status: xhr.status,
content: xhr.responseText
};
if (xhr.status === 200 && reContentType.test(xhr.getResponseHeader('Content-Type'))) {
res.status = 'h5ai';
}
callback(res);
}
});
},
getChecks = function (callback) {
$.ajax({
url: resource.api(),
data: {
action: 'get',
checks: true
},
type: 'POST',
dataType: 'json',
success: function (json) {
callback(json.checks);
},
error: function () {
callback();
}
});
},
getEntries = function (href, what, callback) {
$.ajax({
url: resource.api(),
data: {
action: 'get',
entries: true,
entriesHref: href,
entriesWhat: what
},
type: 'POST',
dataType: 'json',
success: function (json) {
callback(json.entries);
},
error: function () {
callback();
}
});
},
getArchive = function (data, callback) {
$.ajax({
url: resource.api(),
data: {
action: 'archive',
execution: data.execution,
format: data.format,
hrefs: data.hrefs
},
type: 'POST',
dataType: 'json',
beforeSend: function (xhr) {
if (data.user) {
xhr.setRequestHeader('Authorization', 'Basic ' + base64.encode(data.user + ':' + data.password));
}
},
success: function (json) {
callback(json);
},
error: function () {
callback();
}
});
},
getHtml = function (url, callback) {
$.ajax({
url: url,
type: 'POST',
dataType: 'html',
success: function (html) {
callback(html);
},
error: function () {
callback();
}
});
};
return {
getStatus: getStatus,
getChecks: getChecks,
getEntries: getEntries,
getArchive: getArchive,
getHtml: getHtml
};
});

View file

@ -1,12 +0,0 @@
modulejs.define('core/mode', [], function () {
var mode = {
// id: null,
// dataType: null,
// serverName: null,
// serverVersion: null
};
return mode;
});

View file

@ -1,5 +1,5 @@
modulejs.define('core/server', ['$', '_', 'config', 'base64'], function ($, _, config, base64) {
modulejs.define('core/server', ['$', '_', 'config'], function ($, _, config) {
var server = _.extend({}, config.server, {
@ -26,81 +26,20 @@ modulejs.define('core/server', ['$', '_', 'config', 'base64'], function ($, _, c
});
},
requestArchive: function (data, callback) {
requestThumbSmall: function (type, href, callback) {
if (!server.apiHref) {
callback();
return;
}
$.ajax({
url: server.apiHref,
data: {
action: 'archive',
execution: data.execution,
format: data.format,
hrefs: data.hrefs
},
type: 'POST',
dataType: 'json',
beforeSend: function (xhr) {
if (data.user) {
xhr.setRequestHeader('Authorization', 'Basic ' + base64.encode(data.user + ':' + data.password));
}
},
success: function (json) {
callback(json);
},
error: function () {
callback();
}
});
},
requestThumb: function (data, callback) {
server.request({
action: 'getthumbsrc',
type: data.type,
href: data.href,
mode: data.mode,
width: data.width,
height: data.height
}, function (json) {
server.request({action: 'getthumbsrc', type: type, href: href, mode: 'square', width: 16, height: 16}, function (json) {
callback(json && json.code === 0 ? json.absHref : null);
});
},
requestThumbSmall: function (type, href, callback) {
server.requestThumb(
{
type: type,
href: href,
mode: 'square',
width: 16,
height: 16
},
callback
);
},
requestThumbBig: function (type, href, callback) {
server.requestThumb(
{
type: type,
href: href,
mode: 'rational',
width: 100,
height: 48
},
callback
);
server.request({action: 'getthumbsrc', type: type, href: href, mode: 'rational', width: 100, height: 48}, function (json) {
callback(json && json.code === 0 ? json.absHref : null);
});
}
});

View file

@ -1,5 +1,5 @@
modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/ajax'], function (_, $, allsettings, ajax) {
modulejs.define('ext/custom', ['_', '$', 'core/settings'], function (_, $, allsettings) {
var settings = _.extend({
enabled: false,
@ -7,6 +7,23 @@ modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/ajax'], function
footer: '_h5ai.footer.html'
}, allsettings.custom),
getHtml = function (url, callback) {
$.ajax({
url: url,
type: 'POST',
dataType: 'html',
success: function (html) {
callback(html);
},
error: function () {
callback();
}
});
},
init = function () {
if (!settings.enabled) {
@ -14,7 +31,7 @@ modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/ajax'], function
}
if (_.isString(settings.header)) {
ajax.getHtml(settings.header, function (html) {
getHtml(settings.header, function (html) {
if (html) {
$('<div id="content-header">' + html + '</div>').prependTo('#content');
@ -23,7 +40,7 @@ modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/ajax'], function
}
if (_.isString(settings.footer)) {
ajax.getHtml(settings.footer, function (html) {
getHtml(settings.footer, function (html) {
if (html) {
$('<div id="content-footer">' + html + '</div>').appendTo('#content');

View file

@ -1,5 +1,5 @@
modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/event', 'core/resource', 'core/refresh'], function (_, $, allsettings, entry, event, resource, refresh) {
modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/event', 'core/resource', 'core/refresh', 'core/server'], function (_, $, allsettings, event, resource, refresh, server) {
var settings = _.extend({
enabled: false
@ -8,16 +8,12 @@ modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/ev
deleteBtnTemplate = '<li id="delete">' +
'<a href="#">' +
'<img src="' + resource.image('delete') + '" alt="delete"/>' +
'<span class="l10n-delete">delete</span>' +
'<span class="l10n-delete"/>' +
'</a>' +
'</li>',
authTemplate = '<div id="delete-auth">' +
'<input id="delete-auth-user" type="text" value="" placeholder="user"/>' +
'<input id="delete-auth-password" type="text" value="" placeholder="password"/>' +
'</div>',
selectedHrefsStr = '',
$delete, $img, $deleteAuth, $deleteUser, $deletePassword,
$delete, $img,
failed = function () {
@ -33,15 +29,6 @@ modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/ev
$img.attr('src', resource.image('delete'));
if (!json || json.code) {
if (json && json.code === 401) {
$deleteAuth
.css({
left: $delete.offset().left,
top: $delete.offset().top + $delete.outerHeight()
})
.show();
$deleteUser.focus();
}
failed();
}
refresh();
@ -51,17 +38,7 @@ modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/ev
$delete.addClass('current');
$img.attr('src', resource.image('loading.gif', true));
$.ajax({
url: resource.api(),
data: {
action: 'delete',
hrefs: hrefsStr,
user: $deleteUser.val(),
password: $deletePassword.val()
},
dataType: 'json',
success: handleResponse
});
server.request({action: 'delete', hrefs: hrefsStr}, handleResponse);
},
onSelection = function (entries) {
@ -75,13 +52,12 @@ modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/ev
$delete.appendTo('#navbar').show();
} else {
$delete.hide();
$deleteAuth.hide();
}
},
init = function () {
if (!settings.enabled) {
if (!settings.enabled || !server.apiHref) {
return;
}
@ -89,16 +65,11 @@ modulejs.define('ext/delete', ['_', '$', 'core/settings', 'core/entry', 'core/ev
.find('a').on('click', function (event) {
event.preventDefault();
$deleteAuth.hide();
requestDeletion(selectedHrefsStr);
}).end()
.appendTo('#navbar');
$img = $delete.find('img');
$deleteAuth = $(authTemplate).appendTo('body');
$deleteUser = $deleteAuth.find('#delete-auth-user');
$deletePassword = $deleteAuth.find('#delete-auth-password');
event.sub('selection', onSelection);
};

View file

@ -1,5 +1,5 @@
modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/ajax'], function (_, $, allsettings, resource, event, ajax) {
modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/server'], function (_, $, allsettings, resource, event, server) {
var settings = _.extend({
enabled: false,
@ -12,16 +12,12 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
downloadBtnTemplate = '<li id="download">' +
'<a href="#">' +
'<img src="' + resource.image('download') + '" alt="download"/>' +
'<span class="l10n-download">download</span>' +
'<span class="l10n-download"/>' +
'</a>' +
'</li>',
authTemplate = '<div id="download-auth">' +
'<input id="download-auth-user" type="text" value="" placeholder="user"/>' +
'<input id="download-auth-password" type="text" value="" placeholder="password"/>' +
'</div>',
selectedHrefsStr = '',
$download, $img, $downloadAuth, $downloadUser, $downloadPassword,
$download, $img,
failed = function () {
@ -36,24 +32,11 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
$download.removeClass('current');
$img.attr('src', resource.image('download'));
if (json) {
if (json.code === 0) {
setTimeout(function () { // wait here so the img above can be updated in time
if (json && json.code === 0) {
setTimeout(function () { // wait here so the img above can be updated in time
window.location = resource.api() + '?action=getarchive&id=' + json.id + '&as=h5ai-selection.' + settings.format;
}, 200);
} else {
if (json.code === 401) {
$downloadAuth
.css({
left: $download.offset().left,
top: $download.offset().top + $download.outerHeight()
})
.show();
$downloadUser.focus();
}
failed();
}
window.location = server.apiHref + '?action=getarchive&id=' + json.id + '&as=h5ai-selection.' + settings.format;
}, 200);
} else {
failed();
}
@ -63,12 +46,12 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
$download.addClass('current');
$img.attr('src', resource.image('loading.gif', true));
ajax.getArchive({
server.request({
action: 'archive',
execution: settings.execution,
format: settings.format,
hrefs: hrefsStr,
user: $downloadUser.val(),
password: $downloadPassword.val()
hrefs: hrefsStr
}, handleResponse);
},
@ -83,13 +66,12 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
$download.appendTo('#navbar').show();
} else {
$download.hide();
$downloadAuth.hide();
}
},
init = function () {
if (!settings.enabled) {
if (!settings.enabled || !server.apiHref) {
return;
}
@ -97,16 +79,11 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
.find('a').on('click', function (event) {
event.preventDefault();
$downloadAuth.hide();
requestArchive(selectedHrefsStr);
}).end()
.appendTo('#navbar');
$img = $download.find('img');
$downloadAuth = $(authTemplate).appendTo('body');
$downloadUser = $downloadAuth.find('#download-auth-user');
$downloadPassword = $downloadAuth.find('#download-auth-password');
event.sub('selection', onSelection);
};

View file

@ -1,5 +1,5 @@
modulejs.define('model/entry', ['_', 'core/types', 'core/ajax', 'core/event', 'core/settings'], function (_, types, ajax, event, settings) {
modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/settings'], function ($, _, types, event, settings) {
var doc = document,
domain = doc.domain,
@ -93,9 +93,30 @@ modulejs.define('model/entry', ['_', 'core/types', 'core/ajax', 'core/event', 'c
},
reContentType = /^text\/html;h5ai=/,
getStatus = function (href, withContent, callback) {
$.ajax({
url: href,
type: withContent ? 'GET' : 'HEAD',
complete: function (xhr) {
var res = {
status: xhr.status,
content: xhr.responseText
};
if (xhr.status === 200 && reContentType.test(xhr.getResponseHeader('Content-Type'))) {
res.status = 'h5ai';
}
callback(res);
}
});
},
ajaxRequest = function (self, parser, callback) {
ajax.getStatus(self.absHref, parser, function (response) {
getStatus(self.absHref, parser, function (response) {
self.status = response.status;
if (parser && response.status === 'h5ai') {

View file

@ -1,5 +1,5 @@
modulejs.define('parser/apache-autoindex', ['_', '$', 'core/mode', 'core/settings', 'core/format', 'model/entry'], function (_, $, mode, settings, format, Entry) {
modulejs.define('parser/apache-autoindex', ['_', '$', 'core/settings', 'core/format', 'model/entry'], function (_, $, settings, format, Entry) {
var parseTableRow = function (absHref, tr) {
@ -35,11 +35,6 @@ modulejs.define('parser/apache-autoindex', ['_', '$', 'core/mode', 'core/setting
return parseTable(absHref, $id.find('table'));
};
mode.id = 'aai';
mode.dataType = 'apache-autoindex';
mode.serverName = 'apache';
mode.serverVersion = null;
return {
dataType: 'apache-autoindex',
parse: parse

View file

@ -1,12 +1,8 @@
modulejs.define('parser/generic-json', ['_', '$', 'core/mode', 'core/settings', 'model/entry'], function (_, $, mode, settings, Entry) {
modulejs.define('parser/generic-json', ['_', '$', 'core/settings', 'model/entry'], function (_, $, settings, Entry) {
var parseJson = function (absHref, json) {
mode.id = json.id;
mode.serverName = json.serverName;
mode.serverVersion = json.serverVersion;
if (!settings.custom) {
settings.custom = {};
}
@ -40,8 +36,6 @@ modulejs.define('parser/generic-json', ['_', '$', 'core/mode', 'core/settings',
return parseJsonStr(absHref, $id.text());
};
mode.dataType = 'generic-json';
return {
dataType: 'generic-json',
parse: parse

View file

@ -1,137 +0,0 @@
/*
* taken from here:
* http://www.webtoolkit.info/javascript-base64.html
* with minor modifications
*/
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
return Base64._utf8_decode(output);
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

View file

@ -12,7 +12,6 @@
// @include "lib/modulejs-*.js"
// @include "lib/moment-*.js"
// @include "lib/json2-*.js"
// @include "lib/base64.js"
// @include "lib/spin-*.js"
// app
@ -46,7 +45,6 @@
// so they have to be wrapped to not be handled as constructors.
modulejs.define('config', config);
modulejs.define('amplify', amplify);
modulejs.define('base64', Base64);
modulejs.define('$', function () { return jQuery; });
modulejs.define('modernizr', Modernizr);
modulejs.define('moment', function () { return moment; });
@ -72,19 +70,17 @@
loadCommentedJson(appHref + 'conf/types.json', function (types) {
loadCommentedJson(appHref + 'conf/langs.json', function (langs) {
var config = {
options: options,
types: types,
langs: langs,
server: {
backend: backend,
apiHref: null,
name: 'apache',
version: null
}
};
run(config);
run({
options: options,
types: types,
langs: langs,
server: {
backend: backend,
apiHref: null,
name: 'apache',
version: null
}
});
});
});
});

View file

@ -146,7 +146,7 @@ else if ($action === "upload") {
$upload_dir = $APP->get_abs_path($href);
$code = $APP->get_http_code($href);
json_fail(5, "upload dir no h5ai folder or ignored", $code !== "h5ai" || $APP->is_ignored($upload_dir));
json_fail(5, "upload dir no h5ai folder or ignored", $code !== App::$MAGIC_SEQUENCE || $APP->is_ignored($upload_dir));
$dest = $upload_dir . "/" . utf8_encode($userfile["name"]);
@ -173,7 +173,7 @@ else if ($action === "delete") {
$code = $APP->get_http_code($d);
if ($code == "h5ai" && !$APP->is_ignored($n)) {
if ($code == App::$MAGIC_SEQUENCE && !$APP->is_ignored($n)) {
$abs_path = $APP->get_abs_path($href);
@ -183,7 +183,7 @@ else if ($action === "delete") {
}
}
if ($errors->size) {
if (count($errors)) {
json_fail(2, "deletion failed for some");
} else {
json_exit();
@ -202,7 +202,7 @@ else if ($action === "rename") {
$code = $APP->get_http_code($d);
if ($code == "h5ai" && !$APP->is_ignored($n)) {
if ($code == App::$MAGIC_SEQUENCE && !$APP->is_ignored($n)) {
$abs_path = $APP->get_abs_path($href);
$folder = normalize_path(dirname($abs_path));

View file

@ -169,9 +169,6 @@ class App {
$footer = $this->fileExists($footer ? $this->abs_path . "/" . $footer : null) ? $footer : null;
$json = array(
"id" => "php",
"serverName" => strtolower(preg_replace("/\\/.*$/", "", getenv("SERVER_SOFTWARE"))),
"serverVersion" => strtolower(preg_replace("/^.*\\//", "", preg_replace("/\\s.*$/", "", getenv("SERVER_SOFTWARE")))),
"customHeader" => $header,
"customFooter" => $footer,
"entries" => $entries

View file

@ -1,6 +1,6 @@
<?php
function json_exit($obj) {
function json_exit($obj = array()) {
$obj["code"] = 0;
echo json_encode($obj);