@ -187,6 +187,8 @@ function rcube_webmail()
if ( this . env . permaurl )
this . enable _command ( 'permaurl' , 'extwin' , true ) ;
this . local _storage _prefix = 'roundcube.' + ( this . env . user _id || 'anonymous' ) + '.' ;
switch ( this . task ) {
case 'mail' :
@ -578,9 +580,12 @@ function rcube_webmail()
}
// check input before leaving compose step
if ( this . task == 'mail' && this . env . action == 'compose' && $ . inArray ( command , this . env . compose _commands ) < 0 ) {
if ( this . task == 'mail' && this . env . action == 'compose' && $ . inArray ( command , this . env . compose _commands ) < 0 && ! this . env . server _error ) {
if ( this . cmp _hash != this . compose _field _hash ( ) && ! confirm ( this . get _label ( 'notsentwarning' ) ) )
return false ;
// remove copy from local storage if compose screen is left intentionally
this . remove _compose _data ( this . env . compose _id ) ;
}
// process external commands
@ -615,10 +620,10 @@ function rcube_webmail()
break ;
// commands to switch task
case 'logout' :
case 'mail' :
case 'addressbook' :
case 'settings' :
case 'logout' :
this . switch _task ( command ) ;
break ;
@ -638,6 +643,7 @@ function rcube_webmail()
var form = this . gui _objects . messageform ,
win = this . open _window ( '' ) ;
this . save _compose _form _local ( ) ;
$ ( "input[name='_action']" , form ) . val ( 'compose' ) ;
form . action = this . url ( 'mail/compose' , { _id : this . env . compose _id , _extwin : 1 } ) ;
form . target = win . name ;
@ -1292,8 +1298,10 @@ function rcube_webmail()
return ;
var url = this . get _task _url ( task ) ;
if ( task == 'mail' )
if ( task == 'mail' )
url += '&_mbox=INBOX' ;
else if ( task == 'logout' )
this . clear _compose _data ( ) ;
this . redirect ( url ) ;
} ;
@ -3117,6 +3125,53 @@ function rcube_webmail()
}
}
// check for locally stored compose data
if ( window . localStorage ) {
var index = this . local _storage _get _item ( 'compose.index' , [ ] ) ;
for ( var key , i = 0 ; i < index . length ; i ++ ) {
key = index [ i ] , formdata = this . local _storage _get _item ( 'compose.' + key , null , true ) ;
// restore saved copy of current compose_id
if ( formdata && formdata . changed && key == this . env . compose _id ) {
this . restore _compose _form ( key , html _mode ) ;
break ;
}
// show dialog asking to restore the message
if ( formdata && formdata . changed && formdata . session != this . env . session _id ) {
this . show _popup _dialog (
this . get _label ( 'restoresavedcomposedata' )
. replace ( '$date' , new Date ( formdata . changed ) . toLocaleString ( ) )
. replace ( '$subject' , formdata . _subject )
. replace ( /\n/g , '<br/>' ) ,
this . get _label ( 'restoremessage' ) ,
[ {
text : this . get _label ( 'restore' ) ,
click : function ( ) {
ref . restore _compose _form ( key , html _mode ) ;
ref . remove _compose _data ( key ) ; // remove old copy
ref . save _compose _form _local ( ) ; // save under current compose_id
$ ( this ) . dialog ( 'close' ) ;
}
} ,
{
text : this . get _label ( 'delete' ) ,
click : function ( ) {
ref . remove _compose _data ( key ) ;
$ ( this ) . dialog ( 'close' ) ;
}
} ,
{
text : this . get _label ( 'cancel' ) ,
click : function ( ) {
$ ( this ) . dialog ( 'close' ) ;
}
} ]
) ;
break ;
}
}
}
if ( input _to . val ( ) == '' )
input _to . focus ( ) ;
else if ( input _subject . val ( ) == '' )
@ -3554,6 +3609,8 @@ function rcube_webmail()
this . env . draft _id = id ;
$ ( "input[name='_draft_saveid']" ) . val ( id ) ;
this . remove _compose _data ( this . env . compose _id ) ;
} ;
this . auto _save _start = function ( )
@ -3561,6 +3618,11 @@ function rcube_webmail()
if ( this . env . draft _autosave )
this . save _timer = setTimeout ( function ( ) { ref . command ( "savedraft" ) ; } , this . env . draft _autosave * 1000 ) ;
// save compose form content to local storage every 10 seconds
// TODO: track typing activity and only save on changes
if ( ! this . local _save _timer && window . localStorage )
this . local _save _timer = setInterval ( function ( ) { ref . save _compose _form _local ( ) ; } , 10000 ) ;
// Unlock interface now that saving is complete
this . busy = false ;
} ;
@ -3589,6 +3651,109 @@ function rcube_webmail()
return str ;
} ;
// store the contents of the compose form to localstorage
this . save _compose _form _local = function ( )
{
var formdata = { session : this . env . session _id , changed : new Date ( ) . getTime ( ) } ,
ed , empty = true ;
// get fresh content from editor
if ( window . tinyMCE && ( ed = tinyMCE . get ( this . env . composebody ) ) ) {
tinyMCE . triggerSave ( ) ;
}
$ ( 'input, select, textarea' , this . gui _objects . messageform ) . each ( function ( i , elem ) {
switch ( elem . tagName . toLowerCase ( ) ) {
case 'input' :
if ( elem . type == 'button' || elem . type == 'submit' || ( elem . type == 'hidden' && elem . name != '_is_html' ) ) {
break ;
}
formdata [ elem . name ] = elem . type != 'checkbox' || elem . checked ? elem . value : '' ;
if ( formdata [ elem . name ] != '' && elem . type != 'hidden' )
empty = false ;
break ;
case 'select' :
formdata [ elem . name ] = $ ( 'option:checked' , elem ) . val ( ) ;
break ;
default :
formdata [ elem . name ] = $ ( elem ) . val ( ) ;
}
} ) ;
if ( window . localStorage && ! empty ) {
var index = this . local _storage _get _item ( 'compose.index' , [ ] ) ,
key = this . env . compose _id ;
if ( index . indexOf ( key ) < 0 ) {
index . push ( key ) ;
}
this . local _storage _set _item ( 'compose.' + key , formdata , true ) ;
this . local _storage _set _item ( 'compose.index' , index ) ;
}
} ;
// write stored compose data back to form
this . restore _compose _form = function ( key , html _mode )
{
var ed , formdata = this . local _storage _get _item ( 'compose.' + key , true ) ;
if ( formdata && typeof formdata == 'object' ) {
$ . each ( formdata , function ( k , value ) {
if ( k [ 0 ] == '_' ) {
var elem = $ ( "*[name='" + k + "']" ) ;
if ( elem [ 0 ] && elem [ 0 ] . type == 'checkbox' ) {
elem . prop ( 'checked' , value != '' ) ;
}
else {
elem . val ( value ) ;
}
}
} ) ;
// initialize HTML editor
if ( formdata . _is _html == '1' ) {
if ( ! html _mode ) {
tinyMCE . execCommand ( 'mceAddControl' , false , this . env . composebody ) ;
this . triggerEvent ( 'aftertoggle-editor' , { mode : 'html' } ) ;
}
}
else if ( html _mode ) {
tinyMCE . execCommand ( 'mceRemoveControl' , false , this . env . composebody ) ;
this . triggerEvent ( 'aftertoggle-editor' , { mode : 'plain' } ) ;
}
}
} ;
// remove stored compose data from localStorage
this . remove _compose _data = function ( key )
{
if ( window . localStorage ) {
var index = this . local _storage _get _item ( 'compose.index' , [ ] ) ;
if ( index . indexOf ( key ) >= 0 ) {
this . local _storage _remove _item ( 'compose.' + key ) ;
this . local _storage _set _item ( 'compose.index' , $ . grep ( index , function ( val , i ) { return val != key ; } ) ) ;
}
}
} ;
// clear all stored compose data of this user
this . clear _compose _data = function ( )
{
if ( window . localStorage ) {
var index = this . local _storage _get _item ( 'compose.index' , [ ] ) ;
for ( var i = 0 ; i < index . length ; i ++ ) {
this . local _storage _remove _item ( 'compose.' + index [ i ] ) ;
}
this . local _storage _remove _item ( 'compose.index' ) ;
}
}
this . change _identity = function ( obj , show _sig )
{
if ( ! obj || ! obj . options )
@ -6709,6 +6874,20 @@ function rcube_webmail()
setTimeout ( function ( ) { ref . keep _alive ( ) ; ref . start _keepalive ( ) ; } , 30000 ) ;
} ;
// handler for session errors detected on the server
this . session _error = function ( redirect _url )
{
this . env . server _error = 401 ;
// save message in local storage and do not redirect
if ( this . env . action == 'compose' ) {
this . save _compose _form _local ( ) ;
}
else if ( redirect _url ) {
window . setTimeout ( function ( ) { ref . redirect ( redirect _url , true ) ; } , 2000 ) ;
}
} ;
// callback when an iframe finished loading
this . iframe _loaded = function ( unlock )
{
@ -7230,7 +7409,28 @@ function rcube_webmail()
this . set _cookie = function ( name , value , expires )
{
setCookie ( name , value , expires , this . env . cookie _path , this . env . cookie _domain , this . env . cookie _secure ) ;
}
} ;
// wrapper for localStorage.getItem(key)
this . local _storage _get _item = function ( key , deflt , encrypted )
{
// TODO: add encryption
var item = localStorage . getItem ( this . local _storage _prefix + key ) ;
return item !== null ? JSON . parse ( item ) : ( deflt || null ) ;
} ;
// wrapper for localStorage.setItem(key, data)
this . local _storage _set _item = function ( key , data , encrypted )
{
// TODO: add encryption
return localStorage . setItem ( this . local _storage _prefix + key , JSON . stringify ( data ) ) ;
} ;
// wrapper for localStorage.removeItem(key)
this . local _storage _remove _item = function ( key )
{
return localStorage . removeItem ( this . local _storage _prefix + key ) ;
} ;
} // end object rcube_webmail