forked from extern/egroupware
W.I.P collab Editor:
- Implement user access to a document - Implement leave session mechanism for user - Implement single document network for an user (user be able to open a doc multiple times from same or other instances and get them all synced)
This commit is contained in:
parent
94bc949cfa
commit
307e59e7ab
@ -40,16 +40,37 @@ class filemanager_collab extends filemanager_collab_bo {
|
||||
*/
|
||||
function join_session ($es_id)
|
||||
{
|
||||
$response = $this->initSession($es_id);
|
||||
$paths = explode('/webdav.php', $es_id);
|
||||
if (Api\Vfs::check_access($paths[1], Api\Vfs::READABLE))
|
||||
{
|
||||
$response = $this->initSession($es_id);
|
||||
$response['success'] = true;
|
||||
}
|
||||
$response += array (
|
||||
'id' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
'full_name' => $GLOBALS['egw_info']['user']['account_fullname'],
|
||||
'success' => true
|
||||
'full_name' => $GLOBALS['egw_info']['user']['account_fullname']
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function gets called when user leaves the session
|
||||
*
|
||||
* @param string $es_id
|
||||
* @param string $member_id
|
||||
*
|
||||
* @return array returns an array of data as response for client-side
|
||||
*/
|
||||
function leave_session ($es_id, $member_id)
|
||||
{
|
||||
return array (
|
||||
'session_id' => $es_id,
|
||||
'memberid' => $member_id,
|
||||
'success' => $this->OP_removeMember($es_id, $member_id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling mechanisim to sysncronise data
|
||||
*
|
||||
@ -63,11 +84,15 @@ class filemanager_collab extends filemanager_collab_bo {
|
||||
$response = array();
|
||||
if (is_array($params))
|
||||
{
|
||||
$paths = explode('/webdav.php', $params['args']['es_id']);
|
||||
switch ($params['command'])
|
||||
{
|
||||
case 'join_session':
|
||||
$response = $this->join_session($params['args']['es_id'],$params['args']['user_id']);
|
||||
break;
|
||||
case 'leave_session':
|
||||
$response = $this->leave_session($params['args']['es_id'],$params['args']['member_id']);
|
||||
break;
|
||||
case 'sync_ops':
|
||||
try
|
||||
{
|
||||
@ -78,7 +103,7 @@ class filemanager_collab extends filemanager_collab_bo {
|
||||
{
|
||||
$client_ops = $params['args']['client_ops']? $params['args']['client_ops']: [];
|
||||
$current_seq_head = $this->OP_getHeadSeq($es_id);
|
||||
if ($seq_head == $current_seq_head) {
|
||||
if ($seq_head == $current_seq_head && $this->is_collabAllowed($es_id)) {
|
||||
|
||||
if (count($client_ops)>0)
|
||||
{
|
||||
@ -141,4 +166,26 @@ class filemanager_collab extends filemanager_collab_bo {
|
||||
return $this->OP_getHeadSeq($es_id);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type $es_id
|
||||
* @param type $action
|
||||
*/
|
||||
function ajax_actions ($es_id, $action)
|
||||
{
|
||||
switch ($action)
|
||||
{
|
||||
case 'save':
|
||||
$this->SESSION_Save($es_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function is_collabAllowed ($es_id)
|
||||
{
|
||||
$paths = explode('/webdav.php', $es_id);
|
||||
$allowed = Api\Vfs::check_access($paths[1], Api\Vfs::WRITABLE) &&
|
||||
!preg_match('/\/api\/js\/webodf\/template.odf$/', $es_id);
|
||||
return $allowed;
|
||||
}
|
||||
}
|
@ -80,14 +80,12 @@ class filemanager_collab_bo
|
||||
$result = self::db2id($this->SESSION_add2Db($es_id));
|
||||
}
|
||||
|
||||
if (is_null($result['member_id'] = $this->MEMBER_getUserMemberId($es_id, $user_id)))
|
||||
{
|
||||
$this->MEMBER_add2Db($es_id, $user_id, $color);
|
||||
|
||||
$result['member_id'] = $this->MEMBER_getLastMember();
|
||||
$this->MEMBER_add2Db($es_id, $user_id, $color);
|
||||
|
||||
$this->OP_addMember($es_id, $result['member_id'], $full_name, $user_id, $color, $imageUrl);
|
||||
}
|
||||
$result['member_id'] = $this->MEMBER_getLastMember();
|
||||
|
||||
$this->OP_addMember($es_id, $result['member_id'], $full_name, $user_id, $color, $imageUrl);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@ -212,6 +210,24 @@ class filemanager_collab_bo
|
||||
$this->OP_add2Db($op, $es_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to remove member from list
|
||||
*
|
||||
* @param string $es_id session id
|
||||
* @param string $member_id membe id
|
||||
*
|
||||
* @return boolean returns true if remove member is successful otherwise false
|
||||
*/
|
||||
function OP_removeMember ($es_id, $member_id)
|
||||
{
|
||||
$op = array (
|
||||
'optype' => 'RemoveMember',
|
||||
'memberid' => (string) $member_id,
|
||||
'timestamp' => self::getTimeStamp()
|
||||
);
|
||||
return $this->OP_add2Db($op, $es_id)?true:false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get top head seq for a given session
|
||||
*
|
||||
@ -302,7 +318,7 @@ class filemanager_collab_bo
|
||||
'collab_optype' => $op['optype'],
|
||||
'collab_opspec' => json_encode($op)
|
||||
);
|
||||
$this->db->insert(self::OP_TABLE, $data,false,__LINE__, __FILE__,'filemanager');
|
||||
return $this->db->insert(self::OP_TABLE, $data,false,__LINE__, __FILE__,'filemanager');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -344,6 +360,30 @@ class filemanager_collab_bo
|
||||
return is_array($member)? $member['collab_member_id']: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get member record of specific member id
|
||||
*
|
||||
* @param string $member_id member id
|
||||
*
|
||||
* @return string member id or null
|
||||
* @throws Exception throws exception if no member id is given
|
||||
*/
|
||||
protected function MEMBER_getUserLastMemberId ($es_id, $user_id)
|
||||
{
|
||||
if (!$es_id || !$user_id) throw new Exception (self::EXCEPTION_MESSAGE_NO_SESSION);
|
||||
$query = $this->db->select(
|
||||
self::MEMBER_TABLE,
|
||||
'collab_member_id',
|
||||
array('collab_es_id' => $es_id, 'collab_uid' => $user_id),
|
||||
__LINE__,
|
||||
__FILE__,
|
||||
false,
|
||||
"ORDER BY `collab_member_id` DESC LIMIT 1;"
|
||||
);
|
||||
$member = $query->fetchRow();
|
||||
return is_array($member)? $member['collab_member_id']: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to map DB fields to ids
|
||||
*
|
||||
|
@ -17,7 +17,7 @@ use EGroupware\Api\Egw;
|
||||
use EGroupware\Api\Etemplate;
|
||||
|
||||
use EGroupware\Api\Vfs;
|
||||
use filemanager_collab_bo;
|
||||
|
||||
/**
|
||||
* Filemanage user interface class
|
||||
*/
|
||||
@ -1485,14 +1485,21 @@ class filemanager_ui
|
||||
{
|
||||
$tmpl = new Etemplate('filemanager.editor');
|
||||
$file_path = $_GET['path'];
|
||||
$paths = explode('/webdav.php', $file_path);
|
||||
// Include css files used by wodocollabeditor
|
||||
Api\Framework::includeCSS('/api/js/webodf/collab/app/resources/app.css');
|
||||
Api\Framework::includeCSS('/api/js/webodf/collab/wodocollabpane.css');
|
||||
Api\Framework::includeCSS('/api/js/webodf/collab/wodotexteditor.css');
|
||||
Api\Framework::includeJS('/filemanager/js/collab.js',null, 'filemanager');
|
||||
|
||||
$tmpl->setElementAttribute('tools', 'actions', self::getActions_edit());
|
||||
$preserve = $content = array('file_path' => $file_path);
|
||||
$actions = self::getActions_edit();
|
||||
if (!Api\Vfs::check_access($paths[1], Api\Vfs::WRITABLE))
|
||||
{
|
||||
unset ($actions['save']);
|
||||
unset ($actions['delete']);
|
||||
}
|
||||
$tmpl->setElementAttribute('tools', 'actions', $actions);
|
||||
$preserve = $content = array('file_path' => $file_path);
|
||||
$tmpl->exec('filemanager.filemanager_ui.editor',$content,array(),array(),$preserve,2);
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1016,7 @@ app.classes.filemanager = AppJS.extend(
|
||||
*
|
||||
* @todo: creating new empty odt file
|
||||
*/
|
||||
list_editor_new: function (_egwAction) {
|
||||
editor_new: function (_egwAction) {
|
||||
var self = this,
|
||||
template_url = '/api/js/webodf/template.odt';
|
||||
egw.open_link(egw.link('/index.php', {
|
||||
|
@ -8,6 +8,7 @@
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/*egw:uses
|
||||
/filemanager/js/collab_config.js;
|
||||
/api/js/webodf/collab/dojo-amalgamation.js;
|
||||
@ -23,12 +24,20 @@
|
||||
*/
|
||||
app.classes.filemanager = app.classes.filemanager.extend({
|
||||
/*
|
||||
* odf editor object
|
||||
* @var editor odf editor object
|
||||
*/
|
||||
editor: {},
|
||||
|
||||
/**
|
||||
* @var regexp for acceptable mime types
|
||||
*/
|
||||
editor_mime: RegExp(/application\/vnd\.oasis\.opendocument\.text/),
|
||||
|
||||
/**
|
||||
* @var collab_server server object
|
||||
*/
|
||||
collab_server: {},
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
@ -36,6 +45,7 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
{
|
||||
delete this.editor;
|
||||
delete editor_mime;
|
||||
delete collab_server;
|
||||
// call parent
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
@ -58,7 +68,7 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
// need to make body rock solid to avoid extra scrollbars
|
||||
jQuery('body').css({overflow:'hidden'});
|
||||
var self = this;
|
||||
jQuery(window).on('unload', function(){self.editor.leaveSession()});
|
||||
jQuery(window).on('unload', function(){self.editor_leaveSession()});
|
||||
this._init_odf_collab_editor ();
|
||||
}
|
||||
},
|
||||
@ -136,6 +146,16 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Function to leave the current editing session
|
||||
* and as result it will call client-side and server leave session.
|
||||
*/
|
||||
editor_leaveSession: function ()
|
||||
{
|
||||
this.editor.leaveSession(function(){});
|
||||
this.collab_server.server.leaveSession(this.collab_server.es_id, this.collab_server.memberid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to close an opened document
|
||||
*
|
||||
@ -151,7 +171,7 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
{
|
||||
var closeFn = function ()
|
||||
{
|
||||
self.editor.leaveSession(function(){});
|
||||
self.editor_leaveSession();
|
||||
if (action != 'new')
|
||||
{
|
||||
window.close();
|
||||
@ -184,33 +204,6 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to create a new document
|
||||
* @param {object} _egwAction egw action object
|
||||
*
|
||||
* @todo: creating new empty odt file
|
||||
*/
|
||||
editor_new: function (_egwAction) {
|
||||
var self = this,
|
||||
template_url = '/api/js/webodf/template.odt';
|
||||
|
||||
if (Object.keys(this.editor).length > 0)
|
||||
{
|
||||
this.editor_close(_egwAction, function(){
|
||||
|
||||
// TODO create new temp file
|
||||
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
egw.open_link(egw.link('/index.php', {
|
||||
menuaction: 'filemanager.filemanager_ui.editor',
|
||||
path: template_url
|
||||
}), '', egw.link_get_registry('filemanager','view_popup'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method call for saving edited document
|
||||
*
|
||||
@ -239,6 +232,7 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
success: function(data) {
|
||||
egw(window).message(egw.lang('Document %1 successfully has been saved.', filename[1]));
|
||||
self.editor.setDocumentModified(false);
|
||||
egw.json('filemanager.filemanager_collab.ajax_actions',[self.editor_getSessionId(), 'save']).sendRequest();
|
||||
},
|
||||
error: function () {},
|
||||
data: blob,
|
||||
@ -270,7 +264,7 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
// Add odt extension if not exist
|
||||
if (!file_path.match(/\.odt$/,'ig')) file_path += '.odt';
|
||||
widgetFilePath.set_value(file_path);
|
||||
self.editor.leaveSession(function(){});
|
||||
self.editor_leaveSession();
|
||||
self.editor.getDocumentAsByteArray(saveByteArrayLocally);
|
||||
self._init_odf_collab_editor();
|
||||
egw.refresh('','filemanager');
|
||||
@ -429,8 +423,12 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
function joinSession(_sessionId)
|
||||
{
|
||||
var sid = _sessionId;
|
||||
|
||||
server.joinSession(userId, sid, function (_memberId) {
|
||||
memberId = _memberId;
|
||||
// Set server object for current session
|
||||
self.collab_server = {server:server, memberid: memberId, es_id: sid};
|
||||
|
||||
if (Object.keys(self.editor).length == 0) {
|
||||
Wodo.createCollabTextEditor('filemanager-editor_odfEditor', editorOptions, onEditorCreated);
|
||||
} else {
|
||||
@ -459,6 +457,5 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
<buttononly statustext="Tile view" id="button[change_view]" onclick="app.filemanager.change_view" image="list_tile" background_image="true"/>
|
||||
</template>
|
||||
<template id="filemanager.index.header_right" template="" lang="" group="0" version="1.9.003">
|
||||
<buttononly statustext="Create new open document file" id="button[new_doc]" onclick="app.filemanager.list_editor_new();" image="new" background_image="true"/>
|
||||
<buttononly statustext="Create new open document file" id="button[new_doc]" onclick="app.filemanager.editor_new();" image="new" background_image="true"/>
|
||||
<buttononly statustext="Rename, change permissions or ownership" id="button[edit]" onclick="app.filemanager.editprefs();" image="edit" background_image="true"/>
|
||||
<buttononly statustext="Create directory" id="button[createdir]" onclick="app.filemanager.createdir();" image="button_createdir" ro_image="createdir_disabled" background_image="true"/>
|
||||
<buttononly statustext="Create a link" id="button[symlink]" onclick="app.filemanager.symlink();" image="link" ro_image="link_disabled" background_image="true"/>
|
||||
|
Loading…
Reference in New Issue
Block a user