diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js index 097e038a..fde61886 100644 --- a/plugins/kolab_files/kolab_files.js +++ b/plugins/kolab_files/kolab_files.js @@ -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 = $('') .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); + }; }; diff --git a/plugins/kolab_files/kolab_files.php b/plugins/kolab_files/kolab_files.php index bbd410cb..27500633 100644 --- a/plugins/kolab_files/kolab_files.php +++ b/plugins/kolab_files/kolab_files.php @@ -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(); } diff --git a/plugins/kolab_files/lib/kolab_files_engine.php b/plugins/kolab_files/lib/kolab_files_engine.php index 4e42c82a..f8b1bb86 100644 --- a/plugins/kolab_files/lib/kolab_files_engine.php +++ b/plugins/kolab_files/lib/kolab_files_engine.php @@ -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; + } } diff --git a/plugins/kolab_files/localization/en_US.inc b/plugins/kolab_files/localization/en_US.inc index 1b6eb819..96c49bf9 100644 --- a/plugins/kolab_files/localization/en_US.inc +++ b/plugins/kolab_files/localization/en_US.inc @@ -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)'; diff --git a/plugins/kolab_files/skins/larry/style.css b/plugins/kolab_files/skins/larry/style.css index fcaaea6e..06ff3e13 100644 --- a/plugins/kolab_files/skins/larry/style.css +++ b/plugins/kolab_files/skins/larry/style.css @@ -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 */ diff --git a/plugins/kolab_files/skins/larry/templates/filepreview.html b/plugins/kolab_files/skins/larry/templates/filepreview.html new file mode 100644 index 00000000..416cbc74 --- /dev/null +++ b/plugins/kolab_files/skins/larry/templates/filepreview.html @@ -0,0 +1,42 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + +
+ +
+ + + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ + + + + + diff --git a/plugins/kolab_files/skins/larry/templates/files.html b/plugins/kolab_files/skins/larry/templates/files.html index ba52300d..13f6619d 100644 --- a/plugins/kolab_files/skins/larry/templates/files.html +++ b/plugins/kolab_files/skins/larry/templates/files.html @@ -16,7 +16,7 @@ - + diff --git a/plugins/kolab_files/skins/larry/ui.js b/plugins/kolab_files/skins/larry/ui.js index fda15c84..954e5b54 100644 --- a/plugins/kolab_files/skins/larry/ui.js +++ b/plugins/kolab_files/skins/larry/ui.js @@ -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);