plugins/kolab_files

Aleksander Machniak machniak at kolabsys.com
Sun May 19 12:45:40 CEST 2013


 plugins/kolab_files/kolab_files.js                         |   76 ++++-
 plugins/kolab_files/kolab_files.php                        |    1 
 plugins/kolab_files/lib/kolab_files_engine.php             |  182 ++++++++++++-
 plugins/kolab_files/localization/en_US.inc                 |    1 
 plugins/kolab_files/skins/larry/style.css                  |   32 ++
 plugins/kolab_files/skins/larry/templates/filepreview.html |   42 +++
 plugins/kolab_files/skins/larry/templates/files.html       |    2 
 plugins/kolab_files/skins/larry/ui.js                      |    8 
 8 files changed, 319 insertions(+), 25 deletions(-)

New commits:
commit 76a43e5c38a9adc5bbc72a53c7b2d3f3846b4a2f
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Sun May 19 12:45:19 2013 +0200

    Implemented file preview using API viewers

diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js
index 097e038..fde6188 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 = $('<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);
+  };
 };
diff --git a/plugins/kolab_files/kolab_files.php b/plugins/kolab_files/kolab_files.php
index bbd410c..2750063 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 4e42c82..f8b1bb8 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']);
@@ -359,6 +359,64 @@ class kolab_files_engine
     }
 
     /**
+     * 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
      */
     public function get_api_token()
@@ -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');
     }
 
@@ -511,6 +584,60 @@ class kolab_files_engine
     }
 
     /**
+     * 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
      */
     protected function action_save_file()
@@ -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 1b6eb81..96c49bf 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 fcaaea6..06ff3e1 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 0000000..416cbc7
--- /dev/null
+++ b/plugins/kolab_files/skins/larry/templates/filepreview.html
@@ -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>
diff --git a/plugins/kolab_files/skins/larry/templates/files.html b/plugins/kolab_files/skins/larry/templates/files.html
index ba52300..13f6619 100644
--- a/plugins/kolab_files/skins/larry/templates/files.html
+++ b/plugins/kolab_files/skins/larry/templates/files.html
@@ -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>
 
diff --git a/plugins/kolab_files/skins/larry/ui.js b/plugins/kolab_files/skins/larry/ui.js
index fda15c8..954e5b5 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);





More information about the commits mailing list