Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F256886
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
51 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/file_api.php b/lib/file_api.php
index 03ace94..b0e8131 100644
--- a/lib/file_api.php
+++ b/lib/file_api.php
@@ -1,362 +1,366 @@
<?php
class file_api
{
private $app_name = 'Kolab File API';
private $api;
private $config = array(
'date_format' => 'Y-m-d H:i',
'language' => 'en_US',
);
const ERROR_CODE = 500;
public function __construct()
{
}
/**
* Initialise backend class
*/
protected function api_init()
{
if ($this->api) {
return;
}
// @TODO: config
$driver = 'kolab';
$class = $driver . '_file_storage';
require_once $driver . '/' . $class . '.php';
$this->api = new $class;
}
/**
* Process the request and dispatch it to the requested service
*/
public function run()
{
- $request = $_GET['method'];
+ $request = strtolower($_GET['method']);
// Check the session, authenticate the user
if (!$this->session_validate()) {
@session_destroy();
if ($request == 'authenticate') {
session_start();
if ($username = $this->authenticate()) {
$_SESSION['user'] = $username;
$_SESSION['time'] = time();
$_SESSION['config'] = $this->config;
$this->output_success(array('token' => session_id()));
}
}
throw new Exception("Invalid session", 403);
}
// Call service method
$result = $this->request($request);
// Send success response, errors should be handled by driver class
// by throwing exceptions or sending output by itself
$this->output_success($result);
}
/**
* Session validation check
*/
private function session_validate()
{
$sess_id = rcube_utils::request_header('X-Session-Token') ?: $_REQUEST['token'];
if (empty($sess_id)) {
return false;
}
session_id($sess_id);
session_start();
if (empty($_SESSION['user'])) {
return false;
}
// Session timeout
// $timeout = $this->config->get('kolab_wap', 'session_timeout');
$timeout = 3600;
if ($timeout && $_SESSION['time'] && $_SESSION['time'] < time() - $timeout) {
return false;
}
// update session time
$_SESSION['time'] = time();
return true;
}
/**
* Authentication request handler (HTTP Auth)
*/
private function authenticate()
{
if (isset($_POST['username'])) {
$username = $_POST['username'];
$password = $_POST['password'];
}
else if (!empty($_SERVER['PHP_AUTH_USER'])) {
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
}
// when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule
else if (!isset($_SERVER['PHP_AUTH_USER'])) {
// "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..."
if (isset($_SERVER["REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REMOTE_USER"], 6));
}
else if (isset($_SERVER["REDIRECT_REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
}
else if (isset($_SERVER["Authorization"])) {
$basicAuthData = base64_decode(substr($_SERVER["Authorization"], 6));
}
else if (isset($_SERVER["HTTP_AUTHORIZATION"])) {
$basicAuthData = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6));
}
if (isset($basicAuthData) && !empty($basicAuthData)) {
list($username, $password) = explode(":", $basicAuthData);
}
}
if (!empty($username)) {
$this->api_init();
$result = $this->api->authenticate($username, $password);
}
if (empty($result)) {
/*
header('WWW-Authenticate: Basic realm="' . $this->app_name .'"');
header('HTTP/1.1 401 Unauthorized');
exit;
*/
throw new Exception("Invalid password or username", file_api::ERROR_CODE);
}
return $username;
}
/**
* Storage driver method caller
*/
private function request($request)
{
+ if ($request == 'ping') {
+ return array();
+ }
+
$this->api_init();
switch ($request) {
case 'file_list':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
$params = array('reverse' => !empty($_GET['reverse']) && rcube_utils::get_boolean($_GET['reverse']));
if (!empty($_GET['sort'])) {
$params['sort'] = strtolower($_GET['sort']);
}
if (!empty($_GET['search'])) {
$params['search'] = $_GET['search'];
if (!is_array($params['search'])) {
$params['search'] = array('name' => $params['search']);
}
}
return $this->api->file_list($_GET['folder'], $params);
case 'file_create':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
$uploads = $this->upload();
$result = array();
foreach ($uploads as $file) {
$this->api->file_create($_GET['folder'], $file['name'], $file);
unset($file['path']);
$result[$file['name']] = array(
'type' => $file['type'],
'size' => $file['size'],
);
}
return $result;
case 'file_delete':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
if (!isset($_GET['file']) || $_GET['file'] === '') {
throw new Exception("Missing file name", file_api::ERROR_CODE);
}
return $this->api->file_delete($_GET['folder'], $_GET['file']);
case 'file_get':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
header("HTTP/1.0 ".file_api::ERROR_CODE." Missing folder name");
}
if (!isset($_GET['file']) || $_GET['file'] === '') {
header("HTTP/1.0 ".file_api::ERROR_CODE." Missing file name");
}
try {
$this->api->file_get($_GET['folder'], $_GET['file']);
}
catch (Exception $e) {
header("HTTP/1.0 ".file_api::ERROR_CODE." " . $e->getMessage());
}
exit;
case 'file_rename':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
if (!isset($_GET['file']) || $_GET['file'] === '') {
throw new Exception("Missing file name", file_api::ERROR_CODE);
}
if (!isset($_GET['new']) || $_GET['new'] === '') {
throw new Exception("Missing new file name", file_api::ERROR_CODE);
}
if ($_GET['new'] === $_GET['file']) {
throw new Exception("Old and new file name is the same", file_api::ERROR_CODE);
}
return $this->api->file_rename($_GET['folder'], $_GET['file'], $_GET['new']);
case 'folder_create':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
return $this->api->folder_create($_GET['folder']);
case 'folder_delete':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing folder name", file_api::ERROR_CODE);
}
return $this->api->folder_delete($_GET['folder']);
case 'folder_rename':
if (!isset($_GET['folder']) || $_GET['folder'] === '') {
throw new Exception("Missing source folder name", file_api::ERROR_CODE);
}
if (!isset($_GET['new']) || $_GET['new'] === '') {
throw new Exception("Missing destination folder name", file_api::ERROR_CODE);
}
if ($_GET['new'] === $_GET['folder']) {
return;
}
return $this->api->folder_rename($_GET['folder'], $_GET['new']);
case 'folder_list':
return $this->api->folder_list();
case 'quit':
@session_destroy();
return array();
case 'configure':
foreach (array_keys($this->config) as $name) {
if (isset($_GET[$name])) {
$this->config[$name] = $_GET[$name];
}
}
$_SESSION['config'] = $this->config;
return $this->config;
}
if ($request) {
throw new Exception("Unknown method", 501);
}
}
/**
* File uploads handler
*/
protected function upload()
{
$files = array();
if (is_array($_FILES['file']['tmp_name'])) {
foreach ($_FILES['file']['tmp_name'] as $i => $filepath) {
if ($err = $_FILES['file']['error'][$i]) {
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
throw new Exception("Maximum file size exceeded", file_api::ERROR_CODE);
}
throw new Exception("File upload failed", file_api::ERROR_CODE);
}
$files[] = array(
'path' => $filepath,
'name' => $_FILES['file']['name'][$i],
'size' => filesize($filepath),
'type' => rcube_mime::file_content_type($filepath, $_FILES['file']['name'][$i], $_FILES['file']['type']),
);
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
throw new Exception("File upload failed", file_api::ERROR_CODE);
}
return $files;
}
/**
* Send success response
*
* @param mixed $data Data
*/
public function output_success($data)
{
if (!is_array($data)) {
$data = array();
}
$this->output_send(array('status' => 'OK', 'result' => $data));
}
/**
* Send error response
*
* @param mixed $data Data
*/
public function output_error($errdata, $code = null)
{
if (is_string($errdata)) {
$errdata = array('reason' => $errdata);
}
if (!$code) {
$code = file_api::ERROR_CODE;
}
$this->output_send(array('status' => 'ERROR', 'code' => $code) + $errdata);
}
/**
* Send response
*
* @param mixed $data Data
*/
protected function output_send($data)
{
// Send response
header("Content-Type: application/json; charset=utf-8");
echo json_encode($data);
exit;
}
}
diff --git a/public_html/js/files_api.js b/public_html/js/files_api.js
new file mode 100644
index 0000000..1d3b5eb
--- /dev/null
+++ b/public_html/js/files_api.js
@@ -0,0 +1,328 @@
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab File API |
+ | |
+ | Copyright (C) 2012-2013, Kolab Systems AG |
+ | |
+ | This program is free software: you can redistribute it and/or modify |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 of the License, or |
+ | (at your option) any later version. |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+function files_api()
+{
+ var ref = this;
+
+ // default config
+ this.translations = {};
+ this.env = {
+ url: 'api/',
+ directory_separator: '/'
+ };
+
+
+ /*********************************************************/
+ /********* Basic utilities *********/
+ /*********************************************************/
+
+ // set environment variable(s)
+ this.set_env = function(p, value)
+ {
+ if (p != null && typeof p === 'object' && !value)
+ for (var n in p)
+ this.env[n] = p[n];
+ else
+ this.env[p] = value;
+ };
+
+ // add a localized label(s) to the client environment
+ this.tdef = function(p, value)
+ {
+ if (typeof p == 'string')
+ this.translations[p] = value;
+ else if (typeof p == 'object')
+ $.extend(this.translations, p);
+ };
+
+ // return a localized string
+ this.t = function(label)
+ {
+ if (this.translations[label])
+ return this.translations[label];
+ else
+ return label;
+ };
+
+ // print a message into browser console
+ this.log = function(msg)
+ {
+ if (window.console && console.log)
+ console.log(msg);
+ };
+
+ /********************************************************/
+ /********* Remote request methods *********/
+ /********************************************************/
+
+ // send a http POST request to the API service
+ this.post = function(action, postdata, func)
+ {
+ var url = this.env.url + action, ref = this;
+
+ if (!func) func = 'response';
+
+ this.set_request_time();
+
+ return $.ajax({
+ type: 'POST', url: url, data: postdata, dataType: 'json',
+ contentType: 'application/json; charset=utf-8',
+ success: function(response) { ref[func](response); },
+ error: function(o, status, err) { ref.http_error(o, status, err); },
+ cache: false,
+ beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); }
+ });
+ };
+
+ // send a http GET request to the API service
+ this.get = function(action, data, func)
+ {
+ var url = this.env.url;
+
+ if (!func) func = 'response';
+
+ this.set_request_time();
+ data.method = action;
+
+ return $.ajax({
+ type: 'GET', url: url, data: data,
+ success: function(response) { ref[func](response); },
+ error: function(o, status, err) { ref.http_error(o, status, err); },
+ cache: false,
+ beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); }
+ });
+ };
+
+ // handle HTTP request errors
+ this.http_error = function(request, status, err)
+ {
+ var errmsg = request.statusText;
+
+ this.set_busy(false);
+ request.abort();
+
+ if (request.status && errmsg)
+ this.display_message(this.t('servererror') + ' (' + errmsg + ')', 'error');
+ };
+
+ this.response = function(response)
+ {
+ this.update_request_time();
+ this.set_busy(false);
+
+ return this.response_parse(response);
+ };
+
+ this.response_parse = function(response)
+ {
+ if (!response || response.status != 'OK') {
+ // Logout on invalid-session error
+ if (response && response.code == 403)
+ this.logout(response);
+ else
+ this.display_message(response && response.reason ? response.reason : this.t('servererror'), 'error');
+
+ return false;
+ }
+
+ return true;
+ };
+
+
+ /*********************************************************/
+ /********* Utilities *********/
+ /*********************************************************/
+
+ // Called on "session expired" session
+ this.logout = function(response) {};
+
+ // set state
+ this.set_busy = function(a, message) {};
+
+ // displays error message
+ this.display_message = function(label) {};
+
+ // called when a request timed out
+ this.request_timed_out = function() {};
+
+ // called on start of the request
+ this.set_request_time = function() {};
+
+ // called on request response
+ this.update_request_time = function() {};
+
+
+ /*********************************************************/
+ /********* Helpers *********/
+ /*********************************************************/
+
+ // compose a valid url with the given parameters
+ this.url = function(action, query)
+ {
+ var k, param = {},
+ querystring = typeof query === 'string' ? '&' + query : '';
+
+ if (typeof action !== 'string')
+ query = action;
+ else if (!query || typeof query !== 'object')
+ query = {};
+
+ // overwrite task name
+ if (action)
+ query.method = action;
+
+ // remove undefined values
+ for (k in query) {
+ if (query[k] !== undefined && query[k] !== null)
+ param[k] = query[k];
+ }
+
+ return '?' + $.param(param) + querystring;
+ };
+
+ // Folder list parser, converts it into structure
+ this.folder_list_parse = function(list)
+ {
+ var i, n, items, items_len, f, tmp, folder, num = 1,
+ len = list.length, folders = {};
+
+ for (i=0; i<len; i++) {
+ folder = list[i];
+ items = folder.split(this.env.directory_separator);
+ items_len = items.length;
+
+ for (n=0; n<items_len-1; n++) {
+ tmp = items.slice(0,n+1);
+ f = tmp.join(this.env.directory_separator);
+ if (!folders[f])
+ folders[f] = {name: tmp.pop(), depth: n, id: 'f'+num++, virtual: 1};
+ }
+
+ folders[folder] = {name: items.pop(), depth: items_len-1, id: 'f'+num++};
+ }
+
+ return folders;
+ };
+
+ // folder structure presentation (structure icons)
+ this.folder_list_tree = function(folders)
+ {
+ var i, n, diff, tree = [], folder;
+
+ for (i in folders) {
+ items = i.split(this.env.directory_separator);
+ items_len = items.length;
+
+ // skip root
+ if (items_len < 2) {
+ tree = [];
+ continue;
+ }
+
+ folders[i].tree = [1];
+
+ for (n=0; n<tree.length; n++) {
+ folder = tree[n];
+ diff = folders[folder].depth - (items_len - 1);
+ if (diff >= 0)
+ folders[folder].tree[diff] = folders[folder].tree[diff] ? folders[folder].tree[diff] + 2 : 2;
+ }
+
+ tree.push(i);
+ }
+
+ for (i in folders) {
+ if (tree = folders[i].tree) {
+ var html = '', divs = [];
+ for (n=0; n<folders[i].depth; n++) {
+ if (tree[n] > 2)
+ divs.push({'class': 'l3', width: 15});
+ else if (tree[n] > 1)
+ divs.push({'class': 'l2', width: 15});
+ else if (tree[n] > 0)
+ divs.push({'class': 'l1', width: 15});
+ // separator
+ else if (divs.length && !divs[divs.length-1]['class'])
+ divs[divs.length-1].width += 15;
+ else
+ divs.push({'class': null, width: 15});
+ }
+
+ for (n=divs.length-1; n>=0; n--) {
+ if (divs[n]['class'])
+ html += '<span class="tree '+divs[n]['class']+'" />';
+ else
+ html += '<span style="width:'+divs[n].width+'px" />';
+ }
+
+ if (html)
+ $('#' + folders[i].id + ' span.branch').html(html);
+ }
+ }
+ };
+
+ // convert content-type string into class name
+ this.file_type_class = function(type)
+ {
+ if (!type)
+ return '';
+
+ type = type.replace(/[^a-z0-9]/g, '_');
+
+ return type;
+ };
+
+ // convert bytes into number with size unit
+ this.file_size = function(size)
+ {
+ if (size >= 1073741824)
+ return parseFloat(size/1073741824).toFixed(2) + ' GB';
+ if (size >= 1048576)
+ return parseFloat(size/1048576).toFixed(2) + ' MB';
+ if (size >= 1024)
+ return parseInt(size/1024) + ' kB';
+
+ return parseInt(size || 0)+ ' B';
+ };
+};
+
+// Add escape() method to RegExp object
+// http://dev.rubyonrails.org/changeset/7271
+RegExp.escape = function(str)
+{
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
+// make a string URL safe (and compatible with PHP's rawurlencode())
+function urlencode(str)
+{
+ if (window.encodeURIComponent)
+ return encodeURIComponent(str).replace('*', '%2A');
+
+ return escape(str)
+ .replace('+', '%2B')
+ .replace('*', '%2A')
+ .replace('/', '%2F')
+ .replace('@', '%40');
+};
diff --git a/public_html/js/app.js b/public_html/js/files_ui.js
similarity index 74%
rename from public_html/js/app.js
rename to public_html/js/files_ui.js
index 30d1ea8..131905f 100644
--- a/public_html/js/app.js
+++ b/public_html/js/files_ui.js
@@ -1,1000 +1,769 @@
/*
+--------------------------------------------------------------------------+
| This file is part of the Kolab File API |
| |
- | Copyright (C) 2011-2012, Kolab Systems AG |
+ | Copyright (C) 2012-2013, Kolab Systems AG |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
-function file_ui()
+function files_ui()
{
var ref = this;
- this.translations = {};
this.request_timeout = 300;
this.message_time = 3000;
this.events = {};
this.env = {
+ url: 'api/',
sort_column: 'name',
sort_reverse: 0,
directory_separator: '/'
};
// set jQuery ajax options
$.ajaxSetup({
cache: false,
error: function(request, status, err) { ref.http_error(request, status, err); },
beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); }
});
/*********************************************************/
/********* basic utilities *********/
/*********************************************************/
// set environment variable(s)
this.set_env = function(p, value)
{
if (p != null && typeof p === 'object' && !value)
for (var n in p)
this.env[n] = p[n];
else
this.env[p] = value;
};
- // add a localized label(s) to the client environment
- this.tdef = function(p, value)
- {
- if (typeof p == 'string')
- this.translations[p] = value;
- else if (typeof p == 'object')
- $.extend(this.translations, p);
- };
-
- // return a localized string
- this.t = function(label)
- {
- if (this.translations[label])
- return this.translations[label];
- else
- return label;
- };
-
- // print a message into browser console
- this.log = function(msg)
- {
- if (window.console && console.log)
- console.log(msg);
- };
-
// execute a specific command on the web client
this.command = function(command, props, obj)
{
if (obj && obj.blur)
obj.blur();
if (this.busy)
return false;
this.set_busy(true, 'loading');
var ret = undefined,
func = command.replace(/[^a-z]/g, '_'),
task = command.replace(/\.[a-z-_]+$/g, '');
if (this[func] && typeof this[func] === 'function') {
ret = this[func](props);
}
else {
this.http_post(command, props);
}
// update menu state
// $('li', $('#navigation')).removeClass('active');
// $('li.'+task, ('#navigation')).addClass('active');
return ret === false ? false : obj ? false : true;
};
this.set_busy = function(a, message)
{
if (a && this.busy)
return;
if (a && message) {
var msg = this.t(message);
if (msg == message)
msg = 'Loading...';
this.display_message(msg, 'loading');
}
else if (!a) {
this.hide_message('loading');
}
this.busy = a;
// if (this.gui_objects.editform)
// this.lock_form(this.gui_objects.editform, a);
// clear pending timer
if (this.request_timer)
clearTimeout(this.request_timer);
// set timer for requests
if (a && this.request_timeout)
this.request_timer = window.setTimeout(function() { ref.request_timed_out(); }, this.request_timeout * 1000);
};
// called when a request timed out
this.request_timed_out = function()
{
this.set_busy(false);
this.display_message('Request timed out!', 'error');
};
// Add variable to GET string, replace old value if exists
this.add_url = function(url, name, value)
{
value = urlencode(value);
if (/(\?.*)$/.test(url)) {
var urldata = RegExp.$1,
datax = RegExp('((\\?|&)'+RegExp.escape(name)+'=[^&]*)');
if (datax.test(urldata))
urldata = urldata.replace(datax, RegExp.$2 + name + '=' + value);
else
urldata += '&' + name + '=' + value
return url.replace(/(\?.*)$/, urldata);
}
- else
- return url + '?' + name + '=' + value;
+
+ return url + '?' + name + '=' + value;
};
this.trigger_event = function(event, data)
{
if (this.events[event])
for (var i in this.events[event])
this.events[event][i](data);
};
this.add_event_listener = function(event, func)
{
if (!this.events[event])
this.events[event] = [];
this.events[event].push(func);
};
/*********************************************************/
/********* GUI functionality *********/
/*********************************************************/
// write to the document/window title
this.set_pagetitle = function(title)
{
if (title && document.title)
document.title = title;
};
// display a system message (types: loading, notice, error)
this.display_message = function(msg, type, timeout)
{
var obj, ref = this;
if (!type)
type = 'notice';
if (msg)
msg = this.t(msg);
if (type == 'loading') {
timeout = this.request_timeout * 1000;
if (!msg)
msg = this.t('loading');
}
else if (!timeout)
timeout = this.message_time * (type == 'error' || type == 'warning' ? 2 : 1);
obj = $('<div>');
if (type != 'loading') {
msg = '<div><span>' + msg + '</span></div>';
obj.addClass(type).click(function() { return ref.hide_message(); });
}
if (timeout > 0)
window.setTimeout(function() { ref.hide_message(type, type != 'loading'); }, timeout);
obj.attr('id', type == 'loading' ? 'loading' : 'message')
.appendTo('body').html(msg).show();
};
// make a message to disapear
this.hide_message = function(type, fade)
{
if (type == 'loading')
$('#loading').remove();
else
$('#message').fadeOut('normal', function() { $(this).remove(); });
};
this.set_watermark = function(id)
{
if (this.env.watermark)
$('#'+id).html(this.env.watermark);
};
/********************************************************/
/********* Remote request methods *********/
/********************************************************/
- // compose a valid url with the given parameters
- this.url = function(action, query)
- {
- var k, param = {},
- querystring = typeof query === 'string' ? '&' + query : '';
-
- if (typeof action !== 'string')
- query = action;
- else if (!query || typeof query !== 'object')
- query = {};
-
- // overwrite task name
- if (action)
- query.method = action;
-
- // remove undefined values
- for (k in query) {
- if (query[k] !== undefined && query[k] !== null)
- param[k] = query[k];
- }
-
- return '?' + $.param(param) + querystring;
- };
-
// send a http POST request to the server
this.http_post = function(action, postdata)
{
var url = this.url(action);
if (postdata && typeof postdata === 'object')
postdata.remote = 1;
else {
if (!postdata)
postdata = '';
postdata += '&remote=1';
}
this.set_request_time();
return $.ajax({
type: 'POST', url: url, data: postdata, dataType: 'json',
success: function(response) { ui.http_response(response); },
error: function(o, status, err) { ui.http_error(o, status, err); }
});
};
- // send a http POST request to the API service
- this.api_post = function(action, postdata, func)
- {
- var url = 'api/' + action;
-
- if (!func) func = 'api_response';
-
- this.set_request_time();
-
- return $.ajax({
- type: 'POST', url: url, data: postdata, dataType: 'json',
- contentType: 'application/json; charset=utf-8',
- success: function(response) { ui[func](response); },
- error: function(o, status, err) { ui.http_error(o, status, err); }
- });
- };
-
- // send a http GET request to the API service
- this.api_get = function(action, data, func)
- {
- var url = 'api/';
-
- if (!func) func = 'api_response';
-
- this.set_request_time();
- data.method = action;
-
- return $.ajax({
- type: 'GET', url: url, data: data,
- success: function(response) { ui[func](response); },
- error: function(o, status, err) { ui.http_error(o, status, err); }
- });
- };
-
// handle HTTP response
this.http_response = function(response)
{
var i;
if (!response)
return;
// set env vars
if (response.env)
this.set_env(response.env);
// we have translation labels to add
if (typeof response.labels === 'object')
this.tdef(response.labels);
// HTML page elements
if (response.objects)
for (i in response.objects)
$('#'+i).html(response.objects[i]);
this.update_request_time();
this.set_busy(false);
// if we get javascript code from server -> execute it
if (response.exec)
eval(response.exec);
this.trigger_event('http-response', response);
};
// handle HTTP request errors
this.http_error = function(request, status, err)
{
var errmsg = request.statusText;
this.set_busy(false);
request.abort();
if (request.status && errmsg)
this.display_message(this.t('servererror') + ' (' + errmsg + ')', 'error');
};
- this.api_response = function(response)
- {
- this.update_request_time();
- this.set_busy(false);
-
- return this.api_response_parse(response);
- };
-
- this.api_response_parse = function(response)
- {
- if (!response || response.status != 'OK') {
- // Logout on invalid-session error
- if (response && response.code == 403)
- this.main_logout();
- else
- this.display_message(response && response.reason ? response.reason : this.t('servererror'), 'error');
-
- return false;
- }
-
- return true;
- };
-
/********************************************************/
/********* Helper methods *********/
/********************************************************/
// disable/enable all fields of a form
this.lock_form = function(form, lock)
{
if (!form || !form.elements)
return;
var n, len, elm;
if (lock)
this.disabled_form_elements = [];
for (n=0, len=form.elements.length; n<len; n++) {
elm = form.elements[n];
if (elm.type == 'hidden')
continue;
// remember which elem was disabled before lock
if (lock && elm.disabled)
this.disabled_form_elements.push(elm);
// check this.disabled_form_elements before inArray() as a workaround for FF5 bug
// http://bugs.jquery.com/ticket/9873
else if (lock || (this.disabled_form_elements && $.inArray(elm, this.disabled_form_elements)<0))
elm.disabled = lock;
}
};
this.set_request_time = function()
{
this.env.request_time = (new Date()).getTime();
};
// Update request time element
this.update_request_time = function()
{
if (this.env.request_time) {
var t = ((new Date()).getTime() - this.env.request_time)/1000,
el = $('#reqtime');
el.text(el.text().replace(/[0-9.,]+/, t));
}
};
// position and display popup
this.popup_show = function(e, popup)
{
var popup = $(popup),
pos = this.mouse_pos(e),
win = $(window),
w = popup.width(),
h = popup.height(),
left = pos.left - w,
top = pos.top;
if (top + h > win.height())
top -= h;
if (left + w > win.width())
left -= w;
popup.css({left: left + 'px', top: top + 'px'})
.click(function(e) { e.stopPropagation(); $(this).hide(); }).show();
e.stopPropagation();
};
// Return absolute mouse position of an event
this.mouse_pos = function(e)
{
if (!e) e = window.event;
var mX = (e.pageX) ? e.pageX : e.clientX,
mY = (e.pageY) ? e.pageY : e.clientY;
if (document.body && document.all) {
mX += document.body.scrollLeft;
mY += document.body.scrollTop;
}
if (e._offset) {
mX += e._offset.left;
mY += e._offset.top;
}
return { left:mX, top:mY };
};
this.serialize_form = function(id)
{
var i, v, json = {},
form = $(id),
query = form.serializeArray();
for (i in query)
json[query[i].name] = query[i].value;
// serializeArray() doesn't work properly for multi-select
$('select[multiple="multiple"]', form).each(function() {
var name = this.name;
json[name] = [];
$(':selected', this).each(function() {
json[name].push(this.value);
});
});
return json;
};
/*********************************************************/
/********* Commands *********/
/*********************************************************/
this.main_logout = function(params)
{
location.href = '?task=main&action=logout' + (params ? '&' + $.param(params) : '');
return false;
};
// folder list request
this.folder_list = function()
{
this.set_busy(true, 'loading');
- this.api_get('folder_list', {}, 'folder_list_response');
+ this.get('folder_list', {}, 'folder_list_response');
};
// folder list response handler
this.folder_list_response = function(response)
{
- if (!this.api_response(response))
+ if (!this.response(response))
return;
var elem = $('#folderlist'), table = $('table', elem);
this.env.folders = this.folder_list_parse(response.result);
table.empty();
$.each(this.env.folders, function(i, f) {
var row = $('<tr><td><span class="branch"></span><span class="name"></span></td></tr>'),
span = $('span.name', row);
span.text(f.name);
row.attr('id', f.id);
if (f.depth)
$('span.branch', row).width(15 * f.depth);
if (f.virtual)
row.addClass('virtual');
else
span.click(function() { ui.folder_select(i); });
if (i == ui.env.folder)
row.addClass('selected');
table.append(row);
});
// add tree icons
- this.folder_list_tree();
+ this.folder_list_tree(this.env.folders);
};
this.folder_select = function(folder)
{
this.env.search = null;
this.file_search_stop();
this.command('file.list', folder);
};
// folder create request
this.folder_create = function(folder)
{
this.set_busy(true, 'saving');
- this.api_get('folder_create', {folder: folder}, 'folder_create_response');
+ this.get('folder_create', {folder: folder}, 'folder_create_response');
};
// folder create response handler
this.folder_create_response = function(response)
{
- if (!this.api_response(response))
+ if (!this.response(response))
return;
this.folder_list();
};
// file list request
this.file_list = function(folder, params)
{
if (!params)
params = {};
params.folder = folder ? folder : this.env.folder
if (params.sort == undefined)
params.sort = this.env.sort_col;
if (params.reverse == undefined)
params.reverse = this.env.sort_reverse;
if (params.search == undefined)
params.search = this.env.search;
this.env.folder = params.folder;
this.env.sort_col = params.sort;
this.env.sort_reverse = params.reverse;
this.set_busy(true, 'loading');
- this.api_get('file_list', params, 'file_list_response');
+ this.get('file_list', params, 'file_list_response');
var list = $('#folderlist');
$('tr.selected', list).removeClass('selected');
$('#' + this.env.folders[params.folder].id, list).addClass('selected');
};
// file list response handler
this.file_list_response = function(response)
{
- if (!this.api_response(response))
+ if (!this.response(response))
return;
var table = $('#filelist');
$('tbody', table).empty();
$.each(response.result, function(key, data) {
var row = $('<tr><td class="filename"></td>'
+' <td class="filemtime"></td><td class="filesize"></td></tr>'),
link = $('<span></span>').text(key).click(function(e) { ui.file_menu(e, key); });
$('td.filename', row).addClass(ui.file_type_class(data.type)).append(link);
$('td.filemtime', row).text(data.mtime);
$('td.filesize', row).text(ui.file_size(data.size));
row.attr('data-file', urlencode(key));
table.append(row);
});
};
// file delete request
this.file_delete = function(file)
{
this.set_busy(true, 'deleting');
- this.api_get('file_delete', {folder: this.env.folder, file: file}, 'file_delete_response');
+ this.get('file_delete', {folder: this.env.folder, file: file}, 'file_delete_response');
};
// file delete response handler
this.file_delete_response = function(response)
{
- if (!this.api_response(response))
+ if (!this.response(response))
return;
this.file_list(this.env.folder);
};
// file rename request
this.file_rename = function(file, newname)
{
if (file === newname)
return;
this.set_busy(true, 'saving');
- this.api_get('file_rename', {folder: this.env.folder, file: file, 'new': newname}, 'file_rename_response');
+ this.get('file_rename', {folder: this.env.folder, file: file, 'new': newname}, 'file_rename_response');
};
// file delete response handler
this.file_rename_response = function(response)
{
- if (!this.api_response(response))
+ if (!this.response(response))
return;
this.file_list(this.env.folder);
};
this.file_menu = function(e, file)
{
var menu = $('#file-menu');
$('li.file-open > a', menu)
- .attr({target: '_blank', href: 'api/' + ui.url('file_get', {folder: this.env.folder, token: this.env.token, file: file})});
+ .attr({target: '_blank', href: 'api/' + this.url('file_get', {folder: this.env.folder, token: this.env.token, file: file})});
$('li.file-delete > a', menu).off('click').click(function() { ui.file_delete(file); });
$('li.file-rename > a', menu).off('click').click(function() { ui.file_rename_start(file); });
this.popup_show(e, menu);
};
this.file_rename_start = function(file)
{
var list = $('#filelist'),
tr = $('tr[data-file="' + urlencode(file) + '"]', list),
td = $('td.filename', tr),
input = $('<input>').attr({type: 'text', name: 'filename', 'class': 'filerename'})
.val(file).data('filename', file)
.click(function(e) { e.stopPropagation(); })
.keydown(function(e) {
switch (e.which) {
case 27: // ESC
ui.file_rename_stop();
break;
case 13: // Enter
var elem = $(this), newname = elem.val();
ui.file_rename(elem.data('filename'), newname);
elem.parent().text(newname);
break;
}
});
$('span', td).text('').append(input);
input.focus();
};
this.file_rename_stop = function()
{
$('input.filerename').each(function() {
var elem = $(this);
elem.parent().text(elem.data('filename'));
});
};
// file upload request
this.file_upload = function()
{
var form = $('#uploadform'),
field = $('input[type=file]', form).get(0),
files = field.files ? field.files.length : field.value ? 1 : 0;
if (files) {
// submit form and read server response
this.async_upload_form(form, 'file_create', function() {
var doc, response;
try {
doc = this.contentDocument ? this.contentDocument : this.contentWindow.document;
response = doc.body.innerHTML;
// response may be wrapped in <pre> tag
if (response.slice(0, 5).toLowerCase() == '<pre>' && response.slice(-6).toLowerCase() == '</pre>') {
response = doc.body.firstChild.firstChild.nodeValue;
}
response = eval('(' + response + ')');
} catch (err) {
response = {status: 'ERROR'};
}
- if (ui.api_response_parse(response))
+ if (ui.response_parse(response))
ui.file_list(ui.env.folder);
});
}
};
// post the given form to a hidden iframe
this.async_upload_form = function(form, action, onload)
{
var ts = new Date().getTime(),
frame_name = 'fileupload'+ts;
/*
// upload progress support
if (this.env.upload_progress_name) {
var fname = this.env.upload_progress_name,
field = $('input[name='+fname+']', form);
if (!field.length) {
field = $('<input>').attr({type: 'hidden', name: fname});
field.prependTo(form);
}
field.val(ts);
}
*/
// have to do it this way for IE
// otherwise the form will be posted to a new window
if (document.all) {
var html = '<iframe id="'+frame_name+'" name="'+frame_name+'"'
+ ' src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
document.body.insertAdjacentHTML('BeforeEnd', html);
}
// for standards-compliant browsers
else
$('<iframe>')
.attr({name: frame_name, id: frame_name})
.css({border: 'none', width: 0, height: 0, visibility: 'hidden'})
.appendTo(document.body);
// handle upload errors, parsing iframe content in onload
$('#'+frame_name).bind('load', {ts:ts}, onload);
$(form).attr({
target: frame_name,
action: 'api/' + this.url(action, {folder: this.env.folder, token: this.env.token, uploadid:ts}),
method: 'POST'
}).attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data')
.submit();
};
// Display file search form
this.file_search_start = function()
{
var form = this.form_show('file-search');
$('input[name="name"]', form).val('').focus();
};
// Hide file search form
this.file_search_stop = function()
{
if (this.env.search)
this.file_list(null, {search: null});
this.form_hide('file-search');
this.env.search = null;
};
// Execute file search
this.file_search_submit = function()
{
var form = this.form_show('file-search'),
value = $('input[name="name"]', form).val();
if (value) {
this.env.search = {name: value};
this.file_list(null, {search: this.env.search});
}
else
this.file_search_stop();
};
// Display folder creation form
this.folder_create_start = function()
{
var form = this.form_show('folder-create');
$('input[name="name"]', form).val('').focus();
$('input[name="parent"]', form).prop('checked', this.env.folder);
};
// Hide folder creation form
this.folder_create_stop = function()
{
this.form_hide('folder-create');
};
// Submit folder creation form
this.folder_create_submit = function()
{
var folder = '', data = this.serialize_form('#folder-create-form');
if (!data.name)
return;
if (data.parent && this.env.folder)
folder = this.env.folder + this.env.directory_separator;
folder += data.name;
this.folder_create_stop();
this.command('folder_create', folder);
};
// Display folder creation form
this.form_show = function(name)
{
var form = $('#' + name + '-form');
$('#forms > form').hide();
form.show();
$('#taskcontent').css('top', form.height() + 20);
return form;
};
// Display folder creation form
this.form_hide = function(name)
{
var form = $('#' + name + '-form');
form.hide();
$('#taskcontent').css('top', 10);
};
-
- // Folder list parser, converts it into structure
- this.folder_list_parse = function(list)
- {
- var i, n, items, items_len, f, tmp, folder, num = 1,
- len = list.length, folders = {};
-
- for (i=0; i<len; i++) {
- folder = list[i];
- items = folder.split(this.env.directory_separator);
- items_len = items.length;
-
- for (n=0; n<items_len-1; n++) {
- tmp = items.slice(0,n+1);
- f = tmp.join(this.env.directory_separator);
- if (!folders[f])
- folders[f] = {name: tmp.pop(), depth: n, id: 'f'+num++, virtual: 1};
- }
-
- folders[folder] = {name: items.pop(), depth: items_len-1, id: 'f'+num++};
- }
-
- return folders;
- };
-
- // folder structure presentation (structure icons)
- this.folder_list_tree = function()
- {
- var i, n, diff, tree = [], folder, folders = this.env.folders;
-
- for (i in folders) {
- items = i.split(this.env.directory_separator);
- items_len = items.length;
-
- // skip root
- if (items_len < 2) {
- tree = [];
- continue;
- }
-
- folders[i].tree = [1];
-
- for (n=0; n<tree.length; n++) {
- folder = tree[n];
- diff = folders[folder].depth - (items_len - 1);
- if (diff >= 0)
- folders[folder].tree[diff] = folders[folder].tree[diff] ? folders[folder].tree[diff] + 2 : 2;
- }
-
- tree.push(i);
- }
-
- for (i in folders) {
- if (tree = folders[i].tree) {
- var html = '', divs = [];
- for (n=0; n<folders[i].depth; n++) {
- if (tree[n] > 2)
- divs.push({'class': 'l3', width: 15});
- else if (tree[n] > 1)
- divs.push({'class': 'l2', width: 15});
- else if (tree[n] > 0)
- divs.push({'class': 'l1', width: 15});
- // separator
- else if (divs.length && !divs[divs.length-1]['class'])
- divs[divs.length-1].width += 15;
- else
- divs.push({'class': null, width: 15});
- }
-
- for (n=divs.length-1; n>=0; n--) {
- if (divs[n]['class'])
- html += '<span class="tree '+divs[n]['class']+'" />';
- else
- html += '<span style="width:'+divs[n].width+'px" />';
- }
-
- if (html)
- $('#' + folders[i].id + ' span.branch').html(html);
- }
- }
- };
-
- // convert content-type string into class name
- this.file_type_class = function(type)
- {
- if (!type)
- return '';
-
- type = type.replace(/[^a-z0-9]/g, '_');
-
- return type;
- };
-
- // convert bytes into number with size unit
- this.file_size = function(size)
- {
- if (size >= 1073741824)
- return parseFloat(size/1073741824).toFixed(2) + ' GB';
- if (size >= 1048576)
- return parseFloat(size/1048576).toFixed(2) + ' MB';
- if (size >= 1024)
- return parseInt(size/1024) + ' kB';
-
- return parseInt(size || 0)+ ' B';
- };
-};
-
-// Add escape() method to RegExp object
-// http://dev.rubyonrails.org/changeset/7271
-RegExp.escape = function(str)
-{
- return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
-};
-
-// make a string URL safe (and compatible with PHP's rawurlencode())
-function urlencode(str)
-{
- if (window.encodeURIComponent)
- return encodeURIComponent(str).replace('*', '%2A');
-
- return escape(str)
- .replace('+', '%2B')
- .replace('*', '%2A')
- .replace('/', '%2F')
- .replace('@', '%40');
};
// Initialize application object (don't change var name!)
-var ui = new file_ui();
+var ui = $.extend(new files_api(), new files_ui());
// general click handler
$(document).click(function() {
$('.popup').hide();
ui.file_rename_stop();
});
diff --git a/public_html/skins/default/templates/login.html b/public_html/skins/default/templates/login.html
index d1f76b8..ef609ac 100644
--- a/public_html/skins/default/templates/login.html
+++ b/public_html/skins/default/templates/login.html
@@ -1,22 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{$pagetitle}</title>
<link rel="stylesheet" href="{$skin_path}style.css" />
<link rel="shortcut icon" type="image/png" href="{$skin_path}images/favicon.png" />
<script src="js/jquery.min.js"></script>
- <script src="js/app.js"></script>
+ <script src="js/files_api.js"></script>
+ <script src="js/files_ui.js"></script>
</head>
<body>
<div id="logo"></div>
<div id="topmenu"></div>
<div id="navigation"></div>
<div id="task_navigation"></div>
<div id="content">{$engine->login_form()}</div>
<div id="footer">
{include file="footer.html"}
</div>
{$script}
</body>
</html>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jun 10, 3:54 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
196942
Default Alt Text
(51 KB)
Attached To
Mode
R26 chwala
Attached
Detach File
Event Timeline
Log In to Comment