2016-08-16 12:47:00 +02:00
/ * *
* EGroupware - Filemanager - Collab editor application object
*
* @ link http : //www.egroupware.org
* @ package filemanager
* @ author Hadi Nategh < hn - AT - stylite . de >
* @ copyright ( c ) 2016 Stylite AG
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ version $Id$
* /
2016-08-17 17:23:22 +02:00
2016-08-16 12:47:00 +02:00
/ * e g w : u s e s
/ f i l e m a n a g e r / j s / c o l l a b _ c o n f i g . j s ;
/ a p i / j s / w e b o d f / c o l l a b / d o j o - a m a l g a m a t i o n . j s ;
/ a p i / j s / w e b o d f / c o l l a b / w e b o d f . j s ;
/ a p i / j s / w e b o d f / c o l l a b / w o d o c o l l a b t e x t e d i t o r . j s ;
/ f i l e m a n a g e r / j s / a p p . j s ;
* /
/ * *
* UI for filemanager collab
*
* @ augments AppJS
* /
app . classes . filemanager = app . classes . filemanager . extend ( {
/ *
2016-08-17 17:23:22 +02:00
* @ var editor odf editor object
2016-08-16 12:47:00 +02:00
* /
editor : { } ,
2016-08-17 17:23:22 +02:00
/ * *
* @ var regexp for acceptable mime types
* /
2016-08-16 12:47:00 +02:00
editor _mime : RegExp ( /application\/vnd\.oasis\.opendocument\.text/ ) ,
2016-08-17 17:23:22 +02:00
/ * *
* @ var collab _server server object
* /
collab _server : { } ,
2016-08-16 12:47:00 +02:00
/ * *
* Destructor
* /
destroy : function ( )
{
delete this . editor ;
delete editor _mime ;
2016-08-17 17:23:22 +02:00
delete collab _server ;
2016-08-16 12:47:00 +02:00
// call parent
this . _super . apply ( this , arguments ) ;
} ,
/ * *
* This function is called when the etemplate2 object is loaded
* and ready . If you must store a reference to the et2 object ,
* make sure to clean it up in destroy ( ) .
*
* @ param et2 etemplate2 Newly ready object
* @ param { string } name template name
* /
et2 _ready : function ( et2 , name )
{
// call parent
this . _super . apply ( this , arguments ) ;
if ( name == "filemanager.editor" )
{
// need to make body rock solid to avoid extra scrollbars
jQuery ( 'body' ) . css ( { overflow : 'hidden' } ) ;
var self = this ;
2016-08-17 17:23:22 +02:00
jQuery ( window ) . on ( 'unload' , function ( ) { self . editor _leaveSession ( ) } ) ;
2016-08-16 12:47:00 +02:00
this . _init _odf _collab _editor ( ) ;
}
} ,
/ * *
* Initiate odf editor popup & load given file _path
*
* /
_init _odf _editor : function ( )
{
var widgetFilePath = this . et2 . getWidgetById ( 'file_path' ) ,
file _path = widgetFilePath . value ,
isNew = file _path == '/api/js/webodf/template.odt' ? true : false ,
self = this ;
var onEditorCreated = function ( err , editor )
{
if ( err )
{
console . log ( 'Something went wrong whilst loading editor.' + err ) ;
return ;
}
self . editor = editor ;
self . editor . openDocumentFromUrl ( egw . webserverUrl + file _path ) ;
if ( isNew ) {
widgetFilePath . set _value ( '' ) ;
}
} ;
var editorOptions = {
allFeaturesEnabled : true ,
userData : {
fullName : egw . user ( 'account_fullName' ) ,
color : 'blue'
}
} ;
var editor = this . et2 . getWidgetById ( 'odfEditor' ) ;
if ( editor )
{
Wodo . createTextEditor ( 'filemanager-editor_odfEditor' , editorOptions , onEditorCreated ) ;
}
} ,
/ * *
* Initiate odf collab editor popup & load given file _path as active session
* /
_init _odf _collab _editor : function ( )
{
2016-08-19 16:38:44 +02:00
var self = this ;
egw . json ( 'filemanager.filemanager_collab.ajax_getGenesisUrl' , [ this . editor _getFilePath ( ) ] , function ( _data ) {
var serverOptions = {
serverParams : {
url : egw . link ( '/index.php?' , {
menuaction : 'filemanager.filemanager_collab.poll'
} ) ,
genesisUrl : _data . genesis _url
} ,
sessionId : _data . es _id ,
editorOptions : {
allFeaturesEnabled : true ,
userData : {
fullName : egw . user ( 'account_fullName' ) ,
color : 'blue'
}
2016-08-16 12:47:00 +02:00
}
2016-08-19 16:38:44 +02:00
} ;
var editor = self . et2 . getWidgetById ( 'odfEditor' ) ;
if ( editor )
{
self . create _collab _editor ( serverOptions ) ;
2016-08-16 12:47:00 +02:00
}
2016-08-19 16:38:44 +02:00
} ) . sendRequest ( ) ;
2016-08-16 12:47:00 +02:00
} ,
2016-08-17 17:23:22 +02:00
/ * *
* Function to leave the current editing session
* and as result it will call client - side and server leave session .
2016-08-19 16:38:44 +02:00
*
* @ param { function } _successCallback function to gets called after leave session is successful
2016-08-17 17:23:22 +02:00
* /
2016-08-19 16:38:44 +02:00
editor _leaveSession : function ( _successCallback )
2016-08-17 17:23:22 +02:00
{
this . editor . leaveSession ( function ( ) { } ) ;
2016-08-19 16:38:44 +02:00
this . collab _server . server . leaveSession ( this . collab _server . es _id , this . collab _server . memberid , _successCallback ) ;
2016-08-17 17:23:22 +02:00
} ,
2016-08-16 12:47:00 +02:00
/ * *
* Method to close an opened document
*
* @ param { object } _egwAction egw action object
* @ param { function } _callback callback function gets called after close operation
* /
editor _close : function ( _egwAction , _callback ) {
var self = this ,
action = _egwAction . id ,
callback = _callback ;
if ( this . editor )
{
var closeFn = function ( )
{
2016-08-17 17:23:22 +02:00
self . editor _leaveSession ( ) ;
2016-08-16 12:47:00 +02:00
if ( action != 'new' )
{
window . close ( ) ;
}
callback . call ( this ) ;
} ;
// warn user about unsaved changes
if ( this . editor . isDocumentModified ( ) )
{
et2 _dialog . show _dialog (
function ( _btn )
{
if ( _btn == 2 )
{
closeFn ( ) ;
}
} ,
'There are unsaved changes. Are you sure you want to close this document without saving them?' ,
'unsaved changes' ,
null ,
et2 _dialog . BUTTONS _YES _NO ,
et2 _dialog . WARNING _MESSAGE
) ;
}
else
{
closeFn ( ) ;
}
}
} ,
/ * *
* Method call for saving edited document
*
* @ param { object } _egwAction egw action object
* /
editor _save : function ( _egwAction ) {
var self = this ,
widgetFilePath = this . et2 . getWidgetById ( 'file_path' ) ,
file _path = widgetFilePath . value ;
if ( this . editor )
{
function saveByteArrayLocally ( err , data ) {
if ( err ) {
alert ( err ) ;
return ;
}
var filename = file _path . split ( '/webdav.php' ) ,
blob = new Blob ( [ data . buffer ] , { type : self . editor _mime } ) ;
self . editor _file _operation ( {
url : egw . webserverUrl + file _path ,
method : 'PUT' ,
processData : false ,
success : function ( data ) {
egw ( window ) . message ( egw . lang ( 'Document %1 successfully has been saved.' , filename [ 1 ] ) ) ;
self . editor . setDocumentModified ( false ) ;
2016-08-19 17:59:44 +02:00
egw . json ( 'filemanager.filemanager_collab.ajax_actions' , [ self . collab _server . es _id , 'save' ] ) . sendRequest ( ) ;
2016-08-16 12:47:00 +02:00
} ,
error : function ( ) { } ,
data : blob ,
mimeType : self . editor _mime
} ) ;
}
//existed file
if ( file _path != '' && _egwAction . id != 'saveas' ) {
this . editor . getDocumentAsByteArray ( saveByteArrayLocally ) ;
}
// new file
else
{
// create file selector
var vfs _select = et2 _createWidget ( 'vfs-select' , {
id : 'savefile' ,
mode : 'saveas' ,
button _caption : "" ,
button _label : _egwAction . id == 'saveas' ? "save as" : "save" ,
value : "doc.odt"
} , this . et2 ) ;
// bind change handler for setting the selected path and calling save
jQuery ( vfs _select . getDOMNode ( ) ) . on ( 'change' , function ( ) {
file _path = '/webdav.php' + vfs _select . get _value ( ) ;
if ( vfs _select . get _value ( ) )
{
// Add odt extension if not exist
if ( ! file _path . match ( /\.odt$/ , 'ig' ) ) file _path += '.odt' ;
widgetFilePath . set _value ( file _path ) ;
self . editor . getDocumentAsByteArray ( saveByteArrayLocally ) ;
2016-08-19 16:38:44 +02:00
self . editor _leaveSession ( function ( ) {
self . _init _odf _collab _editor ( ) ;
} ) ;
2016-08-16 12:47:00 +02:00
egw . refresh ( '' , 'filemanager' ) ;
}
} ) ;
// start the file selector dialog
jQuery ( vfs _select . getDOMNode ( ) ) . click ( ) ;
}
}
} ,
/ * *
* Method to delete loaded file in editor
* @ param { type } _egwAction
* /
editor _delete : function ( _egwAction ) {
var fullpath = this . et2 . getWidgetById ( 'file_path' ) . value ;
fullpath = fullpath . split ( '/webdav.php' ) [ 1 ] ;
var selected = fullpath . split ( '/' ) ;
selected . pop ( ) ;
var path = selected . join ( '/' ) ;
var self = this ;
et2 _dialog . show _dialog (
function ( _btn )
{
if ( _btn == 2 )
{
2016-08-22 13:05:47 +02:00
self . _do _action ( 'delete' , [ fullpath , path + '/.' + self . collab _server . es _id + '.webodf.odt' ] , false , path ) ;
2016-08-16 12:47:00 +02:00
self . editor _close ( _egwAction ) ;
}
} ,
egw . lang ( 'Delete file %1?' , path ) ,
'Delete file' ,
null ,
et2 _dialog . BUTTONS _YES _NO ,
et2 _dialog . WARNING _MESSAGE
) ;
} ,
/ * *
* Function to handle file operations ( PGD ) for editor
*
* @ param { object } _params jquery ajax parameters
* /
editor _file _operation : function ( _params )
{
var ajaxObj = {
url : egw . webserverUrl + '/webdav.php?/home/' + egw . user ( 'account_lid' ) + '/default.odt'
} ;
jQuery . extend ( ajaxObj , _params ) ;
switch ( ajaxObj && ajaxObj . cmd )
{
case 'PUT' :
jQuery . extend ( { } , ajaxObj , {
data : JSON . stringify ( ajaxObj . data ) ,
contentType : 'application/json'
} ) ;
break ;
case 'GET' :
jQuery . extend ( { } , ajaxObj , {
dataType : 'json'
} ) ;
break ;
case 'DELETE' :
break ;
}
jQuery . ajax ( ajaxObj ) ;
} ,
/ * *
* Function to check wheter selected file is editable . ATM only . odt is supported .
*
* @ param { object } _egwAction egw action object
* @ param { object } _senders object of selected row
*
* @ returns { boolean } returns true if is editable otherwise false
* /
isEditable : function ( _egwAction , _senders ) {
var data = egw . dataGetUIDdata ( _senders [ 0 ] . id ) ,
mime = this . et2 . _inst . widgetContainer . getWidgetById ( '$row' ) ;
return data . data . mime . match ( mime . mime _odf _regex ) ? true : false ;
} ,
/ * *
2016-08-19 16:38:44 +02:00
* Function to get full file path
2016-08-16 12:47:00 +02:00
*
2016-08-19 16:38:44 +02:00
* @ returns { String } retruns file path
2016-08-16 12:47:00 +02:00
* /
2016-08-19 16:38:44 +02:00
editor _getFilePath : function ( )
2016-08-16 12:47:00 +02:00
{
var widgetFilePath = this . et2 . getWidgetById ( 'file_path' ) ,
file _path = widgetFilePath . value ,
2016-08-19 16:38:44 +02:00
path = egw . webserverUrl + file _path ;
return path ;
2016-08-16 12:47:00 +02:00
} ,
2016-08-22 17:46:48 +02:00
/ * *
* This function gets called after discard action to
* notify particioant to join to the new session or
* save as the document to not lose changes .
*
* /
editor _discarded : function ( )
{
var self = this ;
var buttons = [
{ "button_id" : 1 , "text" : 'reload' , id : 'reload' , image : 'check' } ,
{ "button_id" : 0 , "text" : 'save as' , id : 'save' , image : 'cancel' , "default" : true }
]
et2 _dialog . show _dialog (
function ( _btn )
{
if ( _btn == 'save' )
{
self . editor _save ( { id : 'saveas' } ) ;
}
else if ( _btn == 'reload' )
{
window . location . reload ( ) ;
}
} ,
egw . lang ( 'All the changes has been discarded and new session created! Save as your local changes if you need them or reload to join new session.' ) ,
'Delete file' ,
null ,
buttons ,
et2 _dialog . WARNING _MESSAGE
) ;
} ,
2016-08-16 12:47:00 +02:00
/ * *
* Function to create collab editor
*
* @ param { type } _args parameteres to be set for server factory and texteditor
* /
create _collab _editor : function ( _args )
{
var serverFactory ,
server ,
serverParams = _args . serverParams ,
sessionId = _args . sessionId ,
editorOptions = jQuery . extend ( _args . editorOptions , { networkSecurityToken : '' , closeCallback : this . editor _close } ) ,
userId = egw . user ( 'account_id' ) ,
memberId ,
self = this ;
/ * *
* Editor error handler function
2016-08-22 17:46:48 +02:00
*
* this function also been used in order to notify
* participant about session changes .
*
* @ param { string } e
2016-08-16 12:47:00 +02:00
* /
function handleEditingError ( e )
{
2016-08-22 17:46:48 +02:00
switch ( e )
{
// This type of error happens when the session is discarded or
// the document has been deleted and all records in database's been removed.
case 'sessionDoesNotExist' :
this . editor _discarded ( ) ;
break ;
default :
console . log ( e )
}
2016-08-16 12:47:00 +02:00
} ;
function onEditing ( )
{
} ;
/ * *
* Callback function which gets called after the collab editor is created
*
* @ param { string } _err
* @ param { object } _editor webodf collabtexteditor object
*
* @ return { undefined } return undefined if something goes wrong
* /
function onEditorCreated ( _err , _editor )
{
if ( _err )
{
console . log ( 'Something went wrong whilst loading editor.' + _err ) ;
return ;
}
self . editor = _editor ;
2016-08-22 17:46:48 +02:00
self . editor . addEventListener ( Wodo . EVENT _UNKNOWNERROR , jQuery . proxy ( handleEditingError , self ) ) ;
2016-08-16 12:47:00 +02:00
self . editor . joinSession ( serverFactory . createSessionBackend ( sessionId , memberId , server ) , onEditing ) ;
} ;
/ * *
* Function to join a doc session
*
* @ param { type } _sessionId session id of the opened document
* /
function joinSession ( _sessionId )
{
var sid = _sessionId ;
2016-08-17 17:23:22 +02:00
2016-08-16 12:47:00 +02:00
server . joinSession ( userId , sid , function ( _memberId ) {
memberId = _memberId ;
2016-08-17 17:23:22 +02:00
// Set server object for current session
self . collab _server = { server : server , memberid : memberId , es _id : sid } ;
2016-08-16 12:47:00 +02:00
if ( Object . keys ( self . editor ) . length == 0 ) {
Wodo . createCollabTextEditor ( 'filemanager-editor_odfEditor' , editorOptions , onEditorCreated ) ;
} else {
self . editor . joinSession ( serverFactory . createSessionBackend ( sid , _memberId , server ) , onEditing ) ;
}
} , function ( err ) {
console . log ( err ) ;
} ) ;
} ;
require ( [ "egwCollab/ServerFactory" ] , function ( ServerFactory ) {
serverFactory = new ServerFactory ( ) ;
server = serverFactory . createServer ( serverParams ) ;
server . connect ( 8000 , function ( state ) {
switch ( state )
{
case "ready" :
joinSession ( sessionId ) ;
break ;
case "timeout" :
console . log ( 'did not connect to server because of timeout.' )
break ;
default :
console . log ( 'server is not available.' )
}
} ) ;
} ) ;
2016-08-22 13:05:47 +02:00
} ,
_do _action _callback : function ( _data )
{
this . _super . apply ( this , arguments ) ;
switch ( _data . action )
{
case 'delete' :
2016-08-22 17:46:48 +02:00
if ( ! _data . errs ) egw . json ( 'filemanager.filemanager_collab.ajax_actions' , [ this . collab _server . es _id , 'delete' ] , function ( ) { window . close ( ) ; } ) . sendRequest ( ) ;
2016-08-22 13:05:47 +02:00
}
2016-08-22 17:46:48 +02:00
} ,
/ * *
* Discard stacked modification in session from all participants
* it will warn user about the consequences which would be removing
* all stored OP modfifications in DB . Then as result it will notify
* other participants about the action and prompt them to reload the
* session or save as the current session if they want to keep their
* changes .
*
* /
editor _discard : function ( )
{
var self = this ;
var buttons = [
{ "button_id" : 1 , "text" : 'discard' , id : 'discard' , image : 'check' } ,
{ "button_id" : 0 , "text" : 'cancel' , id : 'cancel' , image : 'cancel' , "default" : true }
]
et2 _dialog . show _dialog (
function ( _btn )
{
if ( _btn == 'discard' )
{
egw . json ( 'filemanager.filemanager_collab.ajax_actions' , [ self . collab _server . es _id , 'discard' ] , function ( ) {
window . location . reload ( ) ;
} ) . sendRequest ( ) ;
}
} ,
egw . lang ( 'You are about to discard all modifications applied to this document by you and other participants. Be aware this will affect all participants and their changes on this document too.' ) ,
'Discard all changes' ,
null ,
buttons ,
et2 _dialog . WARNING _MESSAGE
) ;
2016-08-16 12:47:00 +02:00
}
} ) ;