Implemented file preview using API viewers

This commit is contained in:
Aleksander Machniak 2013-05-19 12:45:19 +02:00
parent 96e3b0aa87
commit 76a43e5c38
8 changed files with 319 additions and 25 deletions

View file

@ -67,6 +67,7 @@ window.rcmail && rcmail.addEventListener('init', function() {
rcmail.file_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
rcmail.file_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
*/
rcmail.file_list.addEventListener('dblclick', function(o){ kolab_files_list_dblclick(o); });
rcmail.file_list.addEventListener('select', function(o){ kolab_files_list_select(o); });
rcmail.file_list.addEventListener('dragend', function(e){ kolab_files_drag_end(e); });
rcmail.file_list.addEventListener('column_replace', function(e){ kolab_files_set_coltypes(e); });
@ -87,7 +88,14 @@ window.rcmail && rcmail.addEventListener('init', function() {
rcmail.env.file_commands_all = ['files-delete', 'files-move', 'files-copy'];
kolab_files_init();
file_api.folder_list();
if (rcmail.env.action == 'open') {
rcmail.enable_command('files-get', 'files-delete', rcmail.env.file);
}
else {
file_api.folder_list();
file_api.browser_capabilities_check();
}
}
});
@ -110,7 +118,9 @@ function kolab_files_init()
url: rcmail.env.files_url,
sort_col: 'name',
sort_reverse: false,
search_threads: rcmail.env.search_threads
search_threads: rcmail.env.search_threads,
resources_dir: 'program/resources',
supported_mimetypes: rcmail.env.file_mimetypes
});
file_api.translations = rcmail.labels;
@ -435,6 +445,11 @@ kolab_files_click_on_list = function(e)
return true;
};
kolab_files_list_dblclick = function(list)
{
rcmail.command('files-open');
};
kolab_files_list_select = function(list)
{
var selected = list.selection.length;
@ -445,6 +460,25 @@ kolab_files_list_select = function(list)
// reset all-pages-selection
// if (list.selection.length && list.selection.length != list.rowcount)
// rcmail.select_all_mode = false;
// enable files-
if (selected == 1) {
// get file mimetype
var type = $('tr.selected', list.list).data('type');
rcmail.env.viewer = file_api.file_type_supported(type);
}
else
rcmail.env.viewer = 0;
/*
) {
// caps = this.browser_capabilities().join();
href = '?' + $.param({_task: 'files', _action: 'open', file: file, viewer: viewer == 2 ? 1 : 0});
var win = window.open(href, rcmail.html_identifier('rcubefile'+file));
if (win)
setTimeout(function() { win.focus(); }, 10);
}
*/
rcmail.enable_command('files-open', rcmail.env.viewer);
};
kolab_files_drag_end = function(e)
@ -544,7 +578,7 @@ rcube_webmail.prototype.files_delete = function()
if (!confirm(this.get_label('kolab_files.filedeleteconfirm')))
return;
var files = kolab_files_selected();
var files = this.env.file ? [this.env.file] : kolab_files_selected();
file_api.file_delete(files);
};
@ -584,12 +618,19 @@ rcube_webmail.prototype.files_list_update = function(head)
rcube_webmail.prototype.files_get = function()
{
var files = kolab_files_selected();
var files = this.env.file ? [this.env.file] : kolab_files_selected();
if (files.length == 1)
file_api.file_get(files[0], {'force-download': true});
};
rcube_webmail.prototype.files_open = function()
{
var files = kolab_files_selected();
if (files.length == 1)
file_api.file_open(files[0], rcmail.env.viewer);
};
/**********************************************************/
/********* Files API handler **********/
@ -831,13 +872,18 @@ function kolab_files_ui()
if (!this.response(response))
return;
var i = 0, table = $('#filelist');
var i = 0, list = [], table = $('#filelist');
$.each(response.result, function(key, data) {
i++;
var row = file_api.file_list_row(key, data, i);
rcmail.file_list.insert_row(row);
data.row = row;
data.filename = key;
list.push(data);
});
this.env.file_list = list;
};
// call file_list request for every folder (used for search and virt. collections)
@ -918,6 +964,7 @@ function kolab_files_ui()
var row = this.file_list_row(i, result[i], index++);
table.insert_row(row, elem.row);
result[i].row = row;
result[i].filename = i;
list.push(result[i]);
delete result[i];
}
@ -930,6 +977,7 @@ function kolab_files_ui()
var row = file_api.file_list_row(key, data, index++);
table.insert_row(row);
result[key].row = row;
result[key].filename = key;
list.push(result[key]);
});
@ -986,7 +1034,7 @@ function kolab_files_ui()
row = $('<tr>')
.html(row)
.attr({id: 'rcmrow' + index, 'data-file': file});
.attr({id: 'rcmrow' + index, 'data-file': file, 'data-type': data.type});
// collection (or search) lists files from all folders
// display file name with full path as title
@ -1039,7 +1087,12 @@ function kolab_files_ui()
return;
this.display_message('kolab_files.filedeletenotice', 'confirmation');
this.file_list();
if (rcmail.env.file) {
// @TODO: reload files list in parent window
window.close();
}
else
this.file_list();
};
// file(s) move request
@ -1269,4 +1322,13 @@ function kolab_files_ui()
.submit();
};
// open file in new window, using file API viewer
this.file_open = function(file, viewer)
{
var href = '?' + $.param({_task: 'files', _action: 'open', file: file, viewer: viewer == 2 ? 1 : 0}),
win = window.open(href, rcmail.html_identifier('rcubefile'+file));
if (win)
setTimeout(function() { win.focus(); }, 10);
};
};

View file

@ -47,6 +47,7 @@ class kolab_files extends rcube_plugin
// Register plugin task actions
$this->register_action('index', array($this, 'actions'));
$this->register_action('prefs', array($this, 'actions'));
$this->register_action('open', array($this, 'actions'));
$this->ui();
}

View file

@ -346,7 +346,7 @@ class kolab_files_engine
}
$a_show_cols = $attrib['columns'];
$head = '';
$head = '';
foreach ($this->file_list_head($attrib, $a_show_cols) as $cell) {
$head .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
@ -358,6 +358,64 @@ class kolab_files_engine
$this->rc->output->command('files_list_update', $head);
}
/**
* Template object for file info box
*/
public function file_info_box($attrib)
{
// print_r($this->file_data, true);
$table = new html_table(array('cols' => 2, 'class' => $attrib['class']));
// file name
$table->add('label', $this->plugin->gettext('name').':');
$table->add('data filename', $this->file_data['name']);
// file type
// @TODO: human-readable type name
$table->add('label', $this->plugin->gettext('type').':');
$table->add('data filetype', $this->file_data['type']);
// file size
$table->add('label', $this->plugin->gettext('size').':');
$table->add('data filesize', $this->rc->show_bytes($this->file_data['size']));
// file modification time
$table->add('label', $this->plugin->gettext('mtime').':');
$table->add('data filemtime', $this->file_data['mtime']);
// @TODO: for images: width, height, color depth, etc.
// @TODO: for text files: count of characters, lines, words
return $table->show();
}
/**
* Template object for file preview frame
*/
public function file_preview_frame($attrib)
{
if (empty($attrib['id'])) {
$attrib['id'] = 'filepreviewframe';
}
if ($frame = $this->file_data['viewer']['frame']) {
return $frame;
}
if ($href = $this->file_data['viewer']['href']) {
}
else {
$token = $this->get_api_token();
$href = $this->url . '/api/?method=file_get'
. '&file=' . urlencode($this->file_data['filename'])
. '&token=' . urlencode($token);
}
$this->rc->output->add_gui_object('preview_frame', $attrib['id']);
return html::iframe(array('id' => 'file-content', 'src' => $href));
}
/**
* Get API token for current user session, authenticate if needed
*/
@ -421,7 +479,7 @@ class kolab_files_engine
/**
* Initialize HTTP_Request object
*/
protected function get_request()
protected function get_request($get = null, $token = null)
{
$url = $this->url . '/api/';
@ -441,23 +499,37 @@ class kolab_files_engine
catch (Exception $e) {
rcube::raise_error($e, true, true);
}
// proxy User-Agent string
$this->request->setHeader('user-agent', $_SERVER['HTTP_USER_AGENT']);
}
if ($this->request) {
// cleanup
try {
$this->request->setBody('');
$this->request->setUrl($url);
$this->request->setMethod(HTTP_Request2::METHOD_GET);
}
catch (Exception $e) {
rcube::raise_error($e, true, true);
}
// cleanup
try {
$this->request->setBody('');
$this->request->setUrl($url);
$this->request->setMethod(HTTP_Request2::METHOD_GET);
}
catch (Exception $e) {
rcube::raise_error($e, true, true);
}
if ($token) {
$this->request->setHeader('X-Session-Token', $token);
}
if (!empty($get)) {
$url = $this->request->getUrl();
$url->setQueryVariables($get);
$this->request->setUrl($url);
}
return $this->request;
}
/**
* Handler for main files interface (Files task)
*/
protected function action_index()
{
$this->plugin->add_label(
@ -469,6 +541,7 @@ class kolab_files_engine
);
$this->rc->output->set_pagetitle($this->plugin->gettext('files'));
$this->rc->output->set_env('file_mimetypes', $this->get_mimetypes());
$this->rc->output->send('kolab_files.files');
}
@ -510,6 +583,60 @@ class kolab_files_engine
$this->rc->output->send();
}
/**
* Handler for file open action
*/
protected function action_open()
{
$file = rcube_utils::get_input_value('file', rcube_utils::INPUT_GET);
// get file info
$token = $this->get_api_token();
$request = $this->get_request(array(
'method' => 'file_info',
'file' => $file,
'viewer' => !empty($_GET['viewer']),
), $token);
// send request to the API
try {
$response = $request->send();
$status = $response->getStatus();
$body = @json_decode($response->getBody(), true);
if ($status == 200 && $body['status'] == 'OK') {
$this->file_data = $body['result'];
}
else {
throw new Exception($body['reason']);
}
}
catch (Exception $e) {
rcube::raise_error(array(
'code' => 500, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
'message' => $e->getMessage()),
true, true);
}
$this->file_data['filename'] = $file;
$this->plugin->add_label('filedeleteconfirm', 'filedeleting', 'filedeletenotice');
// this one is for styling purpose
$this->rc->output->set_env('extwin', true);
// register template objects for dialogs (and main interface)
$this->rc->output->add_handlers(array(
'fileinfobox' => array($this, 'file_info_box'),
'filepreviewframe' => array($this, 'file_preview_frame'),
));
$this->rc->output->set_env('file', $file);
$this->rc->output->set_env('file_data', $this->file_data);
$this->rc->output->set_pagetitle(rcube::Q($file));
$this->rc->output->send('kolab_files.filepreview');
}
/**
* Handler for "save all attachments into cloud" action
*/
@ -759,4 +886,35 @@ class kolab_files_engine
$this->rc->output->command('auto_save_start', false);
$this->rc->output->send();
}
/**
* Returns mimetypes supported by File API viewers
*/
protected function get_mimetypes()
{
$token = $this->get_api_token();
$request = $this->get_request(array('method' => 'mimetypes'), $token);
// send request to the API
try {
$response = $request->send();
$status = $response->getStatus();
$body = @json_decode($response->getBody(), true);
if ($status == 200 && $body['status'] == 'OK') {
$mimetypes = $body['result'];
}
else {
throw new Exception($body['reason']);
}
}
catch (Exception $e) {
rcube::raise_error(array(
'code' => 500, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
'message' => $e->getMessage()),
true, false);
}
return $mimetypes;
}
}

View file

@ -18,6 +18,7 @@ $labels['folderinside'] = 'Insert inside';
$labels['foldername'] = 'Folder name';
$labels['name'] = 'Name';
$labels['mtime'] = 'Modified';
$labels['type'] = 'Type';
$labels['upload'] = 'Upload';
$labels['uploadfile'] = 'Upload file(s)';

View file

@ -34,7 +34,7 @@
background-position: center -94px;
}
#filestoolbar a.button.view {
#filestoolbar a.button.open {
background-position: center -131px;
}
@ -52,7 +52,8 @@
left: 6px;
}
#folderlistbox {
#folderlistbox,
#fileinfobox {
position: absolute;
top: 42px;
left: 0;
@ -60,7 +61,8 @@
bottom: 0;
}
#filelistcontainer {
#filelistcontainer,
#filecontent {
position: absolute;
top: 42px;
left: 232px;
@ -78,6 +80,17 @@
width: 100%;
}
#filecontent {
overflow: hidden;
}
#filecontent iframe {
width: 100%;
height: 100%;
margin: 0;
border: 0;
}
#files-folder-list ul li span.name {
background: url(../../../../skins/larry/images/listicons.png) 6px 3px no-repeat;
padding: 6px 8px 2px 32px;
@ -218,6 +231,19 @@
}
*/
#fileinfobox table td.label {
width: 1%;
font-weight: bold;
padding-right: 0;
}
#fileinfobox table td.data.filename {
font-weight: bold;
}
#fileinfobox table tr:first-child td {
border-top: 0;
}
/* plugin dialogs */

View file

@ -0,0 +1,42 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
<script src="plugins/kolab_files/skins/larry/ui.js" type="text/javascript"></script>
</head>
<body class="files noscroll extwin">
<roundcube:include file="/includes/header.html" />
<div id="mainscreen">
<div id="filestoolbar" class="toolbar">
<roundcube:button command="files-get" type="link" class="button get disabled" classAct="button get" classSel="button get pressed" label="kolab_files.get" title="kolab_files.getfile" />
<!--
<roundcube:button command="files-edit" type="link" class="button edit disabled" classAct="button edit" classSel="button edit pressed" label="kolab_files.edit" title="kolab_files.editfile" />
-->
<roundcube:button command="files-delete" type="link" class="button delete disabled" classAct="button delete" classSel="button delete pressed" label="delete" title="kolab_files.deletefile" />
</div>
<div id="fileinfobox" class="uibox listbox">
<roundcube:object name="fileinfobox" id="fileinfo" class="listing" />
</div>
<div id="filecontent" class="uibox">
<div class="iframebox">
<roundcube:object name="filepreviewframe" id="fileframe" frameborder="0" />
</div>
<roundcube:object name="message" id="message" class="statusbar" />
</div>
</div>
<roundcube:include file="/includes/footer.html" />
<script type="text/javascript">
kolab_files_ui_init();
</script>
</body>
</html>

View file

@ -16,7 +16,7 @@
<roundcube:button command="files-upload" type="link" class="button upload disabled" classAct="button upload" classSel="button upload pressed" label="kolab_files.upload" title="kolab_files.uploadfile" />
</form>
<roundcube:button command="files-get" type="link" class="button get disabled" classAct="button get" classSel="button get pressed" label="kolab_files.get" title="kolab_files.getfile" />
<roundcube:button command="files-view" type="link" class="button view disabled" classAct="button view" classSel="button delete pressed" label="kolab_files.view" title="kolab_files.viewfile" />
<roundcube:button command="files-open" type="link" class="button open disabled" classAct="button open" classSel="button open pressed" label="kolab_files.view" title="kolab_files.viewfile" />
<roundcube:button command="files-delete" type="link" class="button delete disabled" classAct="button delete" classSel="button delete pressed" label="delete" title="kolab_files.deletefile" />
</div>

View file

@ -1,7 +1,11 @@
function kolab_files_ui_init()
{
var filesviewsplit = new rcube_splitter({ id:'filesviewsplitter', p1:'#folderlistbox', p2:'#filelistcontainer',
orientation:'v', relative:true, start:226, min:150, size:12 }).init();
if (rcmail.env.action == 'open')
var filesviewsplit = new rcube_splitter({ id:'filesopensplitter', p1:'#fileinfobox', p2:'#filecontent',
orientation:'v', relative:true, start:226, min:150, size:12 }).init();
else
var filesviewsplit = new rcube_splitter({ id:'filesviewsplitter', p1:'#folderlistbox', p2:'#filelistcontainer',
orientation:'v', relative:true, start:226, min:150, size:12 }).init();
$(document).ready(function() {
rcmail.addEventListener('menu-open', kolab_files_show_listoptions);