Page MenuHomePhorge

No OneTemporary

diff --git a/public_html/js/files_ui.js b/public_html/js/files_ui.js
index 7127a72..66f1a83 100644
--- a/public_html/js/files_ui.js
+++ b/public_html/js/files_ui.js
@@ -1,1997 +1,2048 @@
/*
+--------------------------------------------------------------------------+
| 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_ui()
{
var ref = this;
this.request_timeout = 300;
this.message_time = 3000;
this.events = {};
this.commands = {};
this.requests = {};
this.uploads = {};
this.ie = document.all && !window.opera;
this.env = {
url: 'api/',
sort_col: 'name',
sort_reverse: 0,
search_threads: 1,
directory_separator: '/',
resources_dir: 'resources'
};
// 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 *********/
/*********************************************************/
// initialize interface
this.init = function()
{
if (!this.env.token)
return;
if (this.env.task == 'main') {
this.enable_command('folder.list', 'folder.create', 'file.search', true);
this.command('folder.list');
}
else if (this.env.task == 'file') {
this.load_file('#file-content', this.env.filedata);
this.enable_command('file.delete', 'file.download', true);
}
if (!this.env.browser_capabilities)
this.browser_capabilities_check();
};
// 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;
};
// 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;
if (!this.commands[command])
return;
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);
}
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);
}
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);
};
this.buttons = function(p)
{
$.each(p, function(i, v) {
if (!ui.buttons[i])
ui.buttons[i] = [];
if (typeof v == 'object')
ui.buttons[i] = $.merge(ui.buttons[i], v);
else
ui.buttons[i].push(v);
});
};
this.enable_command = function()
{
var i, n, args = Array.prototype.slice.call(arguments),
enable = args.pop(), cmd;
for (n=0; n<args.length; n++) {
cmd = args[n];
// argument of type array
if (typeof cmd === 'string') {
this.commands[cmd] = enable;
if (this.buttons[cmd])
$.each(this.buttons[cmd], function (i, button) {
$('#'+button)[enable ? 'removeClass' : 'addClass']('disabled');
});
this.trigger_event('enable-command', {command: cmd, status: enable});
}
// push array elements into commands array
else {
for (i in cmd)
args.push(cmd[i]);
}
}
};
/*********************************************************/
/********* 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 *********/
- /********************************************************/
-/*
- // 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); }
- });
- };
-
- // 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');
- };
-*/
-
/********************************************************/
/********* 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 + 20,
top = pos.top - 10;
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 and response handlers *********/
/*********************************************************/
this.logout = function()
{
this.main_logout();
};
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.request('folder_list', {}, 'folder_list_response');
};
// folder list response handler
this.folder_list_response = function(response)
{
if (!this.response(response))
return;
var elem = $('#folderlist'), table = $('table', elem);
this.env.folders = this.folder_list_parse(response.result && response.result.list ? response.result.list : response.result);
table.empty();
$.each(this.env.folders, function(i, f) {
var row = ui.folder_list_row(i, f);
table.append(row);
});
// add virtual collections
$.each(['audio', 'video', 'image', 'document'], function(i, n) {
var row = $('<tr><td><span class="name"></span></td></tr>'),
span = $('span.name', row);
row.attr('id', 'folder-collection-' + n);
span.text(ui.t('collection.' + n))
.click(function() { ui.folder_select(n, true); });
if (n == ui.env.collection)
row.addClass('selected');
table.append(row);
});
// add tree icons
this.folder_list_tree(this.env.folders);
// handle authentication errors on external sources
this.folder_list_auth_errors(response.result);
};
this.folder_select = function(folder, is_collection)
{
this.env.search = null;
this.file_search_stop();
var list = $('#folderlist');
$('tr.selected', list).removeClass('selected');
if (is_collection) {
var found = $('#folder-collection-' + folder, list).addClass('selected');
this.env.folder = null;
this.enable_command('file.list', true);
this.enable_command('folder.delete', 'folder.edit', 'file.upload', false);
this.file_list({collection: folder});
}
else {
var found = $('#' + this.env.folders[folder].id, list).addClass('selected');
this.env.collection = null;
this.enable_command('file.list', 'folder.delete', 'folder.edit', 'file.upload', found.length);
this.file_list({folder: folder});
}
};
this.folder_unselect = function()
{
this.env.search = null;
this.env.folder = null;
this.env.collection = null;
this.file_search_stop();
var list = $('#folderlist');
$('tr.selected', list).removeClass('selected');
this.enable_command('file.list', 'folder.delete', 'folder.edit', 'file.upload', false);
};
// folder create request
this.folder_create = function(folder)
{
if (!folder) {
this.folder_create_start();
return;
}
if (typeof folder != 'object') {
folder = {folder: folder};
}
this.set_busy(true, 'saving');
this.request('folder_create', folder, 'folder_create_response');
};
// folder create response handler
this.folder_create_response = function(response)
{
if (!this.response(response))
return;
this.folder_create_stop();
this.folder_list();
};
// folder rename request
this.folder_edit = function(folder)
{
if (!folder) {
this.folder_edit_start();
return;
}
this.set_busy(true, 'saving');
this.env.folder_rename = folder['new'];
this.request('folder_move', {folder: folder.folder, 'new': folder['new']}, 'folder_rename_response');
};
// folder rename response handler
this.folder_rename_response = function(response)
{
if (!this.response(response))
return;
this.env.folder = this.env.folder_rename;
this.folder_list();
this.file_list();
};
// folder delete request
this.folder_delete = function(folder)
{
if (folder === undefined)
folder = this.env.folder;
if (!folder)
return;
// @todo: confirm
this.set_busy(true, 'saving');
this.request('folder_delete', {folder: folder}, 'folder_delete_response');
};
// folder delete response handler
this.folder_delete_response = function(response)
{
if (!this.response(response))
return;
this.env.folder = null;
$('#filelist tbody').empty();
this.enable_command('folder.delete', 'folder.edit', 'file.list', 'file.search', 'file.upload', false);
this.folder_list();
};
// file list request
this.file_list = function(params)
{
if (!params)
params = {};
var i, req = (new Date).getTime();
// reset all pending list requests
for (i in this.requests) {
this.requests[i].abort();
delete this.requests[i];
}
if (params.all_folders) {
params.collection = null;
params.folder = null;
this.folder_unselect();
}
if (params.collection == undefined)
params.collection = this.env.collection;
if (params.folder == undefined)
params.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.collection = params.collection;
this.env.folder = params.folder;
this.env.sort_col = params.sort;
this.env.sort_reverse = params.reverse;
// empty the list
$('#filelist tbody').empty();
this.env.file_list = [];
this.env.list_shift_start = null;
this.enable_command('file.open', 'file.get', 'file.rename', 'file.delete', 'file.copy', 'file.move', false);
// request
if (params.collection || params.all_folders)
this.file_list_loop(params);
else {
this.set_busy(true, 'loading');
this.requests[req] = this.request('file_list', params, 'file_list_response');
}
};
// call file.list request for every folder (used for search and virt. collections)
this.file_list_loop = function(params)
{
var i, folders = [], req = (new Date).getTime(),
limit = Math.max(this.env.search_threads || 1, 1);
if (params.collection) {
if (!params.search)
params.search = {};
params.search['class'] = params.collection;
delete params['collection'];
}
delete params['all_folders'];
$.each(this.env.folders, function(i, f) {
if (!f.virtual)
folders.push(i);
});
this.env.folders_loop = folders;
this.env.folders_loop_params = params;
this.env.folders_loop_lock = false;
for (i=0; i<folders.length && i<limit; i++) {
this.set_busy(true, 'loading');
params.folder = folders.shift();
this.requests[req+'-'+i] = this.request('file_list', params, 'file_list_loop_response');
}
};
// file list response handler
this.file_list_response = function(response)
{
if (!this.response(response))
return;
var table = $('#filelist'), list = [];
$.each(response.result, function(key, data) {
var row = ui.file_list_row(key, data);
table.append(row);
data.row = row;
list.push(data);
});
this.env.file_list = list;
};
// file list response handler for loop'ed request
this.file_list_loop_response = function(response)
{
var i, folders = this.env.folders_loop,
params = this.env.folders_loop_params,
limit = Math.max(this.env.search_threads || 1, 1),
valid = this.response(response),
req = (new Date).getTime();
for (i=0; i<folders.length && i<limit; i++) {
this.set_busy(true, 'loading');
params.folder = folders.shift();
this.requests[req+'-'+i] = this.request('file_list', params, 'file_list_loop_response');
}
if (!valid)
return;
this.file_list_loop_result_add(response.result);
};
// add files from list request to the table (with sorting)
this.file_list_loop_result_add = function(result)
{
// chack if result (hash-array) is empty
if (!object_is_empty(result))
return;
if (this.env.folders_loop_lock) {
setTimeout(function() { ui.file_list_loop_result_add(result); }, 100);
return;
}
// lock table, other list responses will wait
this.env.folders_loop_lock = true;
var n, i, len, elem, list = [], table = $('#filelist');
for (n=0, len=this.env.file_list.length; n<len; n++) {
elem = this.env.file_list[n];
for (i in result) {
if (this.sort_compare(elem, result[i]) < 0)
break;
var row = this.file_list_row(i, result[i]);
elem.row.before(row);
result[i].row = row;
list.push(result[i]);
delete result[i];
}
list.push(elem);
}
// add the rest of rows
$.each(result, function(key, data) {
var row = ui.file_list_row(key, data);
table.append(row);
result[key].row = row;
list.push(result[key]);
});
this.env.file_list = list;
this.env.folders_loop_lock = false;
};
// sort files list (without API request)
this.file_list_sort = function(col, reverse)
{
var n, len, list = this.env.file_list,
table = $('#filelist'), tbody = $('<tbody>');
this.env.sort_col = col;
this.env.sort_reverse = reverse;
if (!list || !list.length)
return;
// sort the list
list.sort(function (a, b) {
return ui.sort_compare(a, b);
});
// add rows to the new body
for (n=0, len=list.length; n<len; n++) {
tbody.append(list[n].row);
}
// replace table bodies
$('tbody', table).replaceWith(tbody);
};
// file delete request
this.file_delete = function(file)
{
if (!file) {
file = [];
if (this.env.file)
file.push(this.env.file);
else
file = this.file_list_selected();
}
this.set_busy(true, 'deleting');
this.request('file_delete', {file: file}, 'file_delete_response');
};
// file delete response handler
this.file_delete_response = function(response)
{
if (!this.response(response))
return;
if (this.env.file) {
var path = this.file_path(this.env.file);
if (window.opener && opener.ui && (!opener.ui.env.folder || opener.ui.env.folder == path))
opener.ui.file_list();
window.close();
}
else
this.file_list();
};
// file rename request
this.file_rename = function(file, newname)
{
if (file === newname)
return;
this.set_busy(true, 'saving');
this.request('file_move', {file: file, 'new': newname}, 'file_rename_response');
};
// file rename response handler
this.file_rename_response = function(response)
{
if (!this.response(response))
return;
// @TODO: we could update list/file metadata and just sort
this.file_list();
};
// file copy request
this.file_copy = function(folder)
{
var count = 0, list = {}, files = this.file_list_selected();
if (!files || !files.length || !folder)
return;
$.each(files, function(i, v) {
var name = folder + ui.env.directory_separator + ui.file_name(v);
if (name != v) {
list[v] = name;
count++;
}
});
if (!count)
return;
this.set_busy(true, 'copying');
this.request('file_copy', {file: list}, 'file_copy_response');
};
// file copy response handler
this.file_copy_response = function(response)
{
if (!this.response(response))
return;
if (response.result && response.result.already_exist && response.result.already_exist.length)
this.file_move_ask_user(response.result.already_exist);
};
// file move request
this.file_move = function(folder)
{
var count = 0, list = {}, files = this.file_list_selected();
if (!files || !files.length || !folder)
return;
$.each(files, function(i, v) {
var name = folder + ui.env.directory_separator + ui.file_name(v);
if (name != v) {
list[v] = name;
count++;
}
});
if (!count)
return;
this.set_busy(true, 'moving');
this.request('file_move', {file: list}, 'file_move_response');
};
// file move response handler
this.file_move_response = function(response)
{
if (!this.response(response))
return;
if (response.result && response.result.already_exist && response.result.already_exist.length)
this.file_move_ask_user(response.result.already_exist, true);
else
this.file_list();
};
this.file_download = function(file)
{
if (!file)
file = this.env.file;
location.href = this.env.url + this.url('file_get', {token: this.env.token, file: file, 'force-download': 1});
};
// file upload request
this.file_upload = function()
{
- var i, size = 0, maxsize = this.env.capabilities.MAX_UPLOAD,
- form = $('#uploadform'),
+ var form = $('#uploadform'),
field = $('input[type=file]', form).get(0),
files = field.files ? field.files.length : field.value ? 1 : 0;
- if (files) {
- // check upload max size
- if (field.files && maxsize) {
- for (i=0; i < files; i++)
- size += field.files[i].size;
+ if (!files || !this.file_upload_size_check(field.files))
+ return;
+
+ // submit form and read server response
+ this.file_upload_form(form, 'file_upload', function(e, frame, folder) {
+ var doc, response, res;
- if (size > maxsize) {
- alert(this.t('upload.size.error').replace('$size', this.file_size(maxsize)));
+ try {
+ doc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;
+ response = doc.body.innerHTML;
+
+ // in Opera onload is called twice, once with empty body
+ if (!response)
return;
- }
+ // response may be wrapped in <pre> tag
+ if (response.match(/^<pre[^>]*>(.*)<\/pre>$/i))
+ response = RegExp.$1;
+
+ response = eval('(' + response + ')');
+ }
+ catch (err) {
+ response = {status: 'ERROR'};
}
- // submit form and read server response
- this.file_upload_form(form, 'file_upload', function(e, frame, folder) {
- var doc, response, res;
+ if ((res = ui.response_parse(response)) && folder == ui.env.folder)
+ ui.file_list();
- try {
- doc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;
- response = doc.body.innerHTML;
+ return res;
+ });
+ };
- // in Opera onload is called twice, once with empty body
- if (!response)
- return;
- // response may be wrapped in <pre> tag
- if (response.match(/^<pre[^>]*>(.*)<\/pre>$/i))
- response = RegExp.$1;
+ // handler when files are dropped to a designated area.
+ // compose a multipart form data and submit it to the server
+ this.file_drop = function(e)
+ {
+ var files = e.target.files || e.dataTransfer.files;
- response = eval('(' + response + ')');
- }
- catch (err) {
- response = {status: 'ERROR'};
+ if (!files || !files.length || !this.file_upload_size_check(files))
+ return;
+
+ // prepare multipart form data composition
+ var ts = new Date().getTime(),
+ progress = this.env.capabilities.PROGRESS_NAME && window.progress_update,
+ formdata = window.FormData ? new FormData() : null,
+ fieldname = 'file[]',
+ boundary = '------multipartformboundary' + (new Date).getTime(),
+ dashdash = '--', crlf = '\r\n',
+ multipart = dashdash + boundary + crlf;
+
+ // inline function to submit the files to the server
+ var submit_data = function() {
+ var multiple = files.length > 1;
+
+ ui.uploads[ts] = ui.env.folder;
+
+ // start progress meter
+ if (progress)
+ ui.file_upload_progress(ts);
+
+ // complete multipart content and post request
+ multipart += dashdash + boundary + dashdash + crlf;
+
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: ui.env.url + ui.url('file_upload', {folder: ui.env.folder}),
+ contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary,
+ processData: false,
+ timeout: 0, // disable default timeout set in ajaxSetup()
+ data: formdata || multipart,
+ success: function(response) {
+ if (ui.response_parse(response) && ui.uploads[ts] == ui.env.folder)
+ ui.file_list();
+ ui.file_upload_progress_stop(ts);
+ },
+ error: function(o, status, err) {
+ ui.http_error(o, status, err);
+ ui.file_upload_progress_stop(ts);
+ },
+ xhr: function() {
+ var xhr = jQuery.ajaxSettings.xhr();
+ if (!formdata && xhr.sendAsBinary)
+ xhr.send = xhr.sendAsBinary;
+ return xhr;
}
+ });
+ };
- if ((res = ui.response_parse(response)) && folder == ui.env.folder)
- ui.file_list();
+ // upload progress supported (and handler exists)
+ // add progress ID to the request - need to be added before files
+ if (progress) {
+ if (formdata)
+ formdata.append(this.env.capabilities.PROGRESS_NAME, ts);
+ else
+ multipart += 'Content-Disposition: form-data; name="' + ts.env.capabilities.PROGRESS_NAME + '"'
+ + crlf + crlf + ts + crlf + dashdash + boundary + crlf;
+ }
- return res;
- });
+ // get contents of all dropped files
+ var f, j, i = 0, last = files.length - 1;
+ for (j = 0; j <= last && (f = files[i]); i++) {
+ if (!f.name) f.name = f.fileName;
+ if (!f.size) f.size = f.fileSize;
+ if (!f.type) f.type = 'application/octet-stream';
+
+ // file name contains non-ASCII characters, do UTF8-binary string conversion.
+ if (!formdata && /[^\x20-\x7E]/.test(f.name))
+ f.name_bin = unescape(encodeURIComponent(f.name));
+
+ // do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+)
+ if (formdata) {
+ formdata.append(fieldname, f);
+ if (j == last)
+ return submit_data();
+ }
+ // use FileReader supporetd by Firefox 3.6
+ else if (window.FileReader) {
+ var reader = new FileReader();
+
+ // closure to pass file properties to async callback function
+ reader.onload = (function(file, j) {
+ return function(e) {
+ multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
+ multipart += '; filename="' + (f.name_bin || file.name) + '"' + crlf;
+ multipart += 'Content-Length: ' + file.size + crlf;
+ multipart += 'Content-Type: ' + file.type + crlf + crlf;
+ multipart += reader.result + crlf;
+ multipart += dashdash + boundary + crlf;
+
+ if (j == last) // we're done, submit the data
+ return submit_data();
+ }
+ })(f,j);
+ reader.readAsBinaryString(f);
+ }
+
+ j++;
}
};
/*********************************************************/
/********* Command helpers *********/
/*********************************************************/
// handle auth errors on folder list
this.folder_list_auth_errors = function(result)
{
if (result && result.auth_errors) {
if (!this.auth_errors)
this.auth_errors = {};
$.extend(this.auth_errors, result.auth_errors);
}
// ask for password to the first storage on the list
$.each(this.auth_errors || [], function(i, v) {
ui.folder_list_auth_dialog(i, v);
return false;
});
};
// create dialog for user credentials of external storage
this.folder_list_auth_dialog = function(label, driver)
{
var div, buttons = {},
content = this.folder_list_auth_form(driver),
title = this.t('folder.authenticate').replace('$title', label);
buttons['form.submit'] = function() {
var data = {folder: label, list: 1};
$('input', this.modal).each(function() {
data[this.name] = this.type == 'checkbox' && !this.checked ? '' : this.value;
});
ui.open_dialog = this;
ui.set_busy(true, 'authenticating');
ui.request('folder_auth', data, 'folder_auth_response');
};
buttons['form.cancel'] = function() {
delete ui.auth_errors[label];
this.hide();
// go to the next one
ui.folder_list_auth_errors();
};
// copy "remember password" checkbox into the dialog
div = $('.drivers-footer').first().clone();
if (div.length) {
div.find('input').each(function() { this.id += '-dialog'; });
div.find('label').each(function() { $(this).prop('for', $(this).prop('for') + '-dialog'); });
content.append(div.show());
}
this.modal_dialog(content, buttons, {
title: title,
fxOpen: function(win) {
// focus first empty input
$('input', win.modal).each(function() {
if (!this.value) {
this.focus();
return false;
}
});
}
});
};
// folder_auth handler
this.folder_auth_response = function(response)
{
if (!this.response(response))
return;
var cnt = 0, folders,
folder = response.result.folder,
parent = $('#' + this.env.folders[folder].id);
delete this.auth_errors[folder];
this.open_dialog.hide();
// go to the next one
this.folder_list_auth_errors();
// count folders on the list
$.each(this.env.folders, function() { cnt++; });
// parse result
folders = this.folder_list_parse(response.result.list, cnt);
delete folders[folder]; // remove root added in folder_list_parse()
// add folders from the external source to the list
$.each(folders, function(i, f) {
var row = ui.folder_list_row(i, f);
parent.after(row);
parent = row;
});
// add tree icons
this.folder_list_tree(folders);
$.extend(this.env.folders, folders);
};
// returns content of the external storage authentication form
this.folder_list_auth_form = function(driver)
{
var elements = [];
$.each(driver.form, function(fi, fv) {
var id = 'authinput' + fi,
attrs = {type: fi.match(/pass/) ? 'password' : 'text', size: 25, name: fi, id: id},
input = $('<input>').attr(attrs);
if (driver.form_values && driver.form_values[fi])
input.attr({value: driver.form_values[fi]});
elements.push($('<span class="formrow">').append($('<label>').attr('for', id).text(fv)).append(input));
});
return $('<div class="form">').append(elements);
};
// create folders table row
this.folder_list_row = function(folder, data)
{
var row = $('<tr><td><span class="branch"></span><span class="name"></span></td></tr>'),
span = $('span.name', row);
span.text(data.name);
row.attr('id', data.id).data('folder', folder);
if (data.depth)
$('span.branch', row).width(15 * data.depth);
if (data.virtual)
row.addClass('virtual');
else {
span.click(function() { ui.folder_select(folder); })
row.mouseenter(function() {
if (ui.drag_active && (!ui.env.folder || ui.env.folder != $(this).data('folder')))
$(this).addClass('droptarget');
})
.mouseleave(function() {
if (ui.drag_active)
$(this).removeClass('droptarget');
});
if (folder == this.env.folder)
row.addClass('selected');
}
return row;
};
// create files table row
this.file_list_row = function(filename, data)
{
var row = $('<tr><td class="filename"></td>'
+' <td class="filemtime"></td><td class="filesize"></td></tr>'),
link = $('<span></span>').text(data.name).click(function(e) { ui.file_menu(e, filename, data.type); });
$('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', filename)
.click(function(e) { ui.file_list_click(e, this); })
.mousedown(function(e) { return ui.file_list_drag(e, this); });
// disables selection in IE
if (document.all)
row.on('selectstart', function() { return false; });
return row;
};
// file row click event handler
this.file_list_click = function(e, row)
{
var list = $('#filelist'), org = row, row = $(row),
found, selected, shift = this.env.list_shift_start;
if (e.shiftKey && shift && org != shift) {
$('tr', list).each(function(i, r) {
if (r == org) {
found = 1;
$(r).addClass('selected');
return;
}
else if (!selected && r == shift) {
selected = 1;
return;
}
if ((!found && selected) || (found && !selected))
$(r).addClass('selected');
else
$(r).removeClass('selected');
});
}
else if (e.ctrlKey)
row.toggleClass('selected');
else {
$('tr.selected', list).removeClass('selected');
$(row).addClass('selected');
this.env.list_shift_start = org;
}
selected = $('tr.selected', list).length;
if (!selected)
this.env.list_shift_start = null;
this.enable_command('file.delete', 'file.move', 'file.copy', selected);
this.enable_command('file.open', 'file.get', 'file.rename', selected == 1);
};
// file row drag start event handler
this.file_list_drag = function(e, row)
{
if (e.shiftKey || e.ctrlKey || $(e.target).is('input'))
return true;
// selects currently unselected row
if (!$(row).hasClass('selected'))
this.file_list_click(e, row);
this.drag_start = true;
this.drag_mouse_start = this.mouse_pos(e);
$(document)
.on('mousemove.draghandler', function(e) { ui.file_list_drag_mouse_move(e); })
.on('mouseup.draghandler', function(e) { ui.file_list_drag_mouse_up(e); });
/*
if (bw.mobile) {
$(document)
.on('touchmove.draghandler', function(e) { ui.file_list_drag_mouse_move(e); })
.on('touchend.draghandler', function(e) { ui.file_list_drag_mouse_up(e); });
}
*/
return false;
};
// file row mouse move event handler
this.file_list_drag_mouse_move = function(e)
{
/*
// convert touch event
if (e.type == 'touchmove') {
if (e.changedTouches.length == 1)
e = rcube_event.touchevent(e.changedTouches[0]);
else
return rcube_event.cancel(e);
}
*/
var max_rows = 10, pos = this.mouse_pos(e);
if (this.drag_start) {
// check mouse movement, of less than 3 pixels, don't start dragging
if (!this.drag_mouse_start || (Math.abs(pos.left - this.drag_mouse_start.left) < 3 && Math.abs(pos.top - this.drag_mouse_start.top) < 3))
return false;
if (!this.draglayer)
this.draglayer = $('<div>').attr('id', 'draglayer')
.css({position:'absolute', display:'none', 'z-index':2000})
.appendTo(document.body);
// reset content
this.draglayer.html('');
// get subjects of selected messages
$('#filelist tr.selected').slice(0, max_rows+1).each(function(i) {
if (i == 0)
ui.drag_start_pos = $(this).offset();
else if (i == max_rows) {
ui.draglayer.append('...');
return;
}
var subject = $('td.filename', this).text();
// truncate filename to 50 characters
if (subject.length > 50)
subject = subject.substring(0, 50) + '...';
ui.draglayer.append($('<div>').text(subject));
});
this.draglayer.show();
this.drag_active = true;
}
if (this.drag_active && this.draglayer)
this.draglayer.css({left:(pos.left+20)+'px', top:(pos.top-5 + (this.ie ? document.documentElement.scrollTop : 0))+'px'});
this.drag_start = false;
return false;
};
// file row mouse up event handler
this.file_list_drag_mouse_up = function(e)
{
document.onmousemove = null;
/*
if (e.type == 'touchend') {
if (e.changedTouches.length != 1)
return rcube_event.cancel(e);
}
*/
$(document).off('.draghandler');
this.drag_active = false;
var got_folder = this.file_list_drag_end(e);
if (this.draglayer && this.draglayer.is(':visible')) {
if (this.drag_start_pos && !got_folder)
this.draglayer.animate(this.drag_start_pos, 300, 'swing').hide(20);
else
this.draglayer.hide();
}
};
// files drag end handler
this.file_list_drag_end = function(e)
{
var folder = $('#folderlist tr.droptarget').removeClass('droptarget');
if (folder.length) {
folder = folder.data('folder');
if (e.shiftKey && this.commands['file.copy']) {
this.file_drag_menu(e, folder);
return true;
}
this.command('file.move', folder);
return true;
}
};
// display file drag menu
this.file_drag_menu = function(e, folder)
{
var menu = $('#file-drag-menu');
$('li.file-copy > a', menu).off('click').click(function() { ui.command('file.copy', folder); });
$('li.file-move > a', menu).off('click').click(function() { ui.command('file.move', folder); });
this.popup_show(e, menu);
};
// display file menu
this.file_menu = function(e, file, type)
{
var href, caps, viewer,
menu = $('#file-menu'),
open_action = $('li.file-open > a', menu);
if (viewer = this.file_type_supported(type)) {
caps = this.browser_capabilities().join();
href = '?' + $.param({task: 'file', action: 'open', token: this.env.token, file: file, caps: caps, viewer: viewer == 2 ? 1 : 0});
open_action.attr({target: '_blank', href: href}).removeClass('disabled').off('click');
}
else
open_action.click(function() { return false; }).addClass('disabled');
$('li.file-download > a', menu)
.attr({href: this.env.url + this.url('file_get', {token: this.env.token, file: file, 'force-download': 1})});
$('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(e); });
this.popup_show(e, menu);
};
// returns selected files (with paths)
this.file_list_selected = function()
{
var files = [];
$('#filelist tr.selected').each(function() {
files.push($(this).data('file'));
});
return files;
};
this.file_rename_start = function(e)
{
var list = $('#filelist'),
tr = $(e.target).parents('tr'),
td = $('td.filename', tr),
file = tr.data('file'),
name = this.file_name(file),
input = $('<input>').attr({type: 'text', name: 'filename', 'class': 'filerename'})
.val(name).data('file', 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(),
oldname = elem.data('file'),
path = ui.file_path(file);
ui.file_rename(oldname, path + ui.env.directory_separator + 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), name = ui.file_name(elem.data('file'));
elem.parent().text(name);
});
};
// post the given form to a hidden iframe
this.file_upload_form = function(form, action, onload)
{
var ts = new Date().getTime(),
frame_name = 'fileupload' + ts;
this.uploads[ts] = this.env.folder;
// upload progress supported (and handler exists)
if (this.env.capabilities.PROGRESS_NAME && window.progress_update) {
var fname = this.env.capabilities.PROGRESS_NAME,
field = $('input[name='+fname+']', form);
if (!field.length) {
field = $('<input>').attr({type: 'hidden', name: fname});
field.prependTo(form);
}
field.val(ts);
this.file_upload_progress(ts);
}
// have to do it this way for IE
// otherwise the form will be posted to a new window
if (document.all) {
document.body.insertAdjacentHTML('BeforeEnd',
'<iframe id="'+frame_name+'" name="'+frame_name+'"'
+ ' src="' + this.env.resources_dir + '/blank.gif" '
+ ' style="width:0;height:0;visibility:hidden;"></iframe>');
}
// 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).load(function(e) {
- // hide progressbar on upload error
- if (!onload(e, this, ui.uploads[ts]) && window.progress_update)
- window.progress_update({id: ts, done: true});
- delete ui.uploads[ts];
+ onload(e, this, ui.uploads[ts]);
+ ui.file_upload_progress_stop(ts);
});
$(form).attr({
target: frame_name,
- action: this.env.url + this.url(action, {folder: this.env.folder, token: this.env.token, uploadid:ts}),
+ action: this.env.url + this.url(action, {folder: this.env.folder, token: this.env.token}),
method: 'POST'
}).attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data')
.submit();
};
// upload progress requests
this.file_upload_progress = function(id)
{
setTimeout(function() {
if (id && ui.uploads[id])
ui.request('upload_progress', {id: id}, 'file_upload_progress_response');
}, this.env.capabilities.PROGRESS_TIME * 1000);
};
// upload progress response
this.file_upload_progress_response = function(response)
{
if (!this.response(response))
return;
var param = response.result;
if (param.id && window.progress_update)
window.progress_update(param);
if (!param.done)
this.file_upload_progress(param.id);
};
+ this.file_upload_progress_stop = function(id)
+ {
+ if (window.progress_update)
+ window.progress_update({id: id, done: true});
+ delete ui.uploads[id];
+ };
+
+ // check upload max size
+ this.file_upload_size_check = function(files)
+ {
+ var i, size = 0, maxsize = this.env.capabilities.MAX_UPLOAD;
+
+ if (files && maxsize) {
+ for (i=0; i < files.length; i++)
+ size += files[i].size;
+
+ if (size > maxsize) {
+ alert(this.t('upload.size.error').replace('$size', this.file_size(maxsize)));
+ return false;
+ }
+ }
+
+ return true;
+ };
+
// Display file search form
this.file_search = function()
{
var form = this.form_show('file-search'),
has_folder = this.env.folder || this.env.collection,
radio1 = $('input[name="all_folders"][value="0"]', form);
$('input[name="name"]', form).val('').focus();
if (has_folder)
radio1.prop('disabled', false).click();
else {
radio1.prop('disabled', true);
$('input[name="all_folders"][value="1"]', form).click();
}
};
// 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(),
all = $('input[name="all_folders"]:checked', form).val();
if (value) {
this.env.search = {name: value};
this.file_list({search: this.env.search, all_folders: all == 1});
}
else
this.file_search_stop();
};
// Display folder creation form
this.folder_create_start = function()
{
var form = $('#folder-create-form');
$('.drivers', form).hide();
$('input[name="name"]', form).val('').focus();
$('input[name="parent"]', form).prop('checked', this.env.folder)
.prop('disabled', !this.env.folder);
$('#folder-driver-checkbox').prop('checked', false);
this.form_show('folder-create');
if (!this.folder_types)
this.request('folder_types', {}, 'folder_types_response');
else
this.folder_types_init();
};
// Hide folder creation form
this.folder_create_stop = function()
{
this.form_hide('folder-create');
};
// Submit folder creation form
this.folder_create_submit = function()
{
var args = {}, 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;
}
else if (data.external && data.driver) {
args.store_passwords = data.store_passwords;
args.driver = data.driver;
$.each(data, function(i, v) {
if (i.startsWith(data.driver + '[')) {
args[i.substring(data.driver.length + 1, i.length - 1)] = v;
}
});
}
folder += data.name;
args.folder = folder;
this.command('folder.create', args);
};
// folder_types response handler
this.folder_types_response = function(response)
{
if (!this.response(response))
return;
if (response.result) {
this.folder_types = response.result;
var list = [];
$.each(this.folder_types, function(i, v) {
var form = [], item = $('<div>').data('id', i),
content = $('<div class="content">')
label = $('<span class="name">').text(v.name),
desc = $('<span class="description">').text(v.description),
img = $('<img>').attr({alt: i, title: i, src: v.image}),
input = $('<input>').attr({type: 'radio', name: 'driver'}).val(i);
item.append(input)
.append(img)
.append(content);
content.append(label).append($('<br>')).append(desc);
$.each(v.form || [], function(fi, fv) {
var id = 'input' +i + fi,
attrs = {type: fi.match(/pass/) ? 'password' : 'text', size: 25, name: i + '[' + fi + ']', id: id};
form.push($('<span class="formrow">')
.append($('<label>').attr('for', id).text(fv))
.append($('<input>').attr(attrs))
);
});
if (form.length) {
$('<div class="form">').append(form).appendTo(content);
}
list.push(item);
});
if (list.length) {
var drivers_list = $('.drivers-list');
drivers_list.append(list);
this.form_show('folder-create');
$.each(list, function() {
this.click(function() {
$('.selected', drivers_list).removeClass('selected');
drivers_list.find('.form').hide();
$(this).addClass('selected').find('.form').show();
$('input[type="radio"]', this).prop('checked', true);
ref.form_show('folder-create');
});
});
$('#folder-parent-checkbox').change(function() {
if (this.checked)
$('#folder-create-form div.drivers').hide();
ref.folder_types_init();
});
$('#folder-driver-checkbox').change(function() {
drivers_list[this.checked ? 'show' : 'hide']();
$('.drivers-footer')[this.checked ? 'show' : 'hide']();
ref.folder_types_init();
});
this.folder_types_init();
}
}
};
// initialize folder types list on folder create form display
this.folder_types_init = function()
{
var form = $('#folder-create-form'),
list = $('.drivers-list > div', form);
if (list.length && !$('input[name="parent"]', form).is(':checked')) {
$('#folder-create-form div.drivers').show();
list[0].click();
}
$('.drivers-list,.drivers-footer')[list.length && $('#folder-driver-checkbox:checked').length ? 'show' : 'hide']();
ref.form_show('folder-create');
};
// Display folder edit form
this.folder_edit_start = function()
{
var opts = [], separator = this.env.directory_separator,
form = this.form_show('folder-edit'),
select = $('#folder-edit-parent-select'),
arr = this.env.folder.split(separator),
name = arr.pop();
$('input[name="name"]', form).val(name).focus();
$('option[value!=""]', select).remove();
$.each(this.env.folders, function(i, v) {
var n, arr = i.split(separator),
name = arr.pop(), prefix = '', level = '&nbsp;&nbsp;&nbsp;';
for (n=arr.length; n>0; n--)
prefix += level;
opts.push($('<option>').attr('value', i).html(prefix).append($('<span>').text(name)));
});
select.append(opts).val(arr.join(separator));
};
// Hide folder edit form
this.folder_edit_stop = function()
{
this.form_hide('folder-edit');
};
// Submit folder edit form
this.folder_edit_submit = function()
{
var folder = '', data = this.serialize_form('#folder-edit-form');
if (!data.name)
return;
if (data.parent)
folder = data.parent + this.env.directory_separator;
folder += data.name;
this.folder_edit_stop();
this.command('folder.edit', {folder: this.env.folder, 'new': folder});
};
// when file move/copy operation returns file-exists error
// this displays a dialog where user can decide to skip
// or overwrite destination file(s)
this.file_move_ask_user = function(list, move)
{
var file = list[0], buttons = {},
label = this.t('file.moveconfirm').replace('$file', file.dst);
buttons['file.overwrite'] = function() {
var file = list.shift(), f = {},
action = move ? 'file_move' : 'file_copy';
f[file.src] = file.dst;
ui.file_move_ask_list = list;
ui.file_move_ask_mode = move;
this.hide();
ui.set_busy(true, move ? 'moving' : 'copying');
ui.request(action, {file: f, overwrite: 1}, 'file_move_ask_user_response');
};
if (list.length > 1)
buttons['file.overwriteall'] = function() {
var f = {}, action = move ? 'file_move' : 'file_copy';
$.each(list, function() { f[this.src] = this.dst; });
this.hide();
ui.set_busy(true, move ? 'moving' : 'copying');
ui.request(action, {file: f, overwrite: 1}, action + '_response');
};
buttons['file.skip'] = function() {
list.shift();
this.hide();
if (list.length)
ui.file_move_ask_user(list, move);
else if (move)
ui.file_list();
};
if (list.length > 1)
buttons['file.skipall'] = function() {
this.hide();
if (move)
ui.file_list();
};
this.modal_dialog(label, buttons);
};
// file move (with overwrite) response handler
this.file_move_ask_user_response = function(response)
{
var mode = this.file_move_ask_mode, list = this.file_move_ask_list;
this.response(response);
if (list && list.length)
this.file_move_ask_user(list, mode);
else if (mode)
this.file_list();
};
this.file_edit = function()
{
if (this.file_editor) {
this.file_editor.enable();
this.enable_command('file.save', true);
}
};
this.file_save = function()
{
if (!this.file_editor)
return;
var content = this.file_editor.getContent();
this.file_editor.disable();
// because we currently can edit only text file
// and we do not expect them to be very big, we save
// file in a very simple way, no upload progress, etc.
this.set_busy(true, 'saving');
this.request('file_update', {file: this.env.file, content: content, info: 1}, 'file_save_response');
};
this.file_save_response = function(response)
{
this.file_editor.enable();
if (!this.response(response))
return;
// update file properties table
var table = $('#filedata table'), file = response.result;
if (response.result) {
$('td.filetype', table).text(file.type);
$('td.filesize', table).text(this.file_size(file.size));
$('td.filemtime', table).text(file.mtime);
}
};
/*********************************************************/
/********* Utilities *********/
/*********************************************************/
// modal dialog popup
this.modal_dialog = function(content, buttons, opts)
{
var settings = {position: 'cm', btns: {}, fxShow: 'fade'},
dialog = $('<div class="_wModal"></div>'),
body = $('<div class="_wModal"></div>'),
head, foot, footer = [];
// title bar
if (opts && opts.title)
$('<div class="_wModal_header"></div>')
.append($('<span>').text(opts.title))
.appendTo(body);
// dialog content
if (typeof content != 'object')
content = $('<div></div>').html(content);
content.addClass('_wModal_msg').appendTo(body);
// buttons
$.each(buttons, function(i, v) {
var n = i.replace(/[^a-z0-9_]/ig, '');
settings.btns[n] = v;
footer.push({name: n, label: ui.t(i)});
});
// open function
settings.fxOpen = opts.fxOpen;
// if (!settings.btns.cancel && (!opts || !opts.no_cancel))
// settings.btns.cancel = function() { this.hide(); };
if (footer.length) {
foot = $('<div class="_wModal_btns"></div>');
$.each(footer, function() {
$('<div tabindex="0"></div>').addClass('_wModal_btn_' + this.name).text(this.label).appendTo(foot)
});
body.append(foot);
// make buttons focusable and key-pressable
$(document).off('keydown.dialog').on('keydown.dialog', function(e) {
if (e.which == 13 && $(e.target).parent().is('._wModal_btns')) {
$(e.target).click();
}
});
}
// configure and display dialog
dialog.append(body).wModal(settings).wModal('show');
};
// Display folder creation form
this.form_show = function(name)
{
var form = $('#' + name + '-form');
if (form.is(':hidden')) {
$('#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);
};
// loads a file content into an iframe (with loading image)
this.load_file = function(content, filedata)
{
var iframe = $(content);
if (!iframe.length)
return;
var href = filedata.href,
div = iframe.parent(),
loader = $('#loader'),
offset = div.offset(),
w = loader.width(), h = loader.height(),
width = div.width(), height = div.height();
loader.css({
top: offset.top + height/2 - h/2 - 20,
left: offset.left + width/2 - w/2
}).show();
iframe.css('opacity', 0.1)
.load(function() { ui.loader_hide(this); })
.attr('src', href);
// some content, e.g. movies or flash doesn't execute onload on iframe
// let's wait some time and check document ready state
if (!/^text/i.test(filedata.mimetype))
setTimeout(function() {
// there sometimes "Permission denied to access propert document", use try/catch
try {
$(iframe.get(0).contentWindow.document).ready(function() {
parent.ui.loader_hide(content);
});
} catch (e) {};
}, 1000);
};
// hide content loader element, show content element
this.loader_hide = function(content)
{
$('#loader').hide();
$(content).css('opacity', 1);
var win = content.contentWindow;
this.file_editor = null;
try {
// it throws "permission denied" sometimes
if (win.file_editor && win.file_editor.editable)
this.file_editor = win.file_editor;
}
catch (e) {}
if (this.file_editor)
ui.enable_command('file.edit', true);
};
};
// Initialize application object (don't change var name!)
var ui = $.extend(new files_api(), new files_ui());
// general click handler
$(document).click(function() {
$('.popup').hide();
ui.file_rename_stop();
}).ready(function() {
ui.init();
});
diff --git a/public_html/skins/default/style.css b/public_html/skins/default/style.css
index 0a78506..d085e5e 100644
--- a/public_html/skins/default/style.css
+++ b/public_html/skins/default/style.css
@@ -1,1520 +1,1540 @@
body {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
color: #333;
margin: 0;
color: #514949;
background: url(images/body.png) top repeat-x #f0f0f0;
}
a {
color: #1E90FF;
text-decoration: none;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 5px;
color: #ff9900;
}
input[type="text"],
input[type="password"],
select[multiple="multiple"],
textarea {
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
padding-left: 2px;
color: black;
}
input[type="checkbox"],
input[type="radio"] {
vertical-align: middle;
}
select[multiple="multiple"] {
padding-left: 0;
}
table.list {
width: 100%;
table-layout: fixed;
border-spacing: 0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
table.list td {
padding: 2px 4px;
border: 1px solid white;
border-left: none;
border-top: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
table.list thead tr {
background-color: #e0e0e0;
font-weight: bold;
}
table.list tbody tr {
background-color: #f0f0f0;
}
table.list tfoot tr {
background-color: #e0e0e0;
}
table.list tfoot tr td {
padding: 3px 3px;
font-size: 10px;
text-shadow: white 1px 1px;
}
table.list tfoot tr td {
border-top: solid 1px white;
border-bottom: none;
}
table.list td:last-child {
border-right: none;
}
table.list tbody tr.selectable td {
cursor: default;
}
table.list tbody tr.selectable:hover {
background-color: #d6efff;
}
table.list tbody tr td.empty-body {
height: 150px;
color: #ff9900;
text-align: center;
}
fieldset {
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
margin-top: 10px;
}
legend {
padding-left: 0;
color: #909090;
}
table.form {
width: 100%;
}
table.form td {
padding: 1px 5px;
}
table.form tr.required input,
table.form tr.required select,
table.form tr.required textarea {
background-color: #f0f9ff;
}
table.form tr input.error,
table.form tr select.error,
table.form tr textarea.error {
background-color: #f5e3e3;
}
td.label {
width: 1%;
min-width: 120px;
text-align: right;
font-weight: bold;
white-space: nowrap;
}
table tbody tr.selected {
background-color: #d6efff;
}
/**** Common UI elements ****/
#topmenu {
text-align: right;
height: 20px;
padding: 0 10px;
margin: 0;
white-space: nowrap;
background: url(images/linen_header.jpg) 0 0 repeat-x;
}
#topmenu > span {
color: #aaa;
font-size: 11px;
padding-top: 2px;
display: inline-block;
height: 18px;
}
#navigation {
margin: 0 15px;
text-align: right;
height: 36px;
z-index: 2;
white-space: nowrap;
}
#task_navigation {
margin: 0 15px;
text-align: right;
height: 21px;
z-index: 2;
white-space: nowrap;
}
#message {
position: absolute;
top: 80px;
left: 20px;
width: 350px;
height: 60px;
z-index: 20;
}
#message div {
opacity: 0.97;
padding-left: 70px;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-moz-box-shadow: 1px 1px 3px #999;
-webkit-box-shadow: #999 1px 1px 3px;
width: 100%;
height: 100%;
display: table;
}
#message.notice div {
border-color: #aec1db;
color: #3465a4;
background: url(images/info.png) 10px center no-repeat #c0e0ff;
}
#message.error div {
border-color: #db9999;
color: #a40000;
background: url(images/error.png) 10px center no-repeat #edcccc;
}
#message div span {
vertical-align: middle;
display: table-cell;
line-height: 20px;
}
#logo {
position: absolute;
top: 0px;
left: 10px;
width: 198px;
height: 74px;
cursor: pointer;
background: url(images/logo.png) 0 0 no-repeat;
}
#content {
position: absolute;
left: 0;
right: 0;
top: 74px;
bottom: 55px;
margin: 0 15px;
padding: 10px;
background-color: #f5f5f5;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
#footer {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 50px;
margin: 2px 15px;
color: #b0b0b0;
font-size: 9px;
}
#loading {
position: absolute;
display: none;
top: 2px;
left: 15px;
width: 150px;
height: 18px;
padding-left: 86px;
color: #aaa;
font-size: 11px;
z-index: 1;
background: url(images/loading.gif) 0 3px no-repeat;
white-space: nowrap;
}
#topmenu .logout {
background: url(images/buttons.png) -1px -100px no-repeat;
padding-left: 20px;
margin-right: 10px;
color: white;
}
#topmenu .login {
padding-left: 20px;
margin-right: 20px;
background: url(images/user_ico.png) 0 2px no-repeat;
}
#topmenu .domain {
padding-left: 20px;
margin-right: 10px;
background: url(images/domain_ico.png) 0 3px no-repeat;
}
#navigation ul {
list-style-type: none;
margin: 0;
padding: 8px 0;
}
#navigation ul li {
display: inline;
font-size: 13px;
font-weight: bold;
padding: 8px 0;
}
#navigation ul li a {
padding: 8px 10px;
text-decoration: none;
color: #514949;
}
#navigation ul li.active {
background: url(images/navbg.png) 0 0 repeat-x;
}
#navigation ul li.active a {
text-shadow: white 1px 1px;
color: #ff9900;
}
#task_navigation ul {
list-style-type: none;
margin: 0;
padding: 2px 0;
}
#task_navigation ul li {
padding: 1px 0;
display: inline;
font-size: 12px;
font-weight: bold;
text-shadow: white 1px 1px;
}
#task_navigation ul li a {
padding: 1px 10px;
text-decoration: none;
color: #808080;
}
#navigation ul li a:active,
#task_navigation ul li a:active {
outline: none;
}
#search {
padding: 7px;
margin-bottom: 10px;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
background-color: #e0e0e0;
}
#searchinput {
border: none;
background-color: white;
margin-top: 2px;
}
#searchinput:focus {
outline: none;
}
.searchinput {
height: 20px;
margin: 0;
padding: 0;
background-color: white;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
overflow: hidden;
}
.searchactions {
float: left;
padding: 1px;
margin-left: -1px;
height: 18px;
width: 37px;
background-color: #f0f0f0;
cursor: pointer;
border-right: 1px solid #e0e0e0;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
-moz-border-radius-topleft: 3px;
-moz-border-radius-bottomleft: 3px;
-webkit-border-top-left-radius: 3px;
-webkit-border-left-right-radius: 3px;
}
#search-reset,
#search-details {
display: block;
float: left;
width: 18px;
height: 18px;
background: url(images/buttons.png) -1px 0 no-repeat;
}
#search-reset:hover,
#search-details:hover {
background-color: white;
}
#search-reset {
border-left: 1px solid #e0e0e0;
}
#search-details {
background-position: -1px 20px;
}
.searchdetails {
display: none;
}
.searchfilter {
color: #909090;
font-weight: bold;
margin-top: 5px;
}
#search fieldset {
margin: 0;
color: #909090;
margin-top: 5px;
}
#search td.label {
min-width: 0;
}
div.vsplitter {
float: left;
width: 10px;
min-height: 400px;
}
/* fix cursor on upload button */
input[type="file"]::-webkit-file-upload-button {
cursor: pointer;
}
#draglayer {
min-width: 300px;
width: auto !important;
width: 300px;
border: 1px solid #999999;
background-color: #fff;
padding-left: 8px;
padding-right: 8px;
padding-top: 3px;
padding-bottom: 3px;
white-space: nowrap;
opacity: 0.9;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-moz-box-shadow: 1px 1px 12px #999;
-webkit-box-shadow: #999 1px 1px 12px;
}
/**** Common classes ****/
a.disabled {
opacity: 0.5;
filter: alpha(opacity=50);
}
.nowrap {
white-space: nowrap;
}
.clear {
clear: both;
}
.watermark {
padding-top: 40px;
text-align: center;
width: 100%;
}
.link {
cursor: pointer;
}
.icon {
width: 16px;
height: 16px;
}
input.inactive {
color: #d0d0d0;
}
.formtitle {
color: #ff9900;
font-size: 18px;
font-weight: bold;
margin-left: 5px;
}
.formbuttons {
text-align: center;
white-space: nowrap;
}
.formbuttons input {
margin: 5px;
}
div.scroller {
left: 0;
top: 0;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
bottom: 19px;
}
.listnav {
width: 100%;
text-align: right;
}
.listnav a {
float: left;
display: block;
width: 16px;
height: 16px;
background: url(images/arrow_left.png) center no-repeat;
}
.listnav a.next {
background: url(images/arrow_right.png) center no-repeat;
}
.listnav a.disabled {
opacity: .3;
cursor: default;
}
.listnav span span {
float: left;
display: block;
height: 14px;
padding: 1px 5px;
}
.disabled,
.readonly,
.select.readonly option {
color: #a0a0a0;
}
input.disabled,
input.readonly,
select.disabled,
select.readonly,
textarea.disabled,
textarea.readonly {
background-color: #f5f5f5;
color: #a0a0a0;
}
input.maxsize {
width: 368px; /* span.listarea width - 2px */
}
pre.debug {
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
background-color: white;
padding: 2px;
width: 500px;
height: 200px;
margin: 0;
overflow: auto;
}
.popup {
display: none;
position: absolute;
border: 1px solid #d0d0d0;
border-radius: 3px;
box-shadow: 0 2px 6px 0 #d0d0d0;
-moz-box-shadow: 0 2px 6px 0 #d0d0d0;
-webkit-box-shadow: 0 2px 6px 0 #d0d0d0;
-o-box-shadow: 0 2px 6px 0 #d0d0d0;
background-color: #f0f0f0;
}
a.button {
display: inline-block;
width: 18px;
height: 18px;
background: url(images/buttons.png) 0 0 no-repeat;
}
a.button.edit {
background-position: -1px -81px;
}
a.button.add {
background-position: -1px -41px;
}
a.button.delete {
background-position: -1px -1px;
}
.popup ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.popup ul li {
padding: 2px 4px;
min-width: 100px;
cursor: default;
}
.popup ul li a {
cursor: default;
display: block;
}
.popup ul li:hover {
background-color: #d6efff;
}
div.boxfooter {
position: absolute;
height: 18px;
left: 0;
right: 0;
bottom: 0;
background-color: #e0e0e0;
border-top: 1px solid #d0d0d0;
}
div.boxfooter a.button {
width: auto;
white-space: nowrap;
color: #514949;
display: inline;
line-height: 18px;
padding: 0 5px 0 20px;
}
/********* Form smart inputs *********/
span.listarea {
display: block;
width: 370px;
max-height: 209px;
overflow-y: auto;
overflow-x: hidden;
margin: 0;
padding: 0;
background-color: white;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
text-align: left;
text-shadow: none;
color: black;
}
span.listelement {
display: block;
padding: 0;
margin: 0;
height: 18px;
overflow: hidden;
border-top: 1px solid #d0d0d0;
white-space: nowrap;
}
span.listelement:first-child {
border: none;
}
span.listelement input {
border: none;
background-color: transparent;
padding-left: 2px;
width: 328px;
height: 16px;
}
span.listarea.disabled span.listelement input,
span.listarea.readonly span.listelement input {
width: 370px;
}
span.listelement input:focus {
outline: none;
}
span.listelement span.actions {
float: left;
padding: 1px 0;
margin-left: -1px;
margin-top: -1px;
height: 18px;
width: 37px;
border: 1px solid #d0d0d0;
background-color: #f0f0f0;
cursor: pointer;
}
span.listelement span.actions span {
display: block;
float: left;
width: 18px;
height: 18px;
background: url(images/buttons.png) 0 0 no-repeat;
}
span.listelement span.actions span:hover {
background-color: white;
}
span.listelement span.actions span.reset {
background-position: -1px -1px;
border-left: 1px solid #e0e0e0;
}
span.listelement span.actions span.add {
background-position: -41px -2px;
}
span.listelement span.actions span.search {
background-position: -61px -1px;
cursor: default;
}
span.listarea.disabled,
span.listarea.readonly {
background-color: #f5f5f5;
}
input.disabled,
input.readonly,
span.listarea.disabled span.listelement input,
span.listarea.readonly span.listelement input {
color: #a0a0a0;
cursor: default;
}
span.listarea.autocomplete span.listelement input {
color: #514949;
}
span.listarea.autocomplete span.listelement input.autocomplete {
color: black;
}
.autocomplete > span.listelement input {
width: 346px;
}
.autocomplete > span.listelement span.actions {
width: 18px;
}
.autocomplete > span.listelement span.actions span.reset {
border-left: none;
}
.autocomplete > span.listelement span.actions span.search:hover {
background-color: #f0f0f0;
}
span.listarea.select {
width: 200px;
}
span.listarea.select > span.listelement input {
width: 180px;
}
span.listcontent {
display: block;
padding: 0;
margin: 0;
overflow: hidden;
max-height: 94px;
overflow-x: hidden;
overflow-y: auto;
border-top: 1px solid #d0d0d0;
background-color: #f5f5f5;
cursor: default;
}
span.listcontent span.listelement {
padding-left: 3px;
}
span.listcontent span.listelement:hover {
background-color: #d6efff;
}
span.listcontent span.listelement.selected {
background-color: #d6efff;
}
span.form_error {
color: #FF0000;
font-weight: bold;
font-size: 90%;
padding-left: 5px;
}
/***** progress bar ****/
table.progress {
width: 100%;
height: 5px;
background-color: #f0f0f0;
border: 1px solid #d0d0d0;
border-spacing: 0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
margin-bottom: 3px;
}
table.progress td.bar {
background-color: #71b9e1;
}
table.progressinfo {
font-size: 9px;
border: 1px solid #d0d0d0;
width: 5%;
background-color: #f0f0f0;
z-index: 100;
border-spacing: 0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
padding: 3px;
}
table.progressinfo td {
padding: 0 1px;
white-space: nowrap;
}
table.progressinfo td.label {
text-align: left;
font-weight: normal;
padding-right: 10px;
min-width: 50px;
width: 1%;
}
table.progressinfo td.value {
text-align: right;
width: 99%;
}
+/***** drag-n-drop *****/
+
+#taskcontent.droptarget.hover,
+#taskcontent.droptarget.active {
+ border-color: #019bc6;
+ box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
+ -webkit-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
+}
+
+#taskcontent.droptarget.hover {
+ background-color: #d9ecf4;
+ box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+ -webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
+}
+
+#taskcontent.droptarget.hover table tbody td {
+ background-color: #d9ecf4;
+}
+
+
/***** autocomplete list *****/
#autocompletepane
{
background-color: white;
border: 1px solid #d0d0d0;
min-width: 351px;
}
#autocompletepane ul
{
margin: 0px;
padding: 2px;
list-style-image: none;
list-style-type: none;
}
#autocompletepane ul li
{
display: block;
height: 16px;
font-size: 11px;
padding-left: 6px;
padding-top: 2px;
padding-right: 6px;
white-space: nowrap;
cursor: pointer;
}
#autocompletepane ul li.selected
{
background-color: #d6efff;
}
/***** tabbed interface elements *****/
div.tabsbar
{
height: 22px;
border-bottom: 1px solid #d0d0d0;
white-space: nowrap;
margin: 10px 5px 0 5px;
}
span.tablink,
span.tablink-selected
{
float: left;
height: 23px !important;
height: 22px;
overflow: hidden;
background: url(images/tabs-left.gif) top left no-repeat;
font-weight: bold;
}
span.tablink
{
cursor: pointer;
text-shadow: white 1px 1px;
}
span.tablink-selected
{
cursor: default;
background-position: 0px -23px;
}
span.tablink a,
span.tablink-selected a
{
display: inline-block;
padding: 4px 10px 0 5px;
margin-left: 5px;
height: 23px;
color: #808080;
max-width: 185px;
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
background: url(images/tabs-right.gif) top right no-repeat;
outline: none;
}
span.tablink-selected a
{
cursor: inherit;
color: #514949;
background-position: right -23px;
}
fieldset.tabbed
{
margin-top: 0;
padding-top: 12px;
border-top: none;
}
/***** Dialog windows *****/
#_wModal_bg {
background-color: #000;
z-index: 10000;
opacity: 0.2;
filter: alpha(opacity=20);
}
#_wModal_pixel {
z-index: 10001;
}
._wModal {
position: relative;
min-width: 350px;
overflow: hidden;
line-height: 15px;
background-color: #FFF;
color: #333;
border: 1px solid rgba(51, 51, 51, 0.5);
border-radius: 4px;
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
}
._wModal_header {
padding: 10px;
font-size: 14px;
font-weight: bold;
border-bottom: solid 1px #DDD;
}
._wModal_close {
position: absolute;
right: 10px;
top: 10px;
font-weight: normal;
font-size: 12px;
cursor: pointer;
color: #BABABA;
}
._wModal_msg {
font-size: 12px;
padding: 20px;
color: #3A3A3A;
text-shadow: rgba(255, 255, 255, 0.75) 0 1px 1px;
}
._wModal_btns {
padding: 10px;
font-size: 10px;
font-weight: bold;
border-top: solid 1px #DDD;
background-color: #EFEFEF;
text-align: right;
white-space: nowrap;
}
._wModal_btns div {
display: inline-block;
min-width: 40px;
padding: 0 10px;
height: 25px;
line-height: 25px;
margin-left: 10px;
text-align: center;
cursor: pointer;
border-radius: 4px;
box-shadow: rgba(255, 255, 255, 0.2) 0px 1px 0px 0px inset, rgba(0, 0, 0, 0.0470588) 0px 1px 2px 0px;
text-shadow: rgba(255, 255, 255, 0.75) 0 1px 1px;
border: 1px solid rgba(0, 0, 0, 0.14902);
border-bottom-color: rgba(0, 0, 0, 0.247059);
background-color: #F5F5F5;
color: #333;
}
._wModal_btns div:hover,
._wModal_btns div:focus {
background-color: #E6E6E6;
outline: none;
}
._wModal_btns div.default {
text-shadow: rgba(0, 0, 0, 0.247059) 0px -1px 0px;
border: 1px solid rgba(0, 0, 0, 0.0980392);
background-color: #006DCC;
color: #FFF;
}
._wModal_btns div.default:hover,
._wModal_btns div.default:focus {
background-color: #0044CC
}
/**** Login form elements ****/
#login_form {
margin: auto;
margin-top: 75px;
padding: 20px;
width: 330px;
background-color: #e0e0e0;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
text-align: center;
}
#login_form span {
display: block;
line-height: 24px;
width: 330px;
text-align: left;
}
#login_form label {
display: block;
width: 80px;
text-align: right;
float: left;
margin-right: 10px;
}
#login_form select,
#login_form input[type="text"],
#login_form input[type="password"] {
width: 210px;
}
#login_submit {
margin-top: 5px;
}
/**** Main screen elements ****/
#main {
padding: 5px 30px;
}
#footer .foot {
white-space: nowrap;
vertical-align: top;
text-align: right;
}
#folder-edit-form label {
display: inline-block;
width: 100px;
}
/***** tree indicators *****/
td span.branch span
{
float: left;
height: 16px;
}
td span.branch span.tree
{
height: 17px;
width: 15px;
background: url(images/tree.gif) 0 0 no-repeat;
}
td span.branch span.l1
{
background-position: 0px 0px; /* L */
}
td span.branch span.l2
{
background-position: -30px 0px; /* | */
}
td span.branch span.l3
{
background-position: -15px 0px; /* |- */
}
/**** File manager elements ****/
#taskcontent {
position: absolute;
left: 310px;
right: 10px;
bottom: 10px;
top: 10px;
background-color: #f0f0f0;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
overflow-y: auto;
}
#actionbar {
position: absolute;
width: 82px;
top: 10px;
bottom: 10px;
overflow: hidden;
}
#forms {
position: absolute;
left: 310px;
right: 10px;
top: 10px;
}
#forms form {
display: none;
}
#forms fieldset {
margin: 0;
background-color: #f0f0f0;
}
#forms table {
border-spacing: 0;
margin: 0;
padding: 0;
}
#forms table td.buttons {
width: 1%;
white-space: nowrap;
}
#actionbar a {
display: block;
width: 80px;
height: 55px;
border: 1px solid #d0d0d0;
border-spacing: 0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
background-color: #f0f0f0;
margin-bottom: 6px;
cursor: pointer;
color: #333;
}
#actionbar a span {
display: block;
position: absolute;
width: 100%;
text-align: center;
padding-top: 40px;
font-size: 9px;
}
#folder-create-button {
background: url(images/folder_new.png) center 6px no-repeat;
}
#file-create-button {
background: url(images/file_new.png) center 6px no-repeat;
}
#file-upload-button {
background: url(images/file_new.png) center 6px no-repeat;
}
#file-search-button {
background: url(images/search.png) center 6px no-repeat;
}
#file-save-button {
background: url(images/save.png) center 6px no-repeat;
}
#actionbar #file-save-button {
display: none;
}
#folderlist,
#filedata {
position: absolute;
width: 200px;
top: 10px;
bottom: 10px;
left: 98px;
border: 1px solid #d0d0d0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
background-color: #f0f0f0;
padding: 2px;
}
#folderlist table,
#filelist table {
width: 100%;
border-spacing: 0;
}
#filelist td {
white-space: nowrap;
cursor: default;
width: 70px;
overflow: hidden;
}
#filelist td.filename {
width: 98%;
height: 20px;
padding: 0 4px;
text-overflow: ellipsis;
}
#filelist td.filesize {
text-align: right;
}
#filelist td.filemtime {
width: 115px;
}
#filelist tbody td.filename span {
background: url(images/mimetypes/unknown.png) 0 0 no-repeat;
padding: 0 0 0 20px;
height: 16px;
cursor: pointer;
}
#filelist tbody td.filename span input {
padding: 0 2px;
height: 18px;
}
#filelist thead td {
cursor: pointer;
}
#filelist thead td.sorted {
padding-right: 16px;
text-decoration: underline;
background: url(images/buttons.png) right -140px no-repeat;
}
#filelist thead td.sorted.reverse {
background-position: right -120px;
}
#folderlist td span.name {
background: url(images/folder.png) 0 0 no-repeat;
height: 18px;
padding-left: 20px;
margin-left: 3px;
cursor: pointer;
}
#folderlist tr.selected td span.name {
background-image: url(images/folder_open.png);
}
#folderlist tr.selected {
background-color: inherit;
}
#folderlist tr.selected td span.name {
font-weight: bold;
}
#folderlist tr.virtual td span.name {
color: #bbb;
cursor: default;
}
#folderlist tr.droptarget {
background-color: #e0e0e0;
}
#folder-collection-audio td span.name,
#folderlist #folder-collection-audio.selected td span.name {
background: url(images/audio.png) 1px 0 no-repeat;
}
#folder-collection-video td span.name,
#folderlist #folder-collection-video.selected td span.name {
background: url(images/video.png) 0 0 no-repeat;
}
#folder-collection-image td span.name,
#folderlist #folder-collection-image.selected td span.name {
background: url(images/image.png) 0 0 no-repeat;
}
#folder-collection-document td span.name,
#folderlist #folder-collection-document.selected td span.name {
background: url(images/document.png) 0 0 no-repeat;
}
#folder-create-form input {
vertical-align: middle;
}
#folder-create-form table td.buttons {
vertical-align: top;
}
.drivers-list {
max-height: 160px;
overflow: auto;
}
.drivers-list > div {
border: 1px solid white;
border-radius: 3px;
margin-top: 3px;
padding: 2px 0;
}
.drivers-list > div.selected {
background-color: #e8e8e8;
}
.drivers-list div.content {
display: inline-block;
vertical-align: middle;
margin-left: 5px;
}
.drivers-list .name {
font-weight: bold;
}
.drivers-list img {
vertical-align: middle;
background-color: #e0e0e0;
border-radius: 3px;
margin: 3px;
background-image: -moz-linear-gradient(center top, #888, #333);
background-image: -webkit-linear-gradient(top, #888, #333);
background-image: -ms-linear-gradient(top, #888, #333);
}
.drivers-list input {
vertical-align: middle;
}
.drivers-list div.content div.form {
padding-top: 4px;
width: 400px;
}
.drivers-footer .description,
.drivers-list .description {
font-size: 10px;
color: #666;
display: block;
}
.drivers-footer .description {
margin-left: 25px;
}
div.form .formrow {
display: block;
padding: 1px;
}
div.form .formrow label {
width: 80px;
display: inline-block;
}
div.form .drivers-footer {
margin-top: 10px;
}
/****** File open interface elements ******/
#actionbar #file-edit-button {
background: url(images/edit.png) center 6px no-repeat #f0f0f0;
}
#actionbar #file-delete-button {
background: url(images/trash.png) center 6px no-repeat #f0f0f0;
}
#actionbar #file-download-button {
background: url(images/download.png) center 6px no-repeat #f0f0f0;
}
#taskcontent iframe {
border: none;
width: 100%;
height: 100%;
background-color: white;
overflow: auto;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
opacity: 0.1;
}
.fileopen #taskcontent {
overflow: hidden;
background-color: white;
}
#filedata table {
width: 200px;
}
#filedata table td.label {
min-width: 30px;
}
#filedata table td.data {
/*
text-overflow: ellipsis;
overflow: hidden;
*/
}
#filedata table td.data.filename {
font-weight: bold;
}
#loader {
display: none;
z-index: 10;
width: 100px;
background-color: #fafafa;
color: #a0a0a0;
position: absolute;
border: 1px solid #e0e0e0;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
text-align: center;
padding: 10px;
font-weight: bold;
}
diff --git a/public_html/skins/default/ui.js b/public_html/skins/default/ui.js
index 1032df8..a0e1749 100644
--- a/public_html/skins/default/ui.js
+++ b/public_html/skins/default/ui.js
@@ -1,141 +1,187 @@
function file_list_sort(name, elem)
{
var td = $(elem), reverse = ui.env.sort_reverse;
if (ui.env.sort_col == name)
reverse = !reverse;
else
reverse = 0;
$('td', td.parent()).removeClass('sorted reverse');
td.addClass('sorted').removeClass('reverse');
if (reverse)
td.addClass('reverse');
ui.file_list_sort(name, reverse);
};
function hack_file_input(id)
{
var link = $('#'+id),
file = $('<input>'),
offset = link.offset();
function move_file_input(e) {
file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'});
}
file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5, title: ''})
.change(function() { ui.file_upload(); })
.click(function() { setTimeout(function() { link.mouseleave(); }, 20); })
// opacity:0 does the trick, display/visibility doesn't work
.css({opacity: 0, cursor: 'pointer', position: 'relative', outline: 'none'});
// In FF and IE we need to move the browser file-input's button under the cursor
// Thanks to the size attribute above we know the length of the input field
if (navigator.userAgent.match(/Firefox|MSIE/))
file.css({marginLeft: '-80px'});
// Note: now, I observe problem with cursor style on FF < 4 only
link.css({overflow: 'hidden', cursor: 'pointer'})
.mouseenter(function() { this.__active = ui.commands['file.upload'] ? true : false; })
// place button under the cursor
.mousemove(function(e) {
if (ui.commands['file.upload'] && this.__active)
move_file_input(e);
// move the input away if button is disabled
else
$(this).mouseleave();
})
.mouseleave(function() {
file.css({top: '-10000px', left: '-10000px'});
this.__active = false;
})
.click(function(e) {
// forward click if mouse-enter event was missed
if (ui.commands['file.upload'] && !this.__active) {
this.__active = true;
move_file_input(e);
file.trigger(e);
}
})
.mouseleave()
.append(file);
};
function progress_update(data)
{
var txt = ui.t('file.progress'), id = 'progress' + data.id,
table = $('#' + id), content = $('#info' + id),
i, row, offset, rows = [];
- if (!data || data.done) {
+ if (!data || data.done || !data.total) {
if (table.length) {
table.remove();
content.remove();
}
return;
}
if (!table.length) {
table = $('<table class="progress" id="' + id + '"><tr><td class="bar"></td><td></td></tr></table>');
content = $('<table class="progressinfo" id="info' + id + '"></table>');
table.appendTo($('#actionbar'))
.on('mouseleave', function() { content.hide(); })
.on('mouseenter', function() { if (content.children().length) content.show(); });
offset = table.offset();
content.css({display: 'none', position: 'absolute', top: offset.top + 8, left: offset.left})
.appendTo(document.body);
}
$('td.bar', table).width((data.percent || 1) + '%');
if (data.total) {
rows[ui.t('upload.size')] = ui.file_size(data.total);
rows[ui.t('upload.progress')] = (data.percent || 0) + '%';
if (data.rate)
rows[ui.t('upload.rate')] = ui.file_size(data.rate) + '/s';
if (data.eta)
rows[ui.t('upload.eta')] = ui.time_format(data.eta);
content.empty();
for (i in rows)
$('<tr>').append($('<td class="label">').text(i))
.append($('<td class="value">').text(rows[i]))
.appendTo(content);
}
};
+// activate html5 file drop feature (if browser supports it)
+function init_drag_drop(container)
+{
+ if (!window.FormData && !(window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary)) {
+ return;
+ }
+
+ $(document.body).bind('dragover dragleave drop', function(e) {
+ if (!ui.env.folder)
+ return;
+
+ e.preventDefault();
+ container[e.type == 'dragover' ? 'addClass' : 'removeClass']('active');
+ });
+
+ container.bind('dragover dragleave', function(e) {
+ return drag_hover(e, e.type == 'dragover');
+ })
+ container.children('table').bind('dragover dragleave', function(e) {
+ return drag_hover(e, e.type == 'dragover');
+ })
+ container.get(0).addEventListener('drop', function(e) {
+ // abort event and reset UI
+ drag_hover(e, false);
+ return ui.file_drop(e);
+ }, false);
+};
+
+// handler for drag/drop on element
+function drag_hover(e, over)
+{
+ if (!ui.env.folder)
+ return;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ var elem = $(e.target);
+
+ if (!elem.hasClass('droptarget'))
+ elem = elem.parents('.droptarget');
+
+ elem[over ? 'addClass' : 'removeClass']('hover');
+};
+
function enable_command_handler(p)
{
if (p.command == 'file.save') {
$('#'+ui.buttons['file.edit']).css('display', p.status ? 'none' : 'block');
$('#'+ui.buttons['file.save']).css('display', p.status ? 'block' : 'none');
}
};
$(window).load(function() {
hack_file_input('file-upload-button');
$('#forms > form').hide();
ui.add_event_listener('enable-command', enable_command_handler);
+ init_drag_drop($('#taskcontent'));
});
// register buttons
ui.buttons({
'folder.create': 'folder-create-button',
'folder.edit': 'folder-edit-button',
'folder.delete': 'folder-delete-button',
'file.upload': 'file-upload-button',
'file.search': 'file-search-button',
'file.delete': 'file-delete-button',
'file.download': 'file-download-button',
'file.edit': 'file-edit-button',
'file.copy': 'file-copy-button',
'file.move': 'file-move-button',
'file.save': 'file-save-button'
});

File Metadata

Mime Type
text/x-diff
Expires
Mon, Sep 15, 9:09 PM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
287614
Default Alt Text
(94 KB)

Event Timeline