Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F1841468
kolab_files.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
130 KB
Referenced Files
None
Subscribers
None
kolab_files.js
View Options
/**
* Kolab files plugin
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2011-2015, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
window
.
rcmail
&&
window
.
files_api
&&
rcmail
.
addEventListener
(
'init'
,
function
()
{
if
(
rcmail
.
task
==
'mail'
)
{
// mail compose
if
(
rcmail
.
env
.
action
==
'compose'
)
{
kolab_files_from_cloud_widget
(
$
(
'#compose-attachments > div'
));
// register some commands to skip warning message on compose page
$
.
merge
(
rcmail
.
env
.
compose_commands
,
[
'files-list'
,
'files-sort'
,
'files-search'
,
'files-search-reset'
]);
}
// mail preview
else
if
(
rcmail
.
env
.
action
==
'show'
||
rcmail
.
env
.
action
==
'preview'
)
{
var
attachment_list
=
$
(
'#attachment-list'
);
if
(
$
(
'li'
,
attachment_list
).
length
)
{
var
link
=
$
(
'<a href="#" class="button filesaveall">'
)
.
text
(
rcmail
.
gettext
(
'kolab_files.saveall'
))
.
click
(
function
()
{
kolab_directory_selector_dialog
();
})
.
insertAfter
(
$
(
'.header-content > .header-links'
).
length
?
$
(
'.header-links > a:last'
)
:
attachment_list
);
}
rcmail
.
addEventListener
(
'menu-open'
,
kolab_files_attach_menu_open
);
rcmail
.
enable_command
(
'folder-create'
,
true
);
}
// attachment preview
else
if
(
rcmail
.
env
.
action
==
'get'
)
{
rcmail
.
enable_command
(
'folder-create'
,
true
);
}
if
(
!
rcmail
.
env
.
action
||
rcmail
.
env
.
action
==
'show'
||
rcmail
.
env
.
action
==
'preview'
)
{
// add "attach from cloud" button for event/task dialog in mail
rcmail
.
addEventListener
(
'plugin.mail2event_dialog'
,
function
()
{
if
(
!
$
(
'#calendar-attachment-form a.fromcloud'
).
length
)
kolab_files_from_cloud_widget
(
$
(
'#calendar-attachment-form > div.buttons'
));
});
}
}
else
if
(
rcmail
.
task
==
'calendar'
)
{
// add "attach from cloud" button for event dialog
if
(
!
rcmail
.
env
.
action
)
kolab_files_from_cloud_widget
(
$
(
'#calendar-attachment-form > div.buttons, #edit-attachments-form'
));
}
else
if
(
rcmail
.
task
==
'tasks'
)
{
// add "attach from cloud" button for task dialog
if
(
!
rcmail
.
env
.
action
)
kolab_files_from_cloud_widget
(
$
(
'#taskedit-attachment-form > div.buttons, #taskedit-attachments-form'
));
}
else
if
(
rcmail
.
task
==
'files'
)
{
if
(
rcmail
.
gui_objects
.
fileslist
)
{
rcmail
.
fileslist
=
new
rcube_list_widget
(
rcmail
.
gui_objects
.
fileslist
,
{
multiselect
:
true
,
draggable
:
true
,
keyboard
:
true
,
column_movable
:
rcmail
.
env
.
files_col_movable
,
dblclick_time
:
rcmail
.
dblclick_time
});
rcmail
.
fileslist
.
addEventListener
(
'dblclick'
,
function
(
o
)
{
kolab_files_list_dblclick
(
o
);
})
.
addEventListener
(
'select'
,
function
(
o
)
{
kolab_files_list_select
(
o
);
})
.
addEventListener
(
'keypress'
,
function
(
o
)
{
kolab_files_list_keypress
(
o
);
})
.
addEventListener
(
'dragstart'
,
function
(
e
)
{
kolab_files_drag_start
(
e
);
})
.
addEventListener
(
'dragmove'
,
function
(
e
)
{
kolab_files_drag_move
(
e
);
})
.
addEventListener
(
'dragend'
,
function
(
e
)
{
kolab_files_drag_end
(
e
);
})
.
addEventListener
(
'column_replace'
,
function
(
e
)
{
kolab_files_set_coltypes
(
e
,
'files'
);
});
rcmail
.
enable_command
(
'menu-open'
,
'menu-save'
,
'files-sort'
,
'files-search'
,
'files-search-reset'
,
'folder-create'
,
true
);
rcmail
.
fileslist
.
init
();
kolab_files_list_coltypes
(
'files'
);
kolab_files_drag_drop_init
(
$
(
rcmail
.
gui_objects
.
fileslist
).
parents
(
'.droptarget'
));
}
if
(
rcmail
.
gui_objects
.
sessionslist
)
{
rcmail
.
sessionslist
=
new
rcube_list_widget
(
rcmail
.
gui_objects
.
sessionslist
,
{
keyboard
:
true
,
column_movable
:
rcmail
.
env
.
sessions_col_movable
,
dblclick_time
:
rcmail
.
dblclick_time
});
rcmail
.
sessionslist
.
addEventListener
(
'dblclick'
,
function
(
o
)
{
kolab_files_sessions_list_dblclick
(
o
);
})
.
addEventListener
(
'select'
,
function
(
o
)
{
kolab_files_sessions_list_select
(
o
);
})
.
addEventListener
(
'keypress'
,
function
(
o
)
{
kolab_files_sessions_list_keypress
(
o
);
})
.
addEventListener
(
'column_replace'
,
function
(
e
)
{
kolab_files_set_coltypes
(
e
,
'sessions'
);
});
rcmail
.
sessionslist
.
init
();
kolab_files_list_coltypes
(
'sessions'
);
}
// "one file only" commands
rcmail
.
env
.
file_commands
=
[
'files-get'
,
'files-rename'
];
// "one or more file" commands
rcmail
.
env
.
file_commands_all
=
[
'files-delete'
,
'files-move'
,
'files-copy'
];
if
(
rcmail
.
env
.
action
==
'open'
||
rcmail
.
env
.
action
==
'edit'
)
{
rcmail
.
enable_command
(
'files-get'
,
true
);
rcmail
.
enable_command
(
'files-delete'
,
rcmail
.
env
.
file_data
.
writable
);
}
else
{
rcmail
.
enable_command
(
'folder-mount'
,
rcmail
.
env
.
external_sources
);
}
}
kolab_files_init
();
});
/**********************************************************/
/********* Shared functionality **********/
/**********************************************************/
// Initializes API object
function
kolab_files_init
()
{
if
(
window
.
file_api
)
return
;
var
editor_config
=
{};
// Initialize application object (don't change var name!)
file_api
=
$
.
extend
(
new
files_api
(),
new
kolab_files_ui
());
file_api
.
set_env
({
token
:
kolab_files_token
(),
url
:
rcmail
.
env
.
files_url
,
sort_col
:
'name'
,
sort_reverse
:
false
,
search_threads
:
rcmail
.
env
.
search_threads
,
resources_dir
:
rcmail
.
env
.
files_url
.
replace
(
/\/api\/?$/
,
'/resources'
),
caps
:
rcmail
.
env
.
files_caps
,
supported_mimetypes
:
rcmail
.
env
.
file_mimetypes
});
file_api
.
translations
=
rcmail
.
labels
;
if
(
rcmail
.
task
==
'files'
)
{
if
(
rcmail
.
env
.
action
==
'edit'
&&
rcmail
.
env
.
editor_type
)
{
// Extract the domain here, it can't be done by Chwala
// when using WOPI, which does not set iframe src attribute
var
domain
,
href
=
rcmail
.
env
.
file_data
.
viewer
.
href
;
if
(
href
&&
/^(https?:\/\/[^/]+)/i
.
test
(
href
))
domain
=
RegExp
.
$1
;
editor_config
=
{
// UI elements
iframe
:
$
(
'#fileframe'
).
get
(
0
),
domain
:
domain
,
export_menu
:
rcmail
.
gui_objects
.
exportmenu
?
$
(
'ul'
,
rcmail
.
gui_objects
.
exportmenu
).
get
(
0
)
:
null
,
title_input
:
$
(
'#document-title'
).
get
(
0
),
members_list
:
$
(
'#members'
).
get
(
0
),
photo_url
:
'?_task=addressbook&_action=photo&_error=1&_email=%email'
,
photo_default_url
:
rcmail
.
env
.
photo_placeholder
,
// events
ready
:
function
(
data
)
{
document_editor_init
();
},
sessionClosed
:
function
(
data
)
{
return
document_editor_close
();
}
};
if
(
rcmail
.
env
.
file_data
.
writable
)
editor_config
.
documentChanged
=
function
(
data
)
{
rcmail
.
enable_command
(
'document-save'
,
true
);
};
}
else
if
(
rcmail
.
env
.
action
==
'open'
)
{
// initialize folders list (for dialogs)
// file_api.folder_list();
// get ongoing sessions
file_api
.
request
(
'folder_info'
,
{
folder
:
file_api
.
file_path
(
rcmail
.
env
.
file
),
sessions
:
1
},
'folder_info_response'
);
}
else
if
(
rcmail
.
env
.
action
==
'share'
)
{
kolab_files_share_form_init
();
}
else
{
file_api
.
env
.
init_folder
=
rcmail
.
env
.
folder
;
file_api
.
env
.
init_collection
=
rcmail
.
env
.
collection
;
file_api
.
folder_list
();
file_api
.
browser_capabilities_check
();
if
(
rcmail
.
env
.
contextmenu
)
{
rcmail
.
env
.
folders_cm
=
rcmail
.
contextmenu
.
init
({
menu_name
:
'foldercontextmenu'
,
menu_source
:
'#folderoptions > ul'
,
list_object
:
'folder_list'
},
{
addmenuitem
:
function
(
p
)
{
// don't add Mount option to the menu
var
str
=
$
(
p
.
el
).
children
(
'a'
).
first
().
attr
(
'onclick'
);
if
(
str
&&
str
.
match
(
/folder-mount/
))
return
{
result
:
false
,
abort
:
true
};
},
activate
:
function
(
p
)
{
var
folder
=
rcmail
.
env
.
context_menu_source_id
;
switch
(
p
.
command
)
{
case
'files-folder-delete'
:
case
'folder-rename'
:
return
!
folder
.
match
(
/^folder-collection-(.*)$/
);
case
'folder-share'
:
return
!
folder
.
match
(
/^folder-collection-(.*)$/
)
&&
file_api
.
is_shareable
(
folder
);
case
'folder-create'
:
case
'folder-mount'
:
return
true
;
}
},
beforecommand
:
function
(
e
)
{
rcmail
.
env
.
file_api_context
=
[
file_api
.
env
.
folder
,
file_api
.
env
.
collection
];
file_api
.
env
.
folder
=
rcmail
.
env
.
context_menu_source_id
;
},
aftercommand
:
function
(
e
)
{
file_api
.
env
.
folder
=
rcmail
.
env
.
file_api_context
[
0
];
file_api
.
env
.
collection
=
rcmail
.
env
.
file_api_context
[
1
];
}
});
}
}
}
if
(
rcmail
.
env
.
files_caps
&&
!
rcmail
.
env
.
framed
&&
rcmail
.
env
.
files_caps
.
DOCEDIT
)
$
.
extend
(
editor_config
,
{
// invitation notifications
api
:
file_api
,
owner
:
rcmail
.
env
.
files_user
,
interval
:
rcmail
.
env
.
files_interval
||
60
,
invitationMore
:
true
,
invitationChange
:
document_editor_invitation_handler
});
$
.
extend
(
editor_config
,
{
// notifications/alerts
gettext
:
function
(
label
)
{
return
rcmail
.
get_label
(
label
,
'kolab_files'
);
},
set_busy
:
function
(
state
,
message
)
{
return
rcmail
.
set_busy
(
state
,
message
?
'kolab_files.'
+
message
:
''
);
},
hide_message
:
function
(
id
)
{
return
rcmail
.
hide_message
(
id
);
},
display_message
:
function
(
label
,
type
,
is_txt
,
timeout
)
{
if
(
!
is_txt
)
label
=
'kolab_files.'
+
label
;
return
rcmail
.
display_message
(
label
,
type
,
timeout
*
1000
);
}
});
if
(
window
.
document_editor_api
)
document_editor
=
new
document_editor_api
(
editor_config
);
else
document_editor
=
new
manticore_api
(
editor_config
);
rcmail
.
addEventListener
(
'responseafterreset'
,
function
(
o
)
{
// update caps/mountpoints on reset
file_api
.
set_env
({
caps
:
rcmail
.
env
.
files_caps
});
});
};
// returns API authorization token
function
kolab_files_token
()
{
// consider the token from parent window more reliable (fresher) than in framed window
// it's because keep-alive is not requested in frames
return
rcmail
.
is_framed
()
&&
parent
.
rcmail
.
env
.
files_token
?
parent
.
rcmail
.
env
.
files_token
:
rcmail
.
env
.
files_token
;
};
function
kolab_files_from_cloud_widget
(
elem
)
{
$
(
'<a class="button btn btn-secondary fromcloud">'
)
.
attr
(
'tabindex'
,
$
(
'button,input'
,
elem
).
first
().
attr
(
'tabindex'
)
||
0
)
.
text
(
rcmail
.
gettext
(
'kolab_files.fromcloud'
))
.
click
(
function
()
{
kolab_files_selector_dialog
();
})
.
appendTo
(
elem
);
if
(
rcmail
.
gui_objects
.
fileslist
)
{
rcmail
.
fileslist
=
new
rcube_list_widget
(
rcmail
.
gui_objects
.
fileslist
,
{
multiselect
:
true
,
keyboard
:
true
,
column_movable
:
false
,
dblclick_time
:
rcmail
.
dblclick_time
});
rcmail
.
fileslist
.
addEventListener
(
'select'
,
function
(
o
)
{
kolab_files_list_select
(
o
);
});
rcmail
.
enable_command
(
'files-sort'
,
'files-search'
,
'files-search-reset'
,
true
);
rcmail
.
fileslist
.
init
();
kolab_files_list_coltypes
();
}
}
// folder selection dialog
function
kolab_directory_selector_dialog
(
id
)
{
var
dialog
=
$
(
'#files-dialog'
),
input
=
$
(
'#file-save-as-input'
),
form
=
$
(
'#file-save-as'
),
list
=
$
(
'#folderlistbox'
),
buttons
=
{},
label
=
'saveto'
,
win
=
window
,
fn
;
// attachment is specified
if
(
id
)
{
var
attach
=
$
(
'#attach'
+
id
+
'> a'
).
first
(),
filename
=
attach
.
attr
(
'title'
);
if
(
!
filename
)
{
attach
=
attach
.
clone
();
$
(
'.attachment-size'
,
attach
).
remove
();
filename
=
$
.
trim
(
attach
.
text
());
}
form
.
show
();
dialog
.
addClass
(
'saveas'
);
input
.
val
(
filename
);
}
// attachment preview page
else
if
(
rcmail
.
env
.
action
==
'get'
)
{
id
=
rcmail
.
env
.
part
;
form
.
show
();
dialog
.
addClass
(
'saveas'
);
input
.
val
(
rcmail
.
env
.
filename
);
}
else
{
form
.
hide
();
dialog
.
removeClass
(
'saveas'
);
label
=
'saveall'
;
}
$
(
'#foldercreatelink'
).
attr
(
'tabindex'
,
0
);
buttons
[
rcmail
.
gettext
(
'kolab_files.save'
)]
=
function
()
{
if
(
!
file_api
.
env
.
folder
)
return
;
var
lock
=
rcmail
.
set_busy
(
true
,
'saving'
),
request
=
{
act
:
'save-file'
,
source
:
rcmail
.
env
.
mailbox
,
uid
:
rcmail
.
env
.
uid
,
dest
:
file_api
.
env
.
folder
};
if
(
id
)
{
request
.
id
=
id
;
request
.
name
=
input
.
val
();
}
rcmail
.
http_post
(
'plugin.kolab_files'
,
request
,
lock
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
if
(
!
rcmail
.
env
.
folders_loaded
)
{
fn
=
function
()
{
rcmail
.
env
.
folder_list_selector
=
'#files-dialog #files-folder-list'
;
rcmail
.
env
.
folder_search_selector
=
'#files-dialog #foldersearch'
;
file_api
.
folder_list
({
writable
:
1
});
rcmail
.
env
.
folders_loaded
=
true
;
};
}
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.'
+
label
),
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
classes
:
{
'ui-dialog'
:
'selection-dialog files-dialog'
},
minWidth
:
250
,
minHeight
:
300
,
height
:
400
,
width
:
300
},
fn
);
// add link for "more options" drop-down
if
(
!
dialog
.
find
(
'foldercreatelink'
).
length
)
$
(
'<a>'
)
.
attr
({
href
:
'#'
,
'class'
:
'btn btn-link options add-folder'
})
.
text
(
rcmail
.
gettext
(
'kolab_files.addfolder'
))
.
click
(
function
(
e
)
{
rcmail
.
command
(
'folder-create'
,
''
,
this
,
e
);
})
.
prependTo
(
dialog
.
parent
().
parent
().
find
(
'.ui-dialog-buttonset'
));
// "enable" folder creation when dialog is displayed in parent window
if
(
rcmail
.
is_framed
())
{
parent
.
rcmail
.
enable_command
(
'folder-create'
,
true
);
parent
.
rcmail
.
folder_create
=
function
()
{
win
.
kolab_files_folder_create_dialog
();
};
}
};
// file selection dialog
function
kolab_files_selector_dialog
()
{
var
dialog
=
$
(
'#files-compose-dialog'
),
buttons
=
{};
buttons
[
rcmail
.
gettext
(
'kolab_files.attachsel'
)]
=
function
()
{
var
list
=
[];
$
(
'#filelist tr.selected'
).
each
(
function
()
{
list
.
push
(
$
(
this
).
data
(
'file'
));
});
kolab_dialog_close
(
this
);
if
(
list
.
length
)
{
// display upload indicator and cancel button
var
content
=
'<span>'
+
rcmail
.
get_label
(
'kolab_files.attaching'
)
+
'</span>'
,
id
=
new
Date
().
getTime
();
rcmail
.
add2attachment_list
(
id
,
{
name
:
''
,
html
:
content
,
classname
:
'uploading'
,
complete
:
false
});
// send request
rcmail
.
http_post
(
'plugin.kolab_files'
,
{
act
:
'attach-file'
,
files
:
list
,
id
:
rcmail
.
env
.
compose_id
,
uploadid
:
id
});
}
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.selectfiles'
),
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
classes
:
{
'ui-dialog'
:
'selection-dialog files-dialog'
},
minWidth
:
500
,
minHeight
:
300
,
width
:
700
,
height
:
500
},
function
()
{
rcmail
.
fileslist
.
resize
();
});
if
(
!
rcmail
.
env
.
files_loaded
)
{
rcmail
.
env
.
folder_list_selector
=
'#files-compose-dialog #files-folder-list'
;
rcmail
.
env
.
folder_search_selector
=
'#files-compose-dialog #foldersearch'
;
file_api
.
folder_list
();
rcmail
.
env
.
files_loaded
=
true
;
}
else
{
rcmail
.
fileslist
.
clear_selection
();
}
};
function
kolab_files_attach_menu_open
(
p
)
{
if
(
!
p
||
!
p
.
props
||
p
.
props
.
menu
!=
'attachmentmenu'
)
return
;
var
id
=
p
.
props
.
id
;
$
(
'#attachmenusaveas'
).
unbind
(
'click'
).
attr
(
'onclick'
,
''
).
click
(
function
(
e
)
{
return
kolab_directory_selector_dialog
(
id
);
});
};
// folder creation dialog
function
kolab_files_folder_create_dialog
()
{
var
dialog
=
$
(
'#files-folder-create-dialog'
),
buttons
=
{},
select
=
$
(
'select[name="parent"]'
,
dialog
).
html
(
''
),
input
=
$
(
'input[name="name"]'
,
dialog
).
val
(
''
);
buttons
[
rcmail
.
gettext
(
'kolab_files.create'
)]
=
function
()
{
var
folder
=
''
,
name
=
input
.
val
(),
parent
=
select
.
val
();
if
(
!
name
)
return
;
if
(
parent
)
folder
=
parent
+
file_api
.
env
.
directory_separator
;
folder
+=
name
;
file_api
.
folder_create
(
folder
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.foldercreate'
),
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
height
:
200
});
// Fix submitting form with Enter
$
(
'form'
,
dialog
).
submit
(
kolab_dialog_submit_handler
);
// build parent selector
file_api
.
folder_select_element
(
select
,
{
empty
:
!
rcmail
.
env
.
files_caps
.
NOROOT
,
writable
:
true
});
};
// folder edit dialog
function
kolab_files_folder_edit_dialog
()
{
var
dialog
=
$
(
'#files-folder-edit-dialog'
),
buttons
=
{},
separator
=
file_api
.
env
.
directory_separator
,
current_folder
=
file_api
.
env
.
folder
,
arr
=
current_folder
.
split
(
separator
),
folder
=
arr
.
pop
(),
path
=
arr
.
join
(
separator
),
select
=
$
(
'select[name="parent"]'
,
dialog
).
html
(
''
),
input
=
$
(
'input[name="name"]'
,
dialog
).
val
(
folder
);
buttons
[
rcmail
.
gettext
(
'kolab_files.save'
)]
=
function
()
{
var
folder
=
''
,
name
=
input
.
val
(),
parent
=
select
.
val
();
if
(
!
name
)
return
;
if
(
parent
)
folder
=
parent
+
separator
;
folder
+=
name
;
file_api
.
folder_rename
(
current_folder
,
folder
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.folderedit'
),
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
height
:
200
});
// Fix submitting form with Enter
$
(
'form'
,
dialog
).
submit
(
kolab_dialog_submit_handler
);
// build parent selector
file_api
.
folder_select_element
(
select
,
{
selected
:
path
,
empty
:
!
rcmail
.
env
.
files_caps
.
NOROOT
});
};
// folder sharing dialog
function
kolab_files_folder_share_dialog
()
{
var
dialog
=
$
(
'<iframe>'
).
attr
(
'src'
,
rcmail
.
url
(
'share'
,
{
_folder
:
file_api
.
env
.
folder
,
_framed
:
1
}));
rcmail
.
simple_dialog
(
dialog
,
rcmail
.
gettext
(
'kolab_files.foldershare'
),
null
,
{
cancel_button
:
'close'
,
width
:
600
,
height
:
500
});
};
// folder mounting dialog
function
kolab_files_folder_mount_dialog
()
{
var
args
=
{
buttons
:
{},
title
:
rcmail
.
gettext
(
'kolab_files.foldermount'
)},
dialog
=
$
(
'#files-folder-mount-dialog'
),
input
=
$
(
'#folder-mount-name'
).
val
(
''
);
args
.
buttons
[
rcmail
.
gettext
(
'kolab_files.save'
)]
=
function
()
{
var
args
=
{},
folder
=
input
.
val
(),
driver
=
$
(
'input[name="driver"]:checked'
,
dialog
).
val
();
if
(
!
folder
||
!
driver
)
return
;
args
.
folder
=
folder
;
args
.
driver
=
driver
;
$
(
'#source-'
+
driver
+
' input'
).
each
(
function
()
{
if
(
this
.
name
.
startsWith
(
driver
+
'['
))
{
args
[
this
.
name
.
substring
(
driver
.
length
+
1
,
this
.
name
.
length
-
1
)]
=
this
.
value
;
}
});
$
(
'.auth-options input'
,
dialog
).
each
(
function
()
{
args
[
this
.
name
]
=
this
.
type
==
'checkbox'
&&
!
this
.
checked
?
''
:
this
.
value
;
});
file_api
.
folder_mount
(
args
);
kolab_dialog_close
(
this
);
};
args
.
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// initialize drivers list
if
(
!
rcmail
.
drivers_list_initialized
)
{
rcmail
.
drivers_list_initialized
=
true
;
$
(
'td.source'
,
dialog
).
each
(
function
()
{
var
td
=
$
(
this
),
id
=
td
.
attr
(
'id'
).
replace
(
'source-'
,
''
),
meta
=
rcmail
.
env
.
external_sources
[
id
];
$
.
each
(
meta
.
form_values
||
[],
function
(
i
,
v
)
{
td
.
find
(
'#source-'
+
id
+
'-'
+
i
).
val
(
v
);
});
td
.
click
(
function
()
{
$
(
'td.selected'
,
dialog
).
removeClass
(
'selected'
);
dialog
.
find
(
'.driverform'
).
hide
();
$
(
this
).
addClass
(
'selected'
).
find
(
'.driverform'
).
show
();
$
(
'input[type="radio"]'
,
this
).
prop
(
'checked'
,
true
);
});
});
}
args
.
button_classes
=
[
'mainaction save'
,
'cancel'
];
// show dialog window
kolab_dialog_show
(
dialog
,
args
,
function
()
{
$
(
'td.source:first'
,
dialog
).
click
();
input
.
focus
();
});
};
// file edit dialog
function
kolab_files_file_edit_dialog
(
file
,
sessions
,
readonly
)
{
var
content
=
[],
items
=
[],
height
=
300
,
dialog
=
$
(
'#files-file-edit-dialog'
),
buttons
=
{},
name
=
file_api
.
file_name
(
file
),
title
=
rcmail
.
gettext
(
'kolab_files.editfiledialog'
),
mainaction
=
rcmail
.
gettext
(
'kolab_files.select'
),
item_fn
=
function
(
id
,
txt
,
classes
)
{
return
$
(
'<label>'
).
attr
(
'class'
,
'session'
+
(
classes
?
' '
+
classes
:
''
))
.
append
(
$
(
'<input>'
).
attr
({
name
:
'opt'
,
value
:
id
,
type
:
'radio'
})).
append
(
$
(
'<span>'
).
text
(
txt
));
},
select_fn
=
function
(
dlg
)
{
var
session
,
input
=
$
(
'input:checked'
,
dialog
),
id
=
input
.
val
();
if
(
dlg
)
kolab_dialog_close
(
dlg
);
if
(
id
&&
input
.
parent
().
is
(
'.session.request'
))
{
document_editor
.
invitation_request
({
session_id
:
id
});
return
;
}
if
(
readonly
&&
(
id
==
0
||
!
input
.
length
))
return
kolab_files_file_create_dialog
(
file
);
rcmail
.
files_edit
(
id
?
id
:
true
);
};
// Create sessions selection
if
(
sessions
&&
sessions
.
length
)
{
items
.
push
(
$
(
'<div>'
).
text
(
rcmail
.
gettext
(
'kolab_files.editfilesessions'
)));
// first display owned sessions, then invited, other at the end
$
.
each
(
sessions
,
function
()
{
if
(
this
.
is_owner
)
{
var
txt
=
rcmail
.
gettext
(
'kolab_files.ownedsession'
);
items
.
push
(
item_fn
(
this
.
id
,
txt
,
'owner'
));
}
});
if
(
items
.
length
==
1
)
items
.
push
(
item_fn
(
0
,
rcmail
.
gettext
(
'kolab_files.newsession'
+
(
readonly
?
'ro'
:
''
))));
$
.
each
(
sessions
,
function
()
{
if
(
this
.
is_invited
)
{
var
txt
=
rcmail
.
gettext
(
'kolab_files.invitedsession'
)
.
replace
(
'$user'
,
this
.
owner_name
?
this
.
owner_name
:
this
.
owner
);
items
.
push
(
item_fn
(
this
.
id
,
txt
,
'invited'
));
}
});
$
.
each
(
sessions
,
function
()
{
if
(
!
this
.
is_owner
&&
!
this
.
is_invited
)
{
var
txt
=
rcmail
.
gettext
(
'kolab_files.joinsession'
)
.
replace
(
'$user'
,
this
.
owner_name
?
this
.
owner_name
:
this
.
owner
);
items
.
push
(
item_fn
(
this
.
id
,
txt
,
'request'
));
}
});
// check the first option
$
(
'input'
,
items
[
1
]).
attr
(
'checked'
,
true
);
$
(
'div'
,
dialog
).
html
(
items
);
// if there's only one session and it's owned, skip the dialog
if
(
!
readonly
&&
items
.
length
==
2
&&
$
(
'input:checked'
,
dialog
).
parent
().
is
(
'.owner'
))
return
select_fn
();
}
// no ongoing session, folder is readonly warning
else
{
title
=
rcmail
.
gettext
(
'kolab_files.editfilerotitle'
);
height
=
150
;
$
(
'div'
,
dialog
).
text
(
rcmail
.
gettext
(
'kolab_files.editfilero'
));
mainaction
=
rcmail
.
gettext
(
'kolab_files.create'
);
}
buttons
[
mainaction
]
=
function
()
{
select_fn
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
title
,
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
minHeight
:
height
-
100
,
height
:
height
});
};
// file rename dialog
function
kolab_files_file_rename_dialog
(
file
)
{
var
dialog
=
$
(
'#files-file-rename-dialog'
),
buttons
=
{},
name
=
file_api
.
file_name
(
file
)
input
=
$
(
'input[name="name"]'
,
dialog
).
val
(
name
);
buttons
[
rcmail
.
gettext
(
'kolab_files.save'
)]
=
function
()
{
var
folder
=
file_api
.
file_path
(
file
),
name
=
input
.
val
();
if
(
!
name
)
return
;
name
=
folder
+
file_api
.
env
.
directory_separator
+
name
;
if
(
name
!=
file
)
file_api
.
file_rename
(
file
,
name
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// Fix submitting form with Enter
$
(
'form'
,
dialog
).
submit
(
kolab_dialog_submit_handler
);
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.renamefile'
),
buttons
:
buttons
,
button_classes
:
[
'mainaction save'
,
'cancel'
],
minHeight
:
100
,
height
:
100
});
};
// file creation (or cloning) dialog
function
kolab_files_file_create_dialog
(
file
)
{
var
buttons
=
{},
action
=
file
?
'copy'
:
'create'
,
button_classes
=
[
'mainaction save edit'
],
dialog
=
$
(
'#files-file-create-dialog'
),
type_select
=
$
(
'select[name="type"]'
,
dialog
),
select
=
$
(
'select[name="parent"]'
,
dialog
).
html
(
''
),
input
=
$
(
'input[name="name"]'
,
dialog
).
val
(
''
),
create_func
=
function
(
dialog
,
editaction
)
{
var
sel
,
folder
=
select
.
val
(),
type
=
type_select
.
val
(),
name
=
input
.
val
();
if
(
!
name
||
!
folder
||
!
file_api
.
is_writable
(
folder
))
return
;
if
(
!
/\.[a-z0-9]{1,5}$/
.
test
(
name
))
{
name
+=
'.'
+
rcmail
.
env
.
file_extensions
[
type
];
}
name
=
folder
+
file_api
.
env
.
directory_separator
+
name
;
// get type of cloned file
if
(
file
)
{
if
(
rcmail
.
env
.
file_data
)
type
=
rcmail
.
env
.
file_data
.
type
;
else
{
sel
=
rcmail
.
fileslist
.
get_selection
();
type
=
$
(
'#rcmrow'
+
sel
[
0
]).
data
(
'type'
);
}
}
file_api
.
file_create
(
name
,
type
,
editaction
,
file
);
kolab_dialog_close
(
dialog
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.'
+
action
+
'andedit'
)]
=
function
()
{
create_func
(
this
,
true
);
};
if
(
action
==
'create'
)
{
button_classes
.
push
(
'save'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.create'
)]
=
function
()
{
create_func
(
this
);
};
type_select
.
parent
(
'tr'
).
show
();
}
else
{
input
.
val
(
file_api
.
file_name
(
file
));
type_select
.
parent
(
'tr'
).
hide
();
}
button_classes
.
push
(
'cancel'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// Fix submitting form with Enter
$
(
'form'
,
dialog
).
submit
(
kolab_dialog_submit_handler
);
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.'
+
action
+
'file'
),
buttons
:
buttons
,
button_classes
:
button_classes
,
minHeight
:
150
,
height
:
250
});
// build folder selector
file_api
.
folder_select_element
(
select
,
{
writable
:
true
});
};
// file session dialog
function
kolab_files_session_dialog
(
session
)
{
var
buttons
=
{},
button_classes
=
[],
dialog
=
$
(
'#files-session-dialog'
),
filename
=
file_api
.
file_name
(
session
.
file
),
owner
=
session
.
owner_name
||
session
.
owner
,
title
=
rcmail
.
gettext
(
'kolab_files.sessiondialog'
),
content
=
rcmail
.
gettext
(
'kolab_files.sessiondialogcontent'
),
join_session
=
function
(
id
)
{
var
viewer
=
file_api
.
file_type_supported
(
'application/vnd.oasis.opendocument.text'
,
rcmail
.
env
.
files_caps
);
params
=
{
action
:
'edit'
,
session
:
id
};
file_api
.
file_open
(
''
,
viewer
,
params
);
};
content
=
content
.
replace
(
'$file'
,
filename
).
replace
(
'$owner'
,
owner
);
$
(
'div'
,
dialog
).
text
(
content
);
if
(
session
.
is_owner
)
{
buttons
[
rcmail
.
gettext
(
'kolab_files.open'
)]
=
function
()
{
kolab_dialog_close
(
this
);
join_session
(
session
.
id
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.close'
)]
=
function
()
{
kolab_dialog_close
(
this
);
file_api
.
document_delete
(
session
.
id
);
};
button_classes
=
[
'mainaction edit'
,
'delete'
];
}
else
if
(
session
.
is_invited
)
{
button_classes
=
[
'mainaction edit'
];
// @TODO: check if not-accepted and provide "Decline invitation" button
// @TODO: Add "Accept button", add comment field to the dialog
buttons
[
rcmail
.
gettext
(
'kolab_files.join'
)]
=
function
()
{
kolab_dialog_close
(
this
);
join_session
(
session
.
id
);
};
}
else
{
button_classes
=
[
'mainaction session request'
];
buttons
[
rcmail
.
gettext
(
'kolab_files.request'
)]
=
function
()
{
kolab_dialog_close
(
this
);
// @TODO: Add comment field to the dialog
document_editor
.
invitation_request
({
session_id
:
session
.
id
});
};
}
button_classes
.
push
(
'cancel'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.cancel'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
title
,
buttons
:
buttons
,
button_classes
:
button_classes
,
minHeight
:
100
,
height
:
150
});
};
function
kolab_dialog_show
(
content
,
params
,
onopen
)
{
params
=
$
.
extend
({
modal
:
true
,
resizable
:
true
,
minWidth
:
400
,
minHeight
:
300
,
width
:
500
,
height
:
400
},
params
||
{});
// dialog close handler
params
.
close
=
function
(
e
,
ui
)
{
var
elem
,
stack
=
rcmail
.
dialog_stack
;
content
.
appendTo
(
document
.
body
);
content
.
hide
();
// for Larry's dialogs
$
(
this
).
parent
().
remove
();
// remove dialog
// focus previously focused element (guessed)
stack
.
pop
();
if
(
stack
.
length
)
{
elem
=
stack
[
stack
.
length
-
1
].
find
(
'input[type!="hidden"]:not(:hidden):first'
);
if
(
!
elem
.
length
)
elem
=
stack
[
stack
.
length
-
1
].
parent
().
find
(
'a[role="button"], .ui-dialog-buttonpane button'
).
first
();
}
(
elem
&&
elem
.
length
?
elem
:
window
).
focus
();
rcmail
.
ksearch_blur
();
};
// This is required for Larry's dialogs
params
.
create
=
function
()
{
content
.
show
();
};
// display it as popup
var
dialog
=
rcmail
.
show_popup_dialog
(
content
,
params
.
title
,
params
.
buttons
,
params
);
if
(
onopen
)
onopen
(
content
);
// save dialog reference, to handle focus when closing one of opened dialogs
if
(
!
rcmail
.
dialog_stack
)
rcmail
.
dialog_stack
=
[];
rcmail
.
dialog_stack
.
push
(
dialog
);
};
// Handle form submit with Enter key, click first dialog button instead
function
kolab_dialog_submit_handler
()
{
$
(
this
).
parents
(
'.ui-dialog'
).
find
(
'.ui-dialog-buttonpane button'
).
first
().
click
();
return
false
;
};
// Hides dialog
function
kolab_dialog_close
(
dialog
,
destroy
)
{
(
rcmail
.
is_framed
()
?
window
.
parent
:
window
).
$
(
dialog
).
dialog
(
destroy
?
'destroy'
:
'close'
);
};
// smart upload button
function
kolab_files_upload_input
(
button
)
{
var
link
=
$
(
button
),
file
=
$
(
'<input>'
),
offset
=
link
.
offset
();
function
move_file_input
(
e
)
{
file
.
css
({
top
:
(
e
.
pageY
-
offset
.
top
-
10
)
+
'px'
,
left
:
(
e
.
pageX
-
offset
.
left
-
10
)
+
'px'
});
}
file
.
attr
({
name
:
'file[]'
,
type
:
'file'
,
multiple
:
'multiple'
,
size
:
5
,
title
:
link
.
attr
(
'title'
),
tabindex
:
"-1"
})
.
change
(
function
()
{
rcmail
.
files_upload
(
'#filesuploadform'
);
})
.
click
(
function
()
{
setTimeout
(
function
()
{
link
.
mouseleave
();
},
20
);
})
// opacity:0 does the trick, display/visibility doesn't work
.
css
({
opacity
:
0
,
cursor
:
'pointer'
,
outline
:
'none'
,
position
:
'absolute'
});
// In FF and IE we need to move the browser file-input's button under the cursor
// Thanks to the size attribute above we know the length of the input field
if
(
bw
.
mz
||
bw
.
ie
)
file
.
css
({
marginLeft
:
'-80px'
});
// Note: now, I observe problem with cursor style on FF < 4 only
// Need position: relative (Bug #2615)
link
.
css
({
overflow
:
'hidden'
,
cursor
:
'pointer'
,
position
:
'relative'
})
.
mouseenter
(
function
()
{
this
.
__active
=
true
;
})
// place button under the cursor
.
mousemove
(
function
(
e
)
{
if
(
rcmail
.
commands
[
'files-upload'
]
&&
this
.
__active
)
move_file_input
(
e
);
// move the input away if button is disabled
else
$
(
this
).
mouseleave
();
})
.
mouseleave
(
function
()
{
file
.
css
({
top
:
'-10000px'
,
left
:
'-10000px'
});
this
.
__active
=
false
;
})
.
attr
(
'onclick'
,
''
)
// remove default button action
.
click
(
function
(
e
)
{
// forward click if mouse-enter event was missed
if
(
rcmail
.
commands
[
'files-upload'
]
&&
!
this
.
__active
)
{
this
.
__active
=
true
;
move_file_input
(
e
);
file
.
trigger
(
e
);
}
})
.
mouseleave
()
// initially disable/hide input
.
append
(
file
);
};
/***********************************************************/
/********** Main functionality **********/
/***********************************************************/
// for reordering column array (Konqueror workaround)
// and for setting some files/sessions list global variables
function
kolab_files_list_coltypes
(
type
)
{
if
(
!
type
)
type
=
'files'
;
var
n
,
list
=
rcmail
[
type
+
'list'
];
rcmail
.
env
.
subject_col
=
null
;
if
((
n
=
$
.
inArray
(
'name'
,
rcmail
.
env
[
type
+
'_coltypes'
]))
>=
0
)
{
rcmail
.
env
.
subject_col
=
n
;
list
.
subject_col
=
n
;
}
list
.
init_header
();
};
function
kolab_files_set_list_options
(
cols
,
sort_col
,
sort_order
,
type
)
{
var
update
=
0
,
i
,
idx
,
name
,
newcols
=
[],
oldcols
=
rcmail
.
env
[
type
+
'_coltypes'
];
if
(
sort_col
===
undefined
)
sort_col
=
rcmail
.
env
[
type
+
'_sort_col'
];
if
(
!
sort_order
)
sort_order
=
rcmail
.
env
[
type
+
'_sort_order'
];
if
(
rcmail
.
env
[
type
+
'_sort_col'
]
!=
sort_col
||
rcmail
.
env
[
type
+
'_sort_order'
]
!=
sort_order
)
{
update
=
1
;
// set table header class
kolab_files_set_list_sorting
(
sort_col
,
sort_order
,
type
);
}
if
(
cols
&&
cols
.
length
)
{
// make sure new columns are added at the end of the list
for
(
i
=
0
;
i
<
oldcols
.
length
;
i
++
)
{
name
=
oldcols
[
i
];
idx
=
$
.
inArray
(
name
,
cols
);
if
(
idx
!=
-
1
)
{
newcols
.
push
(
name
);
delete
cols
[
idx
];
}
}
for
(
i
=
0
;
i
<
cols
.
length
;
i
++
)
if
(
cols
[
i
])
newcols
.
push
(
cols
[
i
]);
if
(
newcols
.
join
()
!=
oldcols
.
join
())
{
update
+=
2
;
oldcols
=
newcols
;
}
}
if
(
update
==
1
)
rcmail
.
command
(
type
+
'-list'
,
{
sort
:
sort_col
,
reverse
:
sort_order
==
'DESC'
});
else
if
(
update
)
{
rcmail
.
http_post
(
'files/prefs'
,
{
type
:
type
,
kolab_files_list_cols
:
oldcols
,
kolab_files_sort_col
:
sort_col
,
kolab_files_sort_order
:
sort_order
},
rcmail
.
set_busy
(
true
,
'loading'
));
}
};
function
kolab_files_set_list_sorting
(
sort_col
,
sort_order
,
type
)
{
// set table header class
var
old_col
=
rcmail
.
env
[
type
+
'_sort_col'
],
old_sort
=
rcmail
.
env
[
type
+
'_sort_order'
];
$
(
'#rcm'
+
old_col
).
removeClass
(
'sortedASC sortedDESC'
);
$
(
'#rcm'
+
sort_col
).
addClass
(
'sorted'
+
sort_order
);
rcmail
.
env
[
type
+
'_sort_col'
]
=
sort_col
;
rcmail
.
env
[
type
+
'_sort_order'
]
=
sort_order
;
};
function
kolab_files_set_coltypes
(
list
,
type
)
{
var
i
,
found
,
name
,
cols
=
list
.
list
.
tHead
.
rows
[
0
].
cells
;
rcmail
.
env
[
type
+
'_coltypes'
]
=
[];
for
(
i
=
0
;
i
<
cols
.
length
;
i
++
)
if
(
cols
[
i
].
id
&&
cols
[
i
].
id
.
match
(
/^rcm/
))
{
name
=
cols
[
i
].
id
.
replace
(
/^rcm/
,
''
);
rcmail
.
env
[
type
+
'_coltypes'
].
push
(
name
);
}
// if ((found = $.inArray('name', rcmail.env.files_coltypes)) >= 0)
// rcmail.env.subject_col = found;
rcmail
.
env
.
subject_col
=
list
.
subject_col
;
rcmail
.
http_post
(
'files/prefs'
,
{
kolab_files_list_cols
:
rcmail
.
env
[
type
+
'_coltypes'
],
type
:
type
});
};
function
kolab_files_sessions_list_dblclick
(
list
)
{
rcmail
.
command
(
'sessions-open'
);
};
function
kolab_files_sessions_list_select
(
list
)
{
var
selected
=
list
.
selection
.
length
;
rcmail
.
enable_command
(
'sessions-open'
,
selected
==
1
);
};
function
kolab_files_sessions_list_keypress
(
list
)
{
if
(
list
.
modkey
==
CONTROL_KEY
)
return
;
if
(
list
.
key_pressed
==
list
.
ENTER_KEY
)
{
// use setTimeout(), otherwise the opened dialog will be immediately closed
setTimeout
(
function
()
{
rcmail
.
command
(
'sessions-open'
);
},
50
);
}
// else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY)
// rcmail.command('sessions-delete');
};
function
kolab_files_list_dblclick
(
list
)
{
rcmail
.
command
(
'files-open'
);
};
function
kolab_files_list_select
(
list
)
{
var
selected
=
list
.
selection
.
length
;
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands_all
,
selected
);
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands
,
selected
==
1
);
// reset all-pages-selection
// if (list.selection.length && list.selection.length != list.rowcount)
// rcmail.select_all_mode = false;
if
(
selected
==
1
)
{
// get file mimetype
var
elem
=
$
(
'tr.selected'
,
list
.
list
),
type
=
elem
.
data
(
'type'
),
folder
=
file_api
.
file_path
(
elem
.
data
(
'file'
));
rcmail
.
env
.
viewer
=
file_api
.
file_type_supported
(
type
,
rcmail
.
env
.
files_caps
);
if
(
!
file_api
.
is_writable
(
folder
))
rcmail
.
enable_command
(
'files-delete'
,
'files-rename'
,
false
);
}
else
rcmail
.
env
.
viewer
=
0
;
rcmail
.
enable_command
(
'files-edit'
,
(
rcmail
.
env
.
viewer
&
4
)
==
4
);
rcmail
.
enable_command
(
'files-open'
,
rcmail
.
env
.
viewer
);
};
function
kolab_files_list_keypress
(
list
)
{
if
(
list
.
modkey
==
CONTROL_KEY
)
return
;
if
(
list
.
key_pressed
==
list
.
ENTER_KEY
)
rcmail
.
command
(
'files-open'
);
else
if
(
list
.
key_pressed
==
list
.
DELETE_KEY
||
list
.
key_pressed
==
list
.
BACKSPACE_KEY
)
rcmail
.
command
(
'files-delete'
);
};
function
kolab_files_drag_start
(
e
)
{
rcmail
.
env
.
drag_target
=
null
;
if
(
rcmail
.
folder_list
)
rcmail
.
folder_list
.
drag_start
();
};
function
kolab_files_drag_end
(
e
)
{
if
(
rcmail
.
folder_list
)
{
rcmail
.
folder_list
.
drag_end
();
if
(
rcmail
.
env
.
drag_target
)
{
var
modkey
=
rcube_event
.
get_modifier
(
e
),
menu
=
rcmail
.
gui_objects
.
file_dragmenu
;
rcmail
.
fileslist
.
draglayer
.
hide
();
if
(
menu
&&
modkey
==
SHIFT_KEY
&&
rcmail
.
commands
[
'files-copy'
])
{
var
pos
=
rcube_event
.
get_mouse_pos
(
e
);
rcmail
.
show_menu
(
menu
.
id
,
true
,
e
);
$
(
menu
).
css
({
top
:
(
pos
.
y
-
10
)
+
'px'
,
left
:
(
pos
.
x
-
10
)
+
'px'
});
return
;
}
rcmail
.
command
(
'files-move'
,
rcmail
.
env
.
drag_target
);
rcmail
.
env
.
drag_target
=
null
;
}
}
};
function
kolab_files_drag_move
(
e
)
{
if
(
rcmail
.
folder_list
)
{
var
mouse
=
rcube_event
.
get_mouse_pos
(
e
);
rcmail
.
env
.
drag_target
=
rcmail
.
folder_list
.
intersects
(
mouse
,
true
);
}
};
function
kolab_files_drag_menu_action
(
command
)
{
var
menu
=
rcmail
.
gui_objects
.
file_dragmenu
;
if
(
menu
)
$
(
menu
).
hide
();
rcmail
.
command
(
command
,
rcmail
.
env
.
drag_target
);
};
function
kolab_files_selected
()
{
var
files
=
[];
$
.
each
(
rcmail
.
fileslist
.
get_selection
(),
function
(
i
,
v
)
{
var
name
,
row
=
$
(
'#rcmrow'
+
v
);
if
(
row
.
length
==
1
&&
(
name
=
row
.
data
(
'file'
)))
files
.
push
(
name
);
});
return
files
;
};
function
kolab_files_frame_load
(
frame
)
{
var
win
=
frame
.
contentWindow
,
info
=
rcmail
.
env
.
file_data
;
try
{
rcmail
.
file_editor
=
win
.
file_editor
;
}
catch
(
e
)
{};
rcmail
.
enable_command
(
'files-edit'
,
(
rcmail
.
file_editor
&&
rcmail
.
file_editor
.
editable
)
||
rcmail
.
env
.
editor_type
||
(
file_api
.
file_type_supported
(
rcmail
.
env
.
file_data
.
type
,
rcmail
.
env
.
files_caps
)
&
4
));
rcmail
.
enable_command
(
'files-print'
,
(
rcmail
.
file_editor
&&
rcmail
.
file_editor
.
printable
)
||
(
info
&&
/^image\//i
.
test
(
info
.
type
)));
// Enable image tools
rcmail
.
enable_command
(
'image-scale'
,
'image-rotate'
,
info
&&
!!
/^image\//
.
test
(
info
.
type
));
rcmail
.
gui_objects
.
messagepartframe
=
frame
;
// on edit page switch immediately to edit mode
if
(
rcmail
.
file_editor
&&
rcmail
.
file_editor
.
editable
&&
rcmail
.
env
.
action
==
'edit'
)
rcmail
.
files_edit
();
// detect Print button and check if it can be accessed
try
{
if
(
$
(
'#fileframe'
).
contents
().
find
(
'#print'
).
length
)
rcmail
.
enable_command
(
'files-print'
,
true
);
}
catch
(
e
)
{};
};
// activate html5 file drop feature (if browser supports it)
function
kolab_files_drag_drop_init
(
container
)
{
if
(
!
window
.
FormData
&&
!
(
window
.
XMLHttpRequest
&&
XMLHttpRequest
.
prototype
&&
XMLHttpRequest
.
prototype
.
sendAsBinary
))
{
return
;
}
if
(
!
container
.
length
)
return
;
$
(
document
.
body
).
bind
(
'dragover dragleave drop'
,
function
(
e
)
{
if
(
!
file_api
.
is_writable
())
return
;
e
.
preventDefault
();
container
[
e
.
type
==
'dragover'
?
'addClass'
:
'removeClass'
](
'active'
);
});
container
.
bind
(
'dragover dragleave'
,
function
(
e
)
{
return
kolab_files_drag_hover
(
e
);
})
container
.
children
(
'div'
).
bind
(
'dragover dragleave'
,
function
(
e
)
{
return
kolab_files_drag_hover
(
e
);
})
container
.
get
(
0
).
addEventListener
(
'drop'
,
function
(
e
)
{
// abort event and reset UI
kolab_files_drag_hover
(
e
);
return
file_api
.
file_drop
(
e
);
},
false
);
};
// handler for drag/drop on element
function
kolab_files_drag_hover
(
e
)
{
if
(
!
file_api
.
is_writable
())
return
;
e
.
preventDefault
();
e
.
stopPropagation
();
var
elem
=
$
(
e
.
target
);
if
(
!
elem
.
hasClass
(
'droptarget'
))
elem
=
elem
.
parents
(
'.droptarget'
);
elem
[
e
.
type
==
'dragover'
?
'addClass'
:
'removeClass'
](
'hover'
);
};
// returns localized file size
function
kolab_files_file_size
(
size
)
{
var
i
,
units
=
[
'GB'
,
'MB'
,
'KB'
,
'B'
];
size
=
file_api
.
file_size
(
size
);
for
(
i
=
0
;
i
<
units
.
length
;
i
++
)
if
(
size
.
toUpperCase
().
indexOf
(
units
[
i
])
>
0
)
return
size
.
replace
(
units
[
i
],
rcmail
.
gettext
(
units
[
i
]));
return
size
;
};
function
kolab_files_progress_str
(
param
)
{
var
current
,
total
=
file_api
.
file_size
(
param
.
total
).
toUpperCase
();
if
(
total
.
indexOf
(
'GB'
)
>
0
)
current
=
parseFloat
(
param
.
current
/
1073741824
).
toFixed
(
1
);
else
if
(
total
.
indexOf
(
'MB'
)
>
0
)
current
=
parseFloat
(
param
.
current
/
1048576
).
toFixed
(
1
);
else
if
(
total
.
indexOf
(
'KB'
)
>
0
)
current
=
parseInt
(
param
.
current
/
1024
);
else
current
=
param
.
current
;
total
=
kolab_files_file_size
(
param
.
total
);
return
rcmail
.
gettext
(
'uploadprogress'
)
.
replace
(
/\$percent/
,
param
.
percent
+
'%'
)
.
replace
(
/\$current/
,
current
)
.
replace
(
/\$total/
,
total
);
};
function
kolab_files_share_form_init
()
{
$
(
'fieldset > table'
,
rcmail
.
gui_objects
.
shareform
).
each
(
function
()
{
var
cnt
=
0
,
mode
=
$
(
this
).
data
(
'mode'
),
single
=
$
(
this
).
data
(
'single'
);
$
(
'tbody > tr'
,
this
).
each
(
function
(
i
,
row
)
{
if
(
!
i
)
{
$
(
'button.submit'
,
row
).
on
(
'click'
,
function
()
{
file_api
.
sharing_submit
(
rcmail
.
env
.
folder
,
row
,
mode
);
});
$
(
'input[data-autocomplete]'
).
each
(
function
()
{
var
input
=
$
(
this
),
req_name
=
'filesac-'
+
mode
;
kolab_files_autocomplete
(
input
,
req_name
,
function
(
e
)
{
$
(
row
).
find
(
'input[type=hidden]'
).
each
(
function
()
{
$
(
this
).
val
(
e
.
data
[
this
.
name
]
||
''
);
});
});
});
}
else
{
cnt
++
;
$
(
'button.delete'
,
row
).
on
(
'click'
,
function
()
{
file_api
.
sharing_delete
(
rcmail
.
env
.
folder
,
row
,
mode
);
});
$
(
'select,input[type=text]'
,
row
).
on
(
'change'
,
function
()
{
file_api
.
sharing_update
(
rcmail
.
env
.
folder
,
row
,
mode
);
});
}
});
if
(
single
&&
cnt
)
{
$
(
'tbody > tr:first'
,
this
).
find
(
'button.submit, input, select'
).
prop
(
'disabled'
,
true
);
}
});
};
function
kolab_files_autocomplete
(
input
,
action
,
insert_callback
)
{
rcmail
.
init_address_input_events
(
input
,
{
action
:
action
});
// "Redirect" autocomplete requests to Chwala API
if
(
rcmail
.
env
.
files_api_version
>
3
)
{
rcmail
.
addEventListener
(
'request'
+
action
,
function
(
post
)
{
var
params
=
{
search
:
post
.
_search
,
mode
:
input
.
data
(
'autocomplete'
)
||
'user'
,
folder
:
rcmail
.
env
.
folder
},
callback
=
function
(
response
)
{
var
result
=
response
.
result
||
[];
$
.
each
(
result
,
function
()
{
// add fake email to skip Roundcube's group expanding code
if
(
this
.
type
==
'group'
&&
!
this
.
email
)
this
.
email
=
1
;
});
rcmail
.
ksearch_query_results
(
result
,
post
.
_search
,
post
.
_reqid
);
},
error_callback
=
function
(
o
,
status
,
err
,
data
)
{
file_api
.
http_error
(
o
,
status
,
err
,
data
);
rcmail
.
ksearch_query_results
([],
post
.
_search
,
post
.
_reqid
);
};
return
file_api
.
get
(
'autocomplete'
,
params
,
callback
,
error_callback
);
});
}
// Update hidden fields on selection
rcmail
.
addEventListener
(
'autocomplete_insert'
,
function
(
e
)
{
if
(
e
.
field
==
input
[
0
])
{
input
.
val
(
e
.
insert
.
replace
(
/[, ]+$/
,
''
));
}
if
(
insert_callback
)
insert_callback
(
e
);
});
};
/**********************************************************/
/********* document editor functionality **********/
/**********************************************************/
// Initialize document toolbar functionality
function
document_editor_init
()
{
var
info
=
rcmail
.
env
.
file_data
;
rcmail
.
enable_command
(
'document-export'
,
'document-print'
,
true
);
if
(
info
&&
info
.
session
&&
info
.
session
.
is_owner
)
rcmail
.
enable_command
(
'document-close'
,
'document-editors'
,
true
);
};
// executed on editing session termination
function
document_editor_close
()
{
var
dialog
=
$
(
'<div>'
).
addClass
(
'popupdialog'
).
attr
(
'role'
,
'alertdialog'
)
.
html
(
$
(
'<span>'
).
text
(
rcmail
.
gettext
(
'kolab_files.sessionterminated'
)));
rcmail
.
alert_dialog
(
dialog
,
function
()
{
window
.
close
();
},
{
title
:
rcmail
.
gettext
(
'kolab_files.sessionterminatedtitle'
)
});
return
false
;
// skip Chwala's error message
};
rcube_webmail
.
prototype
.
document_save
=
function
()
{
document_editor
.
save
(
function
(
data
)
{
rcmail
.
enable_command
(
'document-save'
,
false
);
});
};
rcube_webmail
.
prototype
.
document_export
=
function
(
type
)
{
document_editor
.
export
(
type
||
'odt'
);
};
rcube_webmail
.
prototype
.
document_print
=
function
()
{
document_editor
.
print
();
};
rcube_webmail
.
prototype
.
document_editors
=
function
()
{
kolab_files_editors_dialog
();
};
// close editing session
rcube_webmail
.
prototype
.
document_close
=
function
()
{
var
delete_fn
=
function
()
{
document_editor
.
terminate
(
function
()
{
var
win
=
window
.
opener
||
window
.
parent
;
if
(
win
&&
win
.
rcmail
&&
win
.
file_api
)
win
.
file_api
.
document_delete
(
rcmail
.
env
.
file_data
.
session
.
id
);
// For Elastic: hide the parent dialog
if
(
rcmail
.
is_framed
())
{
parent
.
$
(
'.ui-dialog:visible button.cancel'
).
click
();
}
window
.
close
();
});
};
// check document "unsaved changes" state and display a warning
// skip the warning for WOPI, Collabora will save the document anyway on session close
if
(
this
.
commands
[
'document-save'
]
&&
(
!
this
.
env
.
file_data
.
viewer
||
!
this
.
env
.
file_data
.
viewer
.
wopi
))
this
.
confirm_dialog
(
this
.
gettext
(
'kolab_files.unsavedchanges'
),
'kolab_files.terminate'
,
delete_fn
,
{
button_class
:
'delete'
});
else
delete_fn
();
};
// document editors management dialog
function
kolab_files_editors_dialog
(
session
)
{
var
items
=
[],
buttons
=
{},
info
=
rcmail
.
env
.
file_data
,
dialog
=
$
(
'#document-editors-dialog'
),
comment
=
$
(
'#invitation-comment'
);
if
(
!
info
||
!
info
.
session
||
!
info
.
session
.
is_owner
)
return
;
// always add the session organizer
items
.
push
(
kolab_files_attendee_record
(
info
.
session
.
owner
,
'organizer'
));
$
.
each
(
info
.
session
.
invitations
||
[],
function
(
i
,
u
)
{
var
record
=
kolab_files_attendee_record
(
u
.
user
,
u
.
status
,
u
.
user_name
);
items
.
push
(
record
);
info
.
session
.
invitations
[
i
].
record
=
record
;
});
$
(
'table > tbody'
,
dialog
).
html
(
items
);
buttons
[
rcmail
.
gettext
(
'kolab_files.close'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.manageeditors'
),
buttons
:
buttons
,
button_classes
:
[
'cancel'
]
});
if
(
!
rcmail
.
env
.
editors_dialog
)
{
rcmail
.
env
.
editors_dialog
=
dialog
;
kolab_files_autocomplete
(
$
(
'#invitation-editor-name'
),
'files/autocomplete'
,
function
(
e
)
{
var
success
=
false
;
if
(
e
.
field
.
name
==
'participant'
)
{
// e.data && e.data.type == 'group' ? 'GROUP' : 'INDIVIDUAL'
success
=
kolab_files_add_attendees
(
e
.
insert
,
comment
.
val
());
}
if
(
e
.
field
&&
success
)
{
e
.
field
.
value
=
''
;
}
});
$
(
'#invitation-editor-add'
).
click
(
function
()
{
var
input
=
$
(
'#invitation-editor-name'
);
rcmail
.
ksearch_blur
();
if
(
kolab_files_add_attendees
(
input
.
val
(),
comment
.
val
()))
{
input
.
val
(
''
);
}
});
}
};
// add the given list of participants
function
kolab_files_add_attendees
(
names
,
comment
)
{
var
i
,
item
,
success
,
email
,
name
,
attendees
=
{},
counter
=
0
;
names
=
file_api
.
explode_quoted_string
(
names
.
replace
(
/,\s*$/
,
''
),
','
);
// parse name/email pairs
for
(
i
=
0
;
i
<
names
.
length
;
i
++
)
{
email
=
name
=
''
;
item
=
$
.
trim
(
names
[
i
]);
if
(
!
item
.
length
)
{
continue
;
}
// address in brackets without name (do nothing)
else
if
(
item
.
match
(
/^<[^@]+@[^>]+>$/
))
{
email
=
item
.
replace
(
/[<>]/g
,
''
);
}
// address without brackets and without name (add brackets)
else
if
(
rcube_check_email
(
item
))
{
email
=
item
;
}
// address with name
else
if
(
item
.
match
(
/([^\s<@]+@[^>]+)>*$/
))
{
email
=
RegExp
.
$1
;
name
=
item
.
replace
(
email
,
''
).
replace
(
/^["\s<>]+/
,
''
).
replace
(
/["\s<>]+$/
,
''
);
}
if
(
email
)
{
attendees
[
email
]
=
{
user
:
email
,
name
:
name
};
counter
++
;
}
else
{
rcmail
.
alert_dialog
(
rcmail
.
gettext
(
'noemailwarning'
));
}
}
success
=
counter
>
0
;
// remove already existing entries
if
(
counter
)
{
if
(
attendees
[
rcmail
.
env
.
file_data
.
session
.
owner
])
{
delete
attendees
[
this
.
user
];
counter
--
;
}
$
.
each
(
rcmail
.
env
.
file_data
.
session
.
invitations
||
[],
function
()
{
if
(
this
.
user
in
attendees
)
{
delete
attendees
[
this
.
user
];
counter
--
;
}
});
}
if
(
counter
)
file_api
.
document_invite
(
rcmail
.
env
.
file_data
.
session
.
id
,
attendees
,
comment
);
return
success
;
};
function
kolab_files_attendee_record
(
user
,
status
,
username
)
{
var
options
=
[],
select
,
type
=
status
?
status
.
replace
(
/-.*$/
,
''
)
:
''
,
name
=
$
(
'<td class="name">'
).
text
(
user
),
buttons
=
$
(
'<td class="options">'
),
state
=
$
(
'<td class="status">'
).
text
(
rcmail
.
gettext
(
'kolab_files.status'
+
type
));
// @todo: accept/decline invitation request
if
(
type
==
'requested'
||
status
==
'accepted-owner'
||
status
==
'declined-owner'
)
{
select
=
$
(
'<select>'
).
change
(
function
()
{
var
val
=
$
(
this
).
val
(),
map
=
{
accepted
:
'invitation_accept'
,
declined
:
'invitation_decline'
};
if
(
map
[
val
])
document_editor
[
map
[
val
]]({
user
:
user
,
session_id
:
rcmail
.
env
.
file_data
.
session
.
id
});
});
if
(
type
==
'requested'
)
options
.
push
(
$
(
'<option>'
).
text
(
rcmail
.
gettext
(
'kolab_files.statusrequested'
)).
attr
(
'value'
,
'requested'
));
options
.
push
(
$
(
'<option>'
).
text
(
rcmail
.
gettext
(
'kolab_files.statusaccepted'
)).
attr
(
'value'
,
'accepted'
));
options
.
push
(
$
(
'<option>'
).
text
(
rcmail
.
gettext
(
'kolab_files.statusdeclined'
)).
attr
(
'value'
,
'declined'
));
state
.
html
(
select
.
html
(
options
).
val
(
type
));
}
// delete button
if
(
status
!=
'organizer'
)
{
$
(
'<a>'
).
attr
({
'class'
:
'delete'
,
href
:
'#'
,
title
:
rcmail
.
gettext
(
'kolab_files.removeparticipant'
)})
.
click
(
function
()
{
file_api
.
document_cancel
(
rcmail
.
env
.
file_data
.
session
.
id
,
[
user
]);
})
.
appendTo
(
buttons
);
}
if
(
username
&&
status
!=
'organizer'
)
name
.
html
(
$
(
'<a>'
).
attr
({
href
:
'mailto:'
+
user
,
'class'
:
'mailtolink'
}).
text
(
username
))
.
click
(
function
(
e
)
{
rcmail
.
command
(
'compose'
,
user
,
e
.
target
,
e
);
return
false
;
});
return
$
(
'<tr>'
).
attr
(
'class'
,
'invitation'
+
(
type
?
' '
+
type
:
''
))
.
append
(
name
).
append
(
state
).
append
(
buttons
);
};
function
document_editor_invitation_handler
(
invitation
)
{
// make the "More" link clickable
$
(
'#'
+
invitation
.
id
).
parent
(
'div'
).
click
(
function
()
{
kolab_files_invitation_dialog
(
invitation
);
});
};
function
kolab_files_invitation_dialog
(
invitation
)
{
var
text
,
records
=
[],
content
=
[],
buttons
=
{},
button_classes
=
[],
dialog
=
$
(
'#document-invitation-dialog'
),
data_map
=
{
status
:
'status'
,
'changed'
:
'when'
,
filename
:
'file'
,
comment
:
'comment'
},
record_fn
=
function
(
type
,
label
,
value
)
{
records
.
push
(
$
(
'<tr>'
).
attr
(
'class'
,
type
)
.
append
(
$
(
'<td class="label">'
).
text
(
rcmail
.
gettext
(
'kolab_files.'
+
label
)))
.
append
(
$
(
'<td>'
).
text
(
value
))
);
};
join_session
=
function
()
{
var
viewer
=
file_api
.
file_type_supported
(
'application/vnd.oasis.opendocument.text'
,
rcmail
.
env
.
files_caps
);
params
=
{
action
:
'edit'
,
session
:
invitation
.
session_id
};
file_api
.
file_open
(
''
,
viewer
,
params
);
};
if
(
!
dialog
.
length
)
dialog
=
$
(
'<div>'
).
attr
({
id
:
'document-invitation-dialog'
,
role
:
'dialog'
,
'aria-hidden'
:
'true'
})
.
append
(
$
(
'<div>'
))
.
appendTo
(
document
.
body
);
if
(
!
invitation
.
is_session_owner
)
{
if
(
invitation
.
status
==
'invited'
)
{
text
=
document_editor
.
invitation_msg
(
invitation
);
button_classes
=
[
'session join'
,
'session accept'
,
'session decline delete'
];
buttons
[
rcmail
.
gettext
(
'kolab_files.join'
)]
=
function
()
{
join_session
();
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.accept'
)]
=
function
()
{
document_editor
.
invitation_accept
(
invitation
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.decline'
)]
=
function
()
{
document_editor
.
invitation_decline
(
invitation
);
kolab_dialog_close
(
this
);
};
}
else
if
(
invitation
.
status
==
'declined-owner'
)
{
// @todo: add option to request for an invitation again?
text
=
document_editor
.
invitation_msg
(
invitation
);
}
else
if
(
invitation
.
status
==
'accepted-owner'
)
{
text
=
document_editor
.
invitation_msg
(
invitation
);
button_classes
=
[
'mainaction session join'
];
buttons
[
rcmail
.
gettext
(
'kolab_files.join'
)]
=
function
()
{
join_session
();
kolab_dialog_close
(
this
);
};
}
}
else
{
if
(
invitation
.
status
==
'accepted'
)
{
text
=
document_editor
.
invitation_msg
(
invitation
);
}
else
if
(
invitation
.
status
==
'declined'
)
{
// @todo: add option to invite the user again?
text
=
document_editor
.
invitation_msg
(
invitation
);
}
else
if
(
invitation
.
status
==
'requested'
)
{
text
=
document_editor
.
invitation_msg
(
invitation
);
button_classes
=
[
'session accept'
,
'session decline delete'
];
buttons
[
rcmail
.
gettext
(
'kolab_files.accept'
)]
=
function
()
{
document_editor
.
invitation_accept
(
invitation
);
kolab_dialog_close
(
this
);
};
buttons
[
rcmail
.
gettext
(
'kolab_files.decline'
)]
=
function
()
{
document_editor
.
invitation_decline
(
invitation
);
kolab_dialog_close
(
this
);
};
}
}
if
(
text
)
{
$
.
each
(
data_map
,
function
(
i
,
label
)
{
var
value
=
invitation
[
i
];
if
(
value
)
{
if
(
i
==
'status'
)
value
=
rcmail
.
gettext
(
'kolab_files.status'
+
value
.
replace
(
/-.*$/
,
''
));
record_fn
(
i
,
label
,
value
);
}
});
content
.
push
(
$
(
'<div>'
).
text
(
text
));
content
.
push
(
$
(
'<table class="propform">'
).
html
(
records
));
}
button_classes
.
push
(
'cancel'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.close'
)]
=
function
()
{
kolab_dialog_close
(
this
);
};
$
(
'div'
,
dialog
).
html
(
content
);
// show dialog window
kolab_dialog_show
(
dialog
,
{
title
:
rcmail
.
gettext
(
'kolab_files.invitationtitle'
).
replace
(
'$file'
,
invitation
.
filename
),
buttons
:
buttons
,
button_classes
:
button_classes
});
};
/***********************************************************/
/********** Commands **********/
/***********************************************************/
rcube_webmail
.
prototype
.
files_sort
=
function
(
props
)
{
this
.
files_sort_handler
(
props
,
'files'
);
};
rcube_webmail
.
prototype
.
sessions_sort
=
function
(
props
)
{
this
.
files_sort_handler
(
props
,
'sessions'
);
};
rcube_webmail
.
prototype
.
files_sort_handler
=
function
(
col
,
type
)
{
var
params
=
{},
c
=
type
==
'files'
?
''
:
(
'_'
+
type
),
sort_order
=
this
.
env
[
type
+
'_sort_order'
],
sort_col
=
!
this
.
env
[
'kolab_files'
+
c
+
'_disabled_sort_col'
]
?
col
:
this
.
env
[
type
+
'_sort_col'
];
if
(
!
this
.
env
[
'kolab_files'
+
c
+
'_disabled_sort_order'
])
sort_order
=
this
.
env
[
type
+
'_sort_col'
]
==
sort_col
&&
sort_order
==
'ASC'
?
'DESC'
:
'ASC'
;
// set table header and update env
kolab_files_set_list_sorting
(
sort_col
,
sort_order
,
type
);
this
.
http_post
(
'files/prefs'
,
{
kolab_files_sort_col
:
sort_col
,
kolab_files_sort_order
:
sort_order
,
type
:
type
});
params
.
sort
=
sort_col
;
params
.
reverse
=
sort_order
==
'DESC'
;
this
.
command
(
type
+
'-list'
,
params
);
};
rcube_webmail
.
prototype
.
files_search
=
function
()
{
var
value
=
$
(
this
.
gui_objects
.
filesearchbox
).
val
();
if
(
value
)
file_api
.
file_search
(
value
,
$
(
'#search_all_folders'
).
is
(
':checked'
));
else
file_api
.
file_search_reset
();
};
rcube_webmail
.
prototype
.
files_search_reset
=
function
()
{
$
(
this
.
gui_objects
.
filesearchbox
).
val
(
''
);
file_api
.
file_search_reset
();
};
rcube_webmail
.
prototype
.
files_folder_delete
=
function
(
prop
,
elem
,
event
)
{
this
.
hide_menu
(
'folderoptions'
,
event
);
this
.
confirm_dialog
(
this
.
get_label
(
'kolab_files.folderdeleteconfirm'
),
'delete'
,
function
()
{
file_api
.
folder_delete
(
file_api
.
env
.
folder
);
});
};
rcube_webmail
.
prototype
.
files_delete
=
function
()
{
this
.
confirm_dialog
(
this
.
get_label
(
'kolab_files.filedeleteconfirm'
),
'delete'
,
function
()
{
var
files
=
rcmail
.
env
.
file
?
[
rcmail
.
env
.
file
]
:
kolab_files_selected
();
file_api
.
file_delete
(
files
);
});
};
rcube_webmail
.
prototype
.
files_move
=
function
(
folder
,
obj
,
event
,
files
)
{
if
(
!
files
)
files
=
kolab_files_selected
();
if
(
!
folder
)
{
var
ref
=
this
;
return
this
.
files_folder_selector
(
event
,
function
(
folder
)
{
ref
.
files_move
(
folder
,
null
,
event
,
files
);
});
}
file_api
.
file_move
(
files
,
folder
);
};
rcube_webmail
.
prototype
.
files_copy
=
function
(
folder
,
obj
,
event
,
files
)
{
if
(
!
files
)
files
=
kolab_files_selected
();
if
(
!
folder
)
{
var
ref
=
this
;
return
this
.
files_folder_selector
(
event
,
function
(
folder
)
{
ref
.
files_copy
(
folder
,
null
,
event
,
files
);
});
}
file_api
.
file_copy
(
files
,
folder
);
};
// create folder selector popup
rcube_webmail
.
prototype
.
files_folder_selector
=
function
(
event
,
callback
)
{
if
(
this
.
folder_selector_reset
)
this
.
destroy_entity_selector
(
'folder-selector'
);
// The list is incomplete, reset needed before next use
this
.
folder_selector_reset
=
file_api
.
list_updates
>
0
;
this
.
entity_selector
(
'folder-selector'
,
callback
,
file_api
.
env
.
folders
,
function
(
folder
,
a
,
folder_fullname
)
{
var
n
=
folder
.
depth
||
0
,
row
=
$
(
'<li>'
);
if
(
folder
.
virtual
||
folder
.
readonly
)
a
.
addClass
(
'virtual'
).
attr
({
'aria-disabled'
:
'true'
,
tabindex
:
'-1'
});
else
a
.
addClass
(
'active'
).
data
(
'id'
,
folder_fullname
);
a
.
css
(
'padding-left'
,
n
?
(
n
*
16
)
+
'px'
:
0
);
// add folder name element
a
.
append
(
$
(
'<span>'
).
text
(
folder
.
name
));
return
row
.
append
(
a
);
},
event
);
};
rcube_webmail
.
prototype
.
files_upload
=
function
(
form
)
{
if
(
form
)
file_api
.
file_upload
(
form
);
};
rcube_webmail
.
prototype
.
files_list
=
function
(
param
)
{
// just rcmail wrapper, to handle command busy states
file_api
.
file_list
(
param
);
};
rcube_webmail
.
prototype
.
files_list_update
=
function
(
head
)
{
var
list
=
this
.
fileslist
;
$
(
'thead'
,
list
.
fixed_header
?
list
.
fixed_header
:
list
.
list
).
html
(
head
);
kolab_files_list_coltypes
();
file_api
.
file_list
();
};
rcube_webmail
.
prototype
.
sessions_list
=
function
(
param
)
{
// just rcmail wrapper, to handle command busy states
file_api
.
session_list
(
param
);
};
rcube_webmail
.
prototype
.
sessions_list_update
=
function
(
head
)
{
var
list
=
this
.
sessionslist
;
$
(
'thead'
,
list
.
fixed_header
?
list
.
fixed_header
:
list
.
list
).
html
(
head
);
kolab_files_list_coltypes
(
'sessions'
);
file_api
.
sessions_list
();
};
rcube_webmail
.
prototype
.
files_get
=
function
()
{
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
);
};
// enable file editor
rcube_webmail
.
prototype
.
files_edit
=
function
(
session
)
{
var
files
,
readonly
,
sessions
,
file
=
this
.
env
.
file
,
params
=
{
action
:
'edit'
};
if
(
!
file
&&
!
this
.
env
.
action
)
{
files
=
kolab_files_selected
();
if
(
files
.
length
==
1
)
file
=
files
[
0
];
readonly
=
!
file_api
.
is_writable
(
file_api
.
file_path
(
file
));
}
else
{
readonly
=
!
this
.
env
.
file_data
.
writable
;
}
// check if the folder is read-only or there are ongoing sessions
// in such cases display dialog for the user to decide what to do
if
(
!
session
)
{
sessions
=
file_api
.
file_sessions
(
file
);
if
(
sessions
.
length
||
readonly
)
{
kolab_files_file_edit_dialog
(
file
,
sessions
,
readonly
);
return
;
}
}
else
if
(
session
!==
true
)
params
.
session
=
session
;
if
(
this
.
file_editor
&&
this
.
file_editor
.
editable
&&
!
session
)
{
this
.
file_editor
.
enable
();
this
.
enable_command
(
'files-save'
,
true
);
}
else
if
(
this
.
env
.
file
)
{
var
viewer
=
file_api
.
file_type_supported
(
this
.
env
.
file_data
.
type
,
this
.
env
.
files_caps
);
params
.
local
=
true
;
file_api
.
file_open
(
file
,
viewer
,
params
);
}
else
if
(
file
)
{
file_api
.
file_open
(
file
,
this
.
env
.
viewer
,
params
);
}
};
// save changes to the file
rcube_webmail
.
prototype
.
files_save
=
function
()
{
if
(
!
this
.
file_editor
)
return
;
// binary files like ODF need to be updated using FormData
if
(
this
.
file_editor
.
getContentCallback
)
{
if
(
!
file_api
.
file_uploader_support
())
return
;
file_api
.
req
=
file_api
.
set_busy
(
true
,
'saving'
);
// this.file_editor.disable();
this
.
file_editor
.
getContentCallback
(
function
(
content
,
filename
)
{
file_api
.
file_uploader
([
content
],
{
action
:
'file_update'
,
params
:
{
file
:
rcmail
.
env
.
file
,
info
:
1
,
token
:
file_api
.
env
.
token
},
response_handler
:
'file_save_response'
,
fieldname
:
'content'
,
single
:
true
});
});
return
;
}
var
content
=
this
.
file_editor
.
getContent
();
file_api
.
file_save
(
this
.
env
.
file
,
content
);
};
rcube_webmail
.
prototype
.
files_print
=
function
()
{
if
(
this
.
file_editor
&&
this
.
file_editor
.
printable
)
this
.
file_editor
.
print
();
else
if
(
/^image\//i
.
test
(
this
.
env
.
file_data
.
type
))
{
var
frame
=
$
(
'#fileframe'
).
get
(
0
),
win
=
frame
?
frame
.
contentWindow
:
null
;
if
(
win
)
{
win
.
focus
();
win
.
print
();
}
}
else
{
// e.g. Print button in PDF viewer
try
{
$
(
'#fileframe'
).
contents
().
find
(
'#print'
).
click
();
}
catch
(
e
)
{};
}
};
rcube_webmail
.
prototype
.
files_set_quota
=
function
(
p
)
{
if
(
p
.
total
&&
window
.
file_api
)
{
p
.
used
*=
1024
;
p
.
total
*=
1024
;
p
.
title
=
file_api
.
file_size
(
p
.
used
)
+
' / '
+
file_api
.
file_size
(
p
.
total
)
+
' ('
+
p
.
percent
+
'%)'
;
}
p
.
type
=
this
.
env
.
quota_type
;
this
.
set_quota
(
p
);
};
rcube_webmail
.
prototype
.
files_create
=
function
()
{
kolab_files_file_create_dialog
();
};
rcube_webmail
.
prototype
.
files_rename
=
function
()
{
var
files
=
kolab_files_selected
();
kolab_files_file_rename_dialog
(
files
[
0
]);
};
rcube_webmail
.
prototype
.
folder_create
=
function
()
{
kolab_files_folder_create_dialog
();
};
rcube_webmail
.
prototype
.
folder_rename
=
function
(
prop
,
elem
,
event
)
{
this
.
hide_menu
(
'folderoptions'
,
event
);
kolab_files_folder_edit_dialog
();
};
rcube_webmail
.
prototype
.
folder_share
=
function
(
prop
,
elem
,
event
)
{
this
.
hide_menu
(
'folderoptions'
,
event
);
kolab_files_folder_share_dialog
();
};
rcube_webmail
.
prototype
.
folder_mount
=
function
(
prop
,
elem
,
event
)
{
this
.
hide_menu
(
'folderoptions'
,
event
);
kolab_files_folder_mount_dialog
();
};
// open a session dialog
rcube_webmail
.
prototype
.
sessions_open
=
function
()
{
var
id
=
this
.
sessionslist
.
get_selection
(),
session
=
id
?
file_api
.
env
.
sessions_list
[
id
]
:
null
;
if
(
session
)
kolab_files_session_dialog
(
session
);
};
/**********************************************************/
/********* Files API handler **********/
/**********************************************************/
function
kolab_files_ui
()
{
this
.
requests
=
{};
this
.
uploads
=
[];
this
.
list_updates
=
0
;
/*
// Called on "session expired" session
this.logout = function(response) {};
// called when a request timed out
this.request_timed_out = function() {};
// called on start of the request
this.set_request_time = function() {};
// called on request response
this.update_request_time = function() {};
*/
// set state
this
.
set_busy
=
function
(
a
,
message
)
{
if
(
this
.
req
)
rcmail
.
hide_message
(
this
.
req
);
return
rcmail
.
set_busy
(
a
,
message
);
};
// displays error message
this
.
display_message
=
function
(
label
,
type
)
{
return
rcmail
.
display_message
(
this
.
t
(
label
),
type
);
};
this
.
http_error
=
function
(
request
,
status
,
err
,
data
)
{
rcmail
.
http_error
(
request
,
status
,
err
,
data
?
data
.
req_id
:
null
);
};
// check if specified/current folder/view is writable
this
.
is_writable
=
function
(
folder
)
{
if
(
!
folder
)
folder
=
this
.
env
.
folder
;
if
(
!
folder
)
return
false
;
var
all_folders
=
$
.
extend
({},
this
.
env
.
folders
,
this
.
search_results
);
if
(
!
all_folders
[
folder
]
||
all_folders
[
folder
].
readonly
||
all_folders
[
folder
].
virtual
)
return
false
;
return
true
;
};
// Check if specified folder (hierarchy) supports sharing
this
.
is_shareable
=
function
(
folder
)
{
if
(
!
folder
)
folder
=
this
.
env
.
folder
;
if
(
!
folder
)
return
false
;
var
root
=
folder
.
split
(
this
.
env
.
directory_separator
)[
0
],
caps
=
this
.
env
.
caps
;
if
(
this
.
env
.
caps
.
MOUNTPOINTS
[
root
])
caps
=
root
!=
folder
?
this
.
env
.
caps
.
MOUNTPOINTS
[
root
]
:
{};
return
!!
caps
.
ACL
;
};
// folders list request
this
.
folder_list
=
function
(
params
,
update
)
{
if
(
!
params
)
params
=
{}
params
.
permissions
=
1
;
if
(
params
.
level
===
undefined
)
params
.
level
=
-
1
;
if
(
update
)
{
this
.
list_updates
++
;
params
.
req
=
rcmail
.
display_message
(
''
,
'loading'
);
}
else
{
params
.
req
=
this
.
set_busy
(
true
,
'loading'
);
this
.
list_params
=
params
;
}
this
.
request
(
'folder_list'
,
params
,
update
?
'folder_list_update_response'
:
'folder_list_response'
);
};
// folder list response handler
this
.
folder_list_response
=
function
(
response
,
params
)
{
rcmail
.
hide_message
(
params
.
req
);
if
(
!
this
.
response
(
response
))
return
;
var
folder
,
first
,
body
,
rows
=
[],
list_selector
=
rcmail
.
env
.
folder_list_selector
||
'#files-folder-list'
,
search_selector
=
rcmail
.
env
.
folder_search_selector
||
'#foldersearch'
,
elem
=
$
(
list_selector
),
searchbox
=
$
(
search_selector
),
list
=
$
(
'<ul class="treelist listing folderlist"></ul>'
),
collections
=
[
'audio'
,
'video'
,
'image'
,
'document'
];
// try parent window if the list element does not exist
// i.e. called from a dialog in parent window
if
(
!
elem
.
length
&&
rcmail
.
is_framed
()
&&
(
rcmail
.
env
.
task
!=
'files'
||
(
rcmail
.
env
.
action
!=
'open'
&&
rcmail
.
env
.
action
!=
'edit'
)))
{
body
=
window
.
parent
.
document
.
body
;
elem
=
$
(
list_selector
,
body
);
searchbox
=
$
(
search_selector
,
body
);
}
this
.
list_element
=
list
;
if
(
elem
.
data
(
'no-collections'
)
==
true
)
collections
=
[];
this
.
env
.
folders
=
this
.
folder_list_parse
(
response
.
result
&&
response
.
result
.
list
?
response
.
result
.
list
:
response
.
result
);
rcmail
.
enable_command
(
'files-create'
,
response
.
result
&&
response
.
result
.
list
&&
response
.
result
.
list
.
length
>
0
);
if
(
!
elem
.
length
)
return
;
elem
.
html
(
''
);
$
.
each
(
this
.
env
.
folders
,
function
(
i
,
f
)
{
var
row
;
if
(
row
=
file_api
.
folder_list_row
(
i
,
f
))
{
if
(
!
first
)
first
=
i
;
rows
.
push
(
row
);
}
});
// add virtual collections
$
.
each
(
collections
,
function
(
i
,
n
)
{
var
row
=
$
(
'<li class="mailbox collection '
+
n
+
'"></li>'
);
row
.
attr
(
'id'
,
'rcmli'
+
rcmail
.
html_identifier_encode
(
'folder-collection-'
+
n
))
.
append
(
$
(
'<a class="name"></a>'
).
text
(
rcmail
.
gettext
(
'kolab_files.collection_'
+
n
)))
rows
.
push
(
row
);
});
// add Sessions entry
if
(
rcmail
.
task
==
'files'
&&
!
rcmail
.
env
.
action
&&
this
.
env
.
caps
&&
this
.
env
.
caps
.
DOCEDIT
)
{
rows
.
push
(
$
(
'<li class="mailbox collection sessions"></li>'
)
.
attr
(
'id'
,
'rcmli'
+
rcmail
.
html_identifier_encode
(
'folder-collection-sessions'
))
.
append
(
$
(
'<a class="name"></a>'
).
text
(
rcmail
.
gettext
(
'kolab_files.sessions'
)))
);
}
list
.
append
(
rows
).
appendTo
(
elem
)
.
on
(
'click'
,
'a.subscription'
,
function
(
e
)
{
return
file_api
.
folder_list_subscription_button_click
(
this
);
})
.
on
(
'mouseover'
,
'a.name'
,
function
()
{
rcube_webmail
.
long_subject_title_ex
(
this
);
});
if
(
rcmail
.
task
==
'files'
&&
rcmail
.
env
.
contextmenu
)
list
.
on
(
'contextmenu'
,
function
(
e
)
{
var
elem
=
$
(
e
.
target
).
closest
(
'li'
);
id
=
rcmail
.
html_identifier_decode
(
elem
.
attr
(
'id'
).
replace
(
/^rcmli/
,
''
));
rcmail
.
contextmenu
.
show_one
(
e
,
elem
[
0
],
id
,
rcmail
.
env
.
folders_cm
);
});
if
(
rcmail
.
folder_list
)
{
rcmail
.
folder_list
.
reset
();
this
.
search_results_widget
=
null
;
}
// init treelist widget
rcmail
.
folder_list
=
new
rcube_treelist_widget
(
list
,
{
selectable
:
true
,
id_prefix
:
'rcmli'
,
parent_focus
:
true
,
searchbox
:
searchbox
,
id_encode
:
rcmail
.
html_identifier_encode
,
id_decode
:
rcmail
.
html_identifier_decode
,
check_droptarget
:
function
(
node
)
{
return
!
node
.
virtual
&&
node
.
id
!=
file_api
.
env
.
folder
&&
$
.
inArray
(
'readonly'
,
node
.
classes
)
==
-
1
&&
$
.
inArray
(
'collection'
,
node
.
classes
)
==
-
1
;
}
});
rcmail
.
folder_list
.
addEventListener
(
'collapse'
,
function
(
node
)
{
file_api
.
folder_collapsed
(
node
);
})
.
addEventListener
(
'expand'
,
function
(
node
)
{
file_api
.
folder_collapsed
(
node
);
})
.
addEventListener
(
'beforeselect'
,
function
(
node
)
{
return
!
rcmail
.
busy
;
})
.
addEventListener
(
'search'
,
function
(
search
)
{
file_api
.
folder_search
(
search
);
})
.
addEventListener
(
'select'
,
function
(
node
)
{
if
(
file_api
.
search_results_widget
)
file_api
.
search_results_widget
.
select
();
file_api
.
folder_select
(
node
.
id
);
});
// select first/current folder
if
(
response
.
result
.
auth_errors
&&
response
.
result
.
auth_errors
.
length
)
this
.
env
.
folder
=
this
.
env
.
collection
=
null
;
else
if
(
this
.
env
.
folder
)
rcmail
.
folder_list
.
select
(
this
.
env
.
folder
);
else
if
(
this
.
env
.
collection
)
rcmail
.
folder_list
.
select
(
'folder-collection-'
+
this
.
env
.
collection
);
else
if
(
folder
=
this
.
env
.
init_folder
)
{
if
(
this
.
env
.
folders
[
folder
])
{
this
.
env
.
init_folder
=
null
;
rcmail
.
folder_list
.
select
(
folder
);
}
}
else
if
(
folder
=
this
.
env
.
init_collection
)
{
this
.
env
.
init_collection
=
null
;
rcmail
.
folder_list
.
select
(
'folder-collection-'
+
folder
);
}
else
if
(
first
)
rcmail
.
folder_list
.
select
(
first
);
// handle authentication errors on external sources
this
.
folder_list_auth_errors
(
response
.
result
);
// Fetch 2 levels of folder hierarchy for all mount points that
// do not support fast folders list
if
(
rcmail
.
env
.
files_api_version
>
4
)
{
var
ref
=
this
;
$
.
each
(
this
.
env
.
caps
.
MOUNTPOINTS
||
[],
function
(
k
,
v
)
{
if
(
!
v
.
FAST_FOLDER_LIST
)
ref
.
folder_list
({
level
:
2
,
folder
:
k
},
true
);
});
}
// Elastic: Set notree class on the folder list
var
callback
=
function
()
{
list
[
list
.
find
(
'.treetoggle'
).
length
>
0
?
'removeClass'
:
'addClass'
](
'notree'
);
};
if
(
window
.
MutationObserver
)
(
new
MutationObserver
(
callback
)).
observe
(
list
.
get
(
0
),
{
childList
:
true
,
subtree
:
true
});
callback
();
};
// folder list response handler
this
.
folder_list_update_response
=
function
(
response
,
params
)
{
rcmail
.
hide_message
(
params
.
req
);
this
.
list_updates
--
;
if
(
!
this
.
response
(
response
))
return
;
// handle authentication errors on external sources
this
.
folder_list_auth_errors
(
response
.
result
);
// Update the list
this
.
folder_list_merge
(
params
.
folder
,
response
.
result
.
list
,
params
.
level
);
};
this
.
folder_list_update_wait
=
function
(
folder
)
{
var
ref
=
this
;
// do maximum 10 parallel requests
if
(
this
.
list_updates
>
10
)
return
setTimeout
(
function
()
{
ref
.
folder_list_update_wait
(
folder
);
},
20
);
this
.
folder_list
({
folder
:
folder
,
level
:
0
},
true
);
};
this
.
folder_select
=
function
(
folder
)
{
if
(
rcmail
.
busy
||
!
folder
)
return
;
rcmail
.
triggerEvent
(
'files-folder-select'
,
{
folder
:
folder
});
var
is_collection
=
folder
.
match
(
/^folder-collection-(.*)$/
),
collection
=
RegExp
.
$1
||
null
;
if
(
rcmail
.
task
==
'files'
&&
!
rcmail
.
env
.
action
)
rcmail
.
update_state
(
is_collection
?
{
collection
:
collection
}
:
{
folder
:
folder
});
if
(
collection
==
'sessions'
)
{
rcmail
.
enable_command
(
'files-list'
,
'files-folder-delete'
,
'folder-rename'
,
'files-upload'
,
'files-open'
,
'files-edit'
,
false
);
this
.
sessions_list
();
return
;
}
if
(
is_collection
)
folder
=
null
;
// search-reset can re-select the same folder, skip
if
(
this
.
env
.
folder
==
folder
&&
this
.
env
.
collection
==
collection
)
return
;
this
.
env
.
folder
=
folder
;
this
.
env
.
collection
=
collection
;
rcmail
.
enable_command
(
'files-list'
,
true
);
rcmail
.
enable_command
(
'files-folder-delete'
,
'folder-rename'
,
!
is_collection
);
rcmail
.
enable_command
(
'files-upload'
,
!
is_collection
&&
this
.
is_writable
());
rcmail
.
enable_command
(
'folder-share'
,
!
is_collection
&&
this
.
is_shareable
());
rcmail
.
command
(
'files-list'
,
is_collection
?
{
collection
:
collection
}
:
{
folder
:
folder
});
this
.
quota
();
};
this
.
folder_unselect
=
function
()
{
rcmail
.
folder_list
.
select
();
this
.
env
.
folder
=
null
;
this
.
env
.
collection
=
null
;
rcmail
.
enable_command
(
'files-folder-delete'
,
'files-upload'
,
false
);
};
this
.
folder_collapsed
=
function
(
node
)
{
var
prefname
=
'kolab_files_collapsed_folders'
,
old
=
rcmail
.
env
[
prefname
],
entry
=
'&'
+
urlencode
(
node
.
id
)
+
'&'
;
if
(
node
.
collapsed
)
{
rcmail
.
env
[
prefname
]
=
rcmail
.
env
[
prefname
]
+
entry
;
// select the folder if one of its childs is currently selected
// don't select if it's virtual (#1488346)
if
(
!
node
.
virtual
&&
this
.
env
.
folder
&&
this
.
env
.
folder
.
startsWith
(
node
.
id
+
'/'
))
{
rcmail
.
folder_list
.
select
(
node
.
id
);
}
}
else
{
rcmail
.
env
[
prefname
]
=
rcmail
.
env
[
prefname
].
replace
(
entry
,
''
);
}
if
(
old
!==
rcmail
.
env
[
prefname
]
&&
(
!
rcmail
.
fileslist
||
!
rcmail
.
fileslist
.
drag_active
))
rcmail
.
command
(
'save-pref'
,
{
name
:
prefname
,
value
:
rcmail
.
env
[
prefname
]});
};
this
.
folder_list_row
=
function
(
i
,
folder
,
parent
)
{
var
toggle
,
sublist
,
collapsed
,
parent
,
parent_name
,
classes
=
[
'mailbox'
],
row
=
$
(
'<li>'
),
id
=
'rcmli'
+
rcmail
.
html_identifier_encode
(
i
),
content
=
$
(
'<div>'
).
append
(
$
(
'<a class="name">'
).
text
(
folder
.
name
));
if
(
folder
.
virtual
)
classes
.
push
(
'virtual'
);
else
{
if
(
folder
.
subscribed
!==
undefined
)
content
.
append
(
this
.
folder_list_subscription_button
(
folder
.
subscribed
));
if
(
folder
.
readonly
)
classes
.
push
(
'readonly'
);
}
folder
.
ref
=
row
.
attr
({
id
:
id
,
'class'
:
classes
.
join
(
' '
)}).
append
(
content
);
if
(
folder
.
depth
)
{
// find parent folder
parent_name
=
i
.
replace
(
/\/[^/]+$/
,
''
);
if
(
!
parent
)
parent
=
$
(
this
.
env
.
folders
[
parent_name
].
ref
);
toggle
=
$
(
'div.treetoggle'
,
parent
);
sublist
=
$
(
'> ul'
,
parent
);
if
(
!
toggle
.
length
)
{
collapsed
=
rcmail
.
env
.
kolab_files_collapsed_folders
.
indexOf
(
'&'
+
urlencode
(
parent_name
)
+
'&'
)
>
-
1
;
toggle
=
$
(
'<div>'
).
attr
(
'class'
,
'treetoggle'
+
(
collapsed
?
' collapsed'
:
' expanded'
))
.
html
(
' '
).
appendTo
(
parent
);
sublist
=
$
(
'<ul>'
).
attr
({
role
:
'group'
}).
appendTo
(
parent
);
if
(
collapsed
)
sublist
.
hide
();
}
sublist
.
append
(
row
);
}
else
{
return
row
;
}
};
// create subscription button element
this
.
folder_list_subscription_button
=
function
(
subscribed
)
{
return
$
(
'<a>'
).
attr
({
title
:
rcmail
.
gettext
(
'kolab_files.listpermanent'
),
'class'
:
'subscription'
+
(
subscribed
?
' subscribed'
:
''
),
'aria-checked'
:
subscribed
,
role
:
'checkbox'
});
};
// subscription button handler
this
.
folder_list_subscription_button_click
=
function
(
elem
)
{
var
folder
=
$
(
elem
).
parents
(
'li:first'
).
prop
(
'id'
).
replace
(
/^rcmli/
,
''
),
selected
=
$
(
elem
).
hasClass
(
'subscribed'
);
folder
=
folder
.
replace
(
/--xsR$/
,
''
);
// this might be a search result
folder
=
rcmail
.
html_identifier_decode
(
folder
);
file_api
[
'folder_'
+
(
selected
?
'unsubscribe'
:
'subscribe'
)](
folder
);
return
false
;
};
// sets subscription button status
this
.
folder_list_subscription_state
=
function
(
elem
,
status
)
{
$
(
elem
).
find
(
'a.subscription:first'
)
.
prop
(
'aria-checked'
,
status
)[
status
?
'addClass'
:
'removeClass'
](
'subscribed'
);
};
// Folder searching handler (for unsubscribed folders)
this
.
folder_search
=
function
(
search
)
{
// hide search results
if
(
this
.
search_results_widget
)
{
this
.
search_results_container
.
hide
();
this
.
search_results_widget
.
reset
();
}
this
.
search_results
=
{};
// send search request to the server
if
(
search
.
query
&&
search
.
execute
)
{
// cancel previous search request
if
(
this
.
listsearch_request
)
{
this
.
listsearch_request
.
abort
();
this
.
listsearch_request
=
null
;
}
var
params
=
$
.
extend
({
search
:
search
.
query
,
unsubscribed
:
1
},
this
.
list_params
);
this
.
req
=
this
.
set_busy
(
true
,
rcmail
.
gettext
(
'searching'
));
this
.
listsearch_request
=
this
.
request
(
'folder_list'
,
params
,
'folder_search_response'
);
}
else
if
(
!
search
.
query
)
{
if
(
this
.
listsearch_request
)
{
this
.
listsearch_request
.
abort
();
this
.
listsearch_request
=
null
;
}
// any subscription changed, make sure the newly added records
// are listed before collections not after
if
(
this
.
folder_subscribe
)
{
var
r
,
last
,
move
=
[],
rows
=
$
(
rcmail
.
folder_list
.
container
).
children
(
'li'
);
if
(
rows
.
length
&&
!
$
(
rows
[
rows
.
length
-
1
]).
hasClass
(
'collection'
))
{
// collect all folders to move
while
(
rows
.
length
--
)
{
r
=
$
(
rows
[
rows
.
length
]);
if
(
r
.
hasClass
(
'collection'
))
last
=
r
;
else
if
(
last
)
break
;
else
move
.
push
(
r
);
}
if
(
last
)
$
.
each
(
move
,
function
()
{
this
.
remove
();
last
.
before
(
this
);
});
}
}
}
};
// folder search response handler
this
.
folder_search_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
var
folders
=
response
.
result
&&
response
.
result
.
list
?
response
.
result
.
list
:
response
.
result
;
if
(
!
folders
.
length
)
return
;
folders
=
this
.
folder_list_parse
(
folders
,
10000
,
false
);
if
(
!
this
.
search_results_widget
)
{
var
list
=
rcmail
.
folder_list
.
container
,
title
=
rcmail
.
gettext
(
'kolab_files.additionalfolders'
),
list_id
=
list
.
attr
(
'id'
)
||
'0'
;
this
.
search_results_container
=
$
(
'<div class="searchresults"></div>'
)
.
append
(
$
(
'<h2 class="boxtitle" id="st:'
+
list_id
+
'"></h2>'
).
text
(
title
))
.
insertAfter
(
list
);
this
.
search_results_widget
=
new
rcube_treelist_widget
(
'<ul>'
,
{
id_prefix
:
'rcmli'
,
id_encode
:
rcmail
.
html_identifier_encode
,
id_decode
:
rcmail
.
html_identifier_decode
,
selectable
:
true
});
this
.
search_results_widget
.
addEventListener
(
'beforeselect'
,
function
(
node
)
{
return
!
rcmail
.
busy
;
})
.
addEventListener
(
'select'
,
function
(
node
)
{
rcmail
.
folder_list
.
select
();
file_api
.
folder_select
(
node
.
id
);
});
this
.
search_results_widget
.
container
// copy classes from main list
.
addClass
(
list
.
attr
(
'class'
)).
attr
(
'aria-labelledby'
,
'st:'
+
list_id
)
.
appendTo
(
this
.
search_results_container
)
.
on
(
'click'
,
'a.subscription'
,
function
(
e
)
{
return
file_api
.
folder_list_subscription_button_click
(
this
);
});
}
// add results to the list
$
.
each
(
folders
,
function
(
i
,
folder
)
{
var
node
,
separator
=
file_api
.
env
.
directory_separator
,
path
=
i
.
split
(
separator
),
classes
=
[
'mailbox'
],
html
=
[
$
(
'<a>'
).
text
(
folder
.
name
)];
if
(
!
folder
.
virtual
)
{
// add subscription button
html
.
push
(
file_api
.
folder_list_subscription_button
(
false
));
if
(
folder
.
readonly
)
classes
.
push
(
'readonly'
);
}
path
.
pop
();
file_api
.
search_results_widget
.
insert
({
id
:
i
,
classes
:
classes
,
text
:
folder
.
name
,
html
:
$
(
'<div>'
).
append
(
html
),
collapsed
:
false
,
virtual
:
folder
.
virtual
},
path
.
length
?
path
.
join
(
separator
)
:
null
);
});
this
.
search_results
=
folders
;
this
.
search_results_container
.
show
();
};
// folder subscribe request
this
.
folder_subscribe
=
function
(
folder
)
{
this
.
env
.
folder_subscribe
=
folder
;
this
.
req
=
this
.
set_busy
(
true
,
'foldersubscribing'
);
this
.
request
(
'folder_subscribe'
,
{
folder
:
folder
},
'folder_subscribe_response'
);
}
// folder subscribe response handler
this
.
folder_subscribe_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'foldersubscribed'
,
'confirmation'
);
var
item
,
node
=
rcmail
.
folder_list
.
get_item
(
this
.
env
.
folder_subscribe
);
if
(
this
.
search_results
&&
this
.
search_results
[
this
.
env
.
folder_subscribe
])
{
item
=
this
.
search_results_widget
.
get_item
(
this
.
env
.
folder_subscribe
);
this
.
folder_list_subscription_state
(
item
,
true
);
if
(
item
=
$
(
item
).
attr
(
'id'
))
this
.
folder_list_subscription_state
(
$
(
'#'
+
item
.
replace
(
/--xsR$/
,
''
)),
true
);
}
// search result, move from search to main list widget
if
(
!
node
&&
this
.
search_results
&&
this
.
search_results
[
this
.
env
.
folder_subscribe
])
{
var
i
,
html
,
dir
,
folder
,
separator
=
this
.
env
.
directory_separator
,
path
=
this
.
env
.
folder_subscribe
.
split
(
separator
);
// add all folders in a path to the main list if needed
// including the subscribed folder
for
(
i
=
0
;
i
<
path
.
length
;
i
++
)
{
dir
=
path
.
slice
(
0
,
i
+
1
).
join
(
separator
);
node
=
rcmail
.
folder_list
.
get_node
(
dir
);
if
(
!
node
)
{
node
=
this
.
search_results_widget
.
get_node
(
dir
);
if
(
!
node
)
{
// sanity check
return
;
}
if
(
i
==
path
.
length
-
1
)
{
item
=
this
.
search_results_widget
.
get_item
(
dir
);
this
.
folder_list_subscription_state
(
item
,
true
);
}
folder
=
this
.
search_results
[
dir
];
html
=
[
$
(
'<a>'
).
text
(
folder
.
name
)];
if
(
!
folder
.
virtual
)
html
.
push
(
this
.
folder_list_subscription_button
(
true
));
node
.
html
=
$
(
'<div>'
).
append
(
html
);
delete
node
.
children
;
rcmail
.
folder_list
.
insert
(
node
,
i
>
0
?
path
.
slice
(
0
,
i
).
join
(
separator
)
:
null
);
// we're in search result, so there will be two records,
// add subscription button to the visible one, it was not cloned
if
(
!
folder
.
virtual
)
{
node
=
rcmail
.
folder_list
.
get_item
(
dir
);
$
(
node
).
append
(
file_api
.
folder_list_subscription_button
(
true
));
}
this
.
env
.
folders
[
dir
]
=
folder
;
}
}
// now remove them from the search widget
while
(
path
.
length
)
{
dir
=
path
.
join
(
separator
);
node
=
this
.
search_results_widget
.
get_item
(
dir
);
if
(
$
(
'ul[role="group"] > li'
,
node
).
length
)
break
;
this
.
search_results_widget
.
remove
(
dir
);
path
.
pop
();
}
node
=
null
;
}
if
(
node
)
this
.
folder_list_subscription_state
(
node
,
true
);
this
.
env
.
folders
[
this
.
env
.
folder_subscribe
].
subscribed
=
true
;
};
// folder unsubscribe request
this
.
folder_unsubscribe
=
function
(
folder
)
{
this
.
env
.
folder_subscribe
=
folder
;
this
.
req
=
this
.
set_busy
(
true
,
'folderunsubscribing'
);
this
.
request
(
'folder_unsubscribe'
,
{
folder
:
folder
},
'folder_unsubscribe_response'
);
}
// folder unsubscribe response handler
this
.
folder_unsubscribe_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'folderunsubscribed'
,
'confirmation'
);
var
folder
=
this
.
env
.
folders
[
this
.
env
.
folder_subscribe
],
node
=
rcmail
.
folder_list
.
get_item
(
this
.
env
.
folder_subscribe
);
if
(
this
.
search_results
&&
this
.
search_results
[
this
.
env
.
folder_subscribe
])
{
item
=
this
.
search_results_widget
.
get_item
(
this
.
env
.
folder_subscribe
);
if
(
item
)
{
this
.
folder_list_subscription_state
(
item
,
false
);
item
=
$
(
'#'
+
$
(
item
).
attr
(
'id'
).
replace
(
/--xsR$/
,
''
));
}
else
item
=
$
(
'#rcmli'
+
rcmail
.
html_identifier_encode
(
this
.
env
.
folder_subscribe
),
rcmail
.
folder_list
.
container
);
this
.
folder_list_subscription_state
(
item
,
false
);
}
this
.
folder_list_subscription_state
(
node
,
false
);
folder
.
subscribed
=
false
;
};
// folder create request
this
.
folder_create
=
function
(
folder
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.foldercreating'
);
this
.
request
(
'folder_create'
,
{
folder
:
folder
},
'folder_create_response'
);
};
// folder create response handler
this
.
folder_create_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'kolab_files.foldercreatenotice'
,
'confirmation'
);
// refresh folders list
// TODO: Don't reload the whole list
this
.
folder_list
();
};
// folder rename request
this
.
folder_rename
=
function
(
folder
,
new_name
)
{
if
(
folder
==
new_name
)
return
;
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.folderupdating'
);
this
.
request
(
'folder_move'
,
{
folder
:
folder
,
'new'
:
new_name
},
'folder_rename_response'
);
};
// folder create response handler
this
.
folder_rename_response
=
function
(
response
,
params
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'kolab_files.folderupdatenotice'
,
'confirmation'
);
// refresh folders and files list
if
(
this
.
env
.
folder
==
params
.
folder
)
this
.
env
.
folder
=
params
[
'new'
];
// Removed mount point, refresh capabilities stored in session
if
(
this
.
env
.
caps
.
MOUNTPOINTS
[
params
.
folder
])
{
this
.
env
.
caps
.
MOUNTPOINTS
[
params
[
'new'
]]
=
this
.
env
.
caps
.
MOUNTPOINTS
[
params
.
folder
];
delete
this
.
env
.
caps
.
MOUNTPOINTS
[
params
.
folder
];
rcmail
.
http_post
(
'files/reset'
,
{});
}
// TODO: Don't reload the whole list
this
.
folder_list
();
};
// folder mount (external storage) request
this
.
folder_mount
=
function
(
data
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.foldermounting'
);
this
.
request
(
'folder_create'
,
data
,
'folder_mount_response'
);
};
// folder create response handler
this
.
folder_mount_response
=
function
(
response
,
params
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'kolab_files.foldermountnotice'
,
'confirmation'
);
if
(
response
.
result
.
capabilities
)
{
// we make sure the result is an object not array
// when the list is empty it is an array, because of how works JSON encoding from PHP
var
add
=
{};
add
[
params
.
folder
]
=
response
.
result
.
capabilities
;
this
.
env
.
caps
.
MOUNTPOINTS
=
$
.
extend
({},
this
.
env
.
caps
.
MOUNTPOINTS
,
add
);
}
// Refresh capabilities stored in session
rcmail
.
http_post
(
'files/reset'
,
{});
// refresh folders list
// TODO: load only folders from the created mount point
this
.
folder_list
();
};
// folder delete request
this
.
folder_delete
=
function
(
folder
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.folderdeleting'
);
this
.
request
(
'folder_delete'
,
{
folder
:
folder
},
'folder_delete_response'
);
};
// folder delete response handler
this
.
folder_delete_response
=
function
(
response
,
params
)
{
if
(
!
this
.
response
(
response
))
return
;
this
.
display_message
(
'kolab_files.folderdeletenotice'
,
'confirmation'
);
if
(
this
.
env
.
folder
==
params
.
folder
)
{
this
.
env
.
folder
=
null
;
rcmail
.
enable_command
(
'files-folder-delete'
,
'folder-rename'
,
'files-list'
,
false
);
}
// Removed mount point, refresh capabilities stored in session
if
(
this
.
env
.
caps
.
MOUNTPOINTS
[
params
.
folder
])
{
delete
this
.
env
.
caps
.
MOUNTPOINTS
[
params
.
folder
];
rcmail
.
http_post
(
'files/reset'
,
{});
}
// refresh folders list
this
.
folder_list
();
this
.
quota
();
};
this
.
sharing_submit
=
function
(
folder
,
row
,
mode
)
{
var
post
=
this
.
sharing_data
(
row
,
{
action
:
'submit'
,
folder
:
folder
,
mode
:
mode
});
if
(
post
===
false
)
return
;
this
.
sharing_submit_post
=
post
;
this
.
sharing_submit_row
=
row
;
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.updatingfolder'
+
mode
);
this
.
post
(
'sharing'
,
post
,
'sharing_submit_response'
);
};
this
.
sharing_submit_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
// reset inputs
$
(
this
.
sharing_submit_row
).
find
(
'input[type=text]'
).
val
(
''
);
var
hidden
=
[],
post
=
$
.
extend
({},
this
.
sharing_submit_post
,
response
.
result
||
{}),
form_info
=
rcmail
.
env
.
form_info
[
post
.
mode
],
table
=
$
(
this
.
sharing_submit_row
).
closest
(
'table'
),
row
=
$
(
'<tr>'
),
btn
=
$
(
'<button type="button" class="btn btn-secondary btn-danger delete">'
)
.
text
(
rcmail
.
gettext
(
'delete'
))
.
on
(
'click'
,
function
()
{
file_api
.
sharing_delete
(
post
.
folder
,
$
(
this
).
closest
(
'tr'
),
post
.
mode
);
});
if
(
form_info
.
list_column
)
{
row
.
append
(
$
(
'<td>'
).
append
(
$
(
'<span class="name">'
)
.
text
(
response
.
result
.
display
||
post
[
form_info
.
list_column
])
.
attr
(
'title'
,
response
.
result
.
title
))
);
}
else
{
$
.
each
(
form_info
.
form
||
[],
function
(
i
,
v
)
{
var
content
,
opts
=
[];
if
(
v
.
type
==
'select'
)
{
content
=
$
(
'<select>'
).
attr
(
'name'
,
i
)
.
on
(
'change'
,
function
()
{
file_api
.
sharing_update
(
post
.
folder
,
$
(
this
).
closest
(
'tr'
),
post
.
mode
);
});
$
.
each
(
v
.
options
,
function
(
i
,
v
)
{
opts
.
push
(
$
(
'<option>'
).
attr
(
'value'
,
i
).
text
(
v
));
});
content
.
append
(
opts
).
val
(
post
[
i
]);
}
else
{
content
=
$
(
'<span class="name">'
).
text
(
response
.
result
.
display
||
post
[
i
]).
attr
(
'title'
,
response
.
result
.
title
);
hidden
.
push
(
$
(
'<input>'
).
attr
({
type
:
'hidden'
,
name
:
i
,
value
:
post
[
i
]
||
''
}));
}
row
.
append
(
$
(
'<td>'
).
append
(
content
));
});
}
$
.
each
(
form_info
.
extra_fields
||
[],
function
(
i
,
v
)
{
hidden
.
push
(
$
(
'<input>'
).
attr
({
type
:
'hidden'
,
name
:
i
,
value
:
post
[
i
]
||
''
}));
});
row
.
append
(
$
(
'<td>'
).
append
(
btn
).
append
(
hidden
));
$
(
this
.
sharing_submit_row
).
parent
().
append
(
row
);
if
(
window
.
UI
&&
UI
.
pretty_select
)
row
.
find
(
'select'
).
each
(
function
()
{
UI
.
pretty_select
(
this
);
});
// for Elastic
if
(
table
.
data
(
'single'
))
{
$
(
'tbody > tr:first'
,
table
).
find
(
'button,input,select'
).
prop
(
'disabled'
,
true
);
}
$
(
'tbody > tr:first'
,
table
).
find
(
'input[type=text],input[type=password]'
).
val
(
''
);
};
this
.
sharing_update
=
function
(
folder
,
row
,
mode
)
{
var
post
=
this
.
sharing_data
(
row
,
{
action
:
'update'
,
folder
:
folder
,
mode
:
mode
});
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.updatingfolder'
+
mode
);
this
.
post
(
'sharing'
,
post
,
'sharing_update_response'
);
};
this
.
sharing_update_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
// todo: on error reset fields?
};
this
.
sharing_delete
=
function
(
folder
,
row
,
mode
)
{
var
post
=
this
.
sharing_data
(
row
,
{
action
:
'delete'
,
folder
:
folder
,
mode
:
mode
});
this
.
sharing_delete_row
=
row
;
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.updatingfolder'
+
mode
);
this
.
post
(
'sharing'
,
post
,
'sharing_delete_response'
);
};
this
.
sharing_delete_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
var
table
=
$
(
this
.
sharing_delete_row
).
closest
(
'table'
);
if
(
table
.
data
(
'single'
))
{
$
(
'tbody > tr:first'
,
table
).
find
(
'button,input,select'
).
prop
(
'disabled'
,
false
);
}
$
(
this
.
sharing_delete_row
).
remove
();
};
this
.
sharing_data
=
function
(
row
,
data
)
{
var
error
;
$
(
'select,input'
,
row
).
each
(
function
()
{
if
(
this
.
type
==
'password'
&&
!
this
.
name
.
match
(
/confirm$/
)
&&
this
.
value
!=
$
(
'input[name='
+
this
.
name
+
'confirm]'
,
row
).
val
())
error
=
rcmail
.
display_message
(
'kolab_files.passwordconflict'
,
'error'
);
data
[
this
.
name
]
=
$
(
this
).
val
();
});
return
error
?
false
:
data
;
};
// quota request
this
.
quota
=
function
()
{
if
(
rcmail
.
env
.
files_quota
&&
(
this
.
env
.
folder
||
!
this
.
env
.
caps
.
NOROOT
))
this
.
request
(
'quota'
,
{
folder
:
this
.
env
.
folder
},
'quota_response'
);
};
// quota response handler
this
.
quota_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
rcmail
.
files_set_quota
(
response
.
result
);
};
// List of sessions
this
.
sessions_list
=
function
(
params
)
{
if
(
!
rcmail
.
gui_objects
.
sessionslist
)
return
;
this
.
file_list_abort
(
true
);
if
(
!
params
)
params
=
{};
if
(
rcmail
.
gui_objects
.
fileslist
)
{
$
(
rcmail
.
gui_objects
.
fileslist
).
parent
().
hide
();
$
(
rcmail
.
gui_objects
.
sessionslist
).
parent
().
show
();
rcmail
.
fileslist
.
clear
();
}
this
.
env
.
folder
=
null
;
this
.
env
.
collection
=
null
;
// empty the list
this
.
env
.
sessions_list
=
{};
rcmail
.
sessionslist
.
clear
(
true
);
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands
,
false
);
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands_all
,
false
);
params
.
req_id
=
this
.
set_busy
(
true
,
'loading'
);
this
.
requests
[
params
.
req_id
]
=
this
.
request
(
'sessions'
,
params
,
'sessions_list_response'
);
};
// file list response handler
this
.
sessions_list_response
=
function
(
response
)
{
if
(
response
.
req_id
)
rcmail
.
hide_message
(
response
.
req_id
);
if
(
!
this
.
response
(
response
))
return
;
$
.
each
(
response
.
result
,
function
(
sess_id
,
data
)
{
var
row
=
file_api
.
session_list_row
(
sess_id
,
data
);
rcmail
.
sessionslist
.
insert_row
(
row
);
response
.
result
[
sess_id
].
row
=
row
;
});
this
.
env
.
sessions_list
=
response
.
result
;
rcmail
.
sessionslist
.
resize
();
};
// Files list
this
.
file_list
=
function
(
params
)
{
if
(
!
rcmail
.
gui_objects
.
fileslist
)
return
;
this
.
file_list_abort
(
true
);
if
(
!
params
)
params
=
{};
if
(
params
.
all_folders
)
{
params
.
collection
=
null
;
params
.
folder
=
null
;
this
.
folder_unselect
();
}
if
(
params
.
collection
==
undefined
)
params
.
collection
=
this
.
env
.
collection
;
if
(
params
.
folder
==
undefined
)
params
.
folder
=
this
.
env
.
folder
;
if
(
params
.
sort
==
undefined
)
params
.
sort
=
this
.
env
.
files_sort_col
;
if
(
params
.
reverse
==
undefined
)
params
.
reverse
=
this
.
env
.
files_sort_reverse
;
if
(
params
.
search
==
undefined
)
params
.
search
=
this
.
env
.
search
;
this
.
env
.
folder
=
params
.
folder
;
this
.
env
.
collection
=
params
.
collection
;
this
.
env
.
files_sort_col
=
params
.
sort
;
this
.
env
.
files_sort_reverse
=
params
.
reverse
;
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands
,
false
);
rcmail
.
enable_command
(
rcmail
.
env
.
file_commands_all
,
false
);
if
(
rcmail
.
gui_objects
.
sessionslist
)
{
$
(
rcmail
.
gui_objects
.
sessionslist
).
parent
().
hide
();
$
(
rcmail
.
gui_objects
.
fileslist
).
parent
().
show
();
rcmail
.
sessionslist
.
clear
(
true
)
}
// empty the list
this
.
env
.
file_list
=
[];
rcmail
.
fileslist
.
clear
(
true
);
rcmail
.
triggerEvent
(
'listupdate'
,
{
list
:
rcmail
.
fileslist
,
rowcount
:
0
});
// request
if
(
params
.
collection
||
params
.
all_folders
)
this
.
file_list_loop
(
params
);
else
if
(
this
.
env
.
folder
)
{
params
.
req_id
=
this
.
env
.
file_list_req_id
=
this
.
set_busy
(
true
,
'loading'
);
this
.
requests
[
params
.
req_id
]
=
this
.
request
(
'file_list'
,
params
,
'file_list_response'
);
}
};
// file list response handler
this
.
file_list_response
=
function
(
response
)
{
if
(
response
.
req_id
)
rcmail
.
hide_message
(
response
.
req_id
);
if
(
!
this
.
response
(
response
))
return
;
var
i
=
0
,
list
=
[];
$
.
each
(
response
.
result
,
function
(
key
,
data
)
{
var
row
=
file_api
.
file_list_row
(
key
,
data
,
++
i
);
rcmail
.
fileslist
.
insert_row
(
row
);
data
.
row
=
row
;
data
.
filename
=
key
;
list
.
push
(
data
);
});
this
.
env
.
file_list
=
list
;
rcmail
.
fileslist
.
resize
();
rcmail
.
triggerEvent
(
'listupdate'
,
{
list
:
rcmail
.
fileslist
,
rowcount
:
rcmail
.
fileslist
.
rowcount
});
// update document sessions info of this folder
if
(
list
&&
list
.
length
)
this
.
request
(
'folder_info'
,
{
folder
:
this
.
file_path
(
list
[
0
].
filename
),
sessions
:
1
},
'folder_info_response'
);
};
this
.
file_list_abort
=
function
(
all
)
{
if
(
all
)
{
clearTimeout
(
this
.
file_list_worker
);
this
.
file_list_worker
=
null
;
}
// reset all pending list requests
$
.
each
(
this
.
requests
,
function
(
i
,
v
)
{
v
.
abort
();
rcmail
.
hide_message
(
i
);
});
this
.
requests
=
{};
rcmail
.
set_busy
(
false
,
null
,
this
.
env
.
file_list_req_id
);
};
// call file_list request for every folder (used for search and virt. collections)
this
.
file_list_loop
=
function
(
params
)
{
var
i
,
folders
=
[],
limit
=
Math
.
max
(
this
.
env
.
search_threads
||
1
,
1
),
msg
=
rcmail
.
get_label
(
'searching'
)
+
' <a onclick="file_api.file_list_abort()">'
+
rcmail
.
get_label
(
'kolab_files.abort'
)
+
'</a>'
;
if
(
params
.
collection
)
{
if
(
!
params
.
search
)
params
.
search
=
{};
params
.
search
[
'class'
]
=
params
.
collection
;
delete
params
[
'collection'
];
}
delete
params
[
'all_folders'
];
$
.
each
(
this
.
env
.
folders
,
function
(
i
,
f
)
{
if
(
!
f
.
virtual
)
folders
.
push
(
i
);
});
this
.
env
.
folders_loop
=
folders
;
this
.
env
.
folders_loop_lock
=
false
;
this
.
env
.
file_list_req_id
=
rcmail
.
display_message
(
msg
,
'loading'
,
5
*
60
*
1000
,
'files-file-search'
);
rcmail
.
set_busy
(
true
);
for
(
i
=
0
;
i
<
folders
.
length
&&
i
<
limit
;
i
++
)
{
params
.
req_id
=
new
Date
().
getTime
();
params
.
folder
=
folders
.
shift
();
this
.
requests
[
params
.
req_id
]
=
this
.
request
(
'file_list'
,
params
,
'file_list_loop_response'
);
}
};
// file list response handler for loop'ed request
this
.
file_list_loop_response
=
function
(
response
,
params
)
{
var
folders
=
this
.
env
.
folders_loop
,
valid
=
this
.
response
(
response
);
if
(
folders
.
length
)
{
params
.
req_id
=
new
Date
().
getTime
();
params
.
folder
=
folders
.
shift
();
this
.
requests
[
params
.
req_id
]
=
this
.
request
(
'file_list'
,
params
,
'file_list_loop_response'
);
}
else
{
rcmail
.
set_busy
(
false
,
null
,
this
.
env
.
file_list_req_id
);
}
// refresh sessions info in time intervals (one request for all folders)
if
(
!
this
.
file_list_worker
&&
this
.
env
.
caps
&&
this
.
env
.
caps
.
DOCEDIT
&&
(
rcmail
.
fileslist
||
rcmail
.
env
.
file
))
this
.
file_list_worker
=
setTimeout
(
function
()
{
var
params
=
{
req_id
:
file_api
.
set_busy
(
true
,
'loading'
)};
file_api
.
request
(
'sessions'
,
params
,
'file_list_sessions_response'
);
},
0
);
rcmail
.
fileslist
.
resize
();
if
(
!
valid
)
return
;
this
.
file_list_loop_result_add
(
response
.
result
);
};
// Update sessions metadata for files list (in multifolder mode)
this
.
file_list_sessions_response
=
function
(
response
)
{
this
.
file_list_worker
=
setTimeout
(
function
()
{
var
params
=
{
req_id
:
file_api
.
set_busy
(
true
,
'loading'
)};
file_api
.
request
(
'sessions'
,
params
,
'file_list_sessions_response'
);
},
(
rcmail
.
env
.
files_interval
||
60
)
*
1000
);
if
(
response
.
req_id
)
rcmail
.
hide_message
(
response
.
req_id
);
if
(
!
this
.
response
(
response
))
return
;
this
.
sessions
=
[];
$
.
each
(
response
.
result
||
[],
function
(
sess_id
,
data
)
{
var
folder
=
file_api
.
file_path
(
data
.
file
);
if
(
!
file_api
.
sessions
[
folder
])
file_api
.
sessions
[
folder
]
=
{};
file_api
.
sessions
[
folder
][
sess_id
]
=
data
;
});
// update files list with document session info
$
.
each
(
file_api
.
env
.
file_list
||
[],
function
(
i
,
file
)
{
var
folder
=
file_api
.
file_path
(
file
.
filename
);
file_api
.
file_session_data_set
(
file
,
file_api
.
sessions
[
folder
]);
});
};
// add files from list request to the table (with sorting)
this
.
file_list_loop_result_add
=
function
(
result
)
{
// chack if result (hash-array) is empty
if
(
!
object_is_empty
(
result
))
return
;
if
(
this
.
env
.
folders_loop_lock
)
{
setTimeout
(
function
()
{
file_api
.
file_list_loop_result_add
(
result
);
},
100
);
return
;
}
// lock table, other list responses will wait
this
.
env
.
folders_loop_lock
=
true
;
var
n
,
i
,
len
,
elem
,
folder
,
list
=
[],
index
=
this
.
env
.
file_list
.
length
,
table
=
rcmail
.
fileslist
,
fn
=
function
(
result
,
key
,
before
)
{
var
row
=
file_api
.
file_list_row
(
key
,
result
[
key
],
++
index
);
table
.
insert_row
(
row
,
before
);
result
[
key
].
row
=
row
;
result
[
key
].
filename
=
key
;
list
.
push
(
result
[
key
]);
if
(
!
folder
)
folder
=
file_api
.
file_path
(
key
);
};
for
(
n
=
0
,
len
=
index
;
n
<
len
;
n
++
)
{
elem
=
this
.
env
.
file_list
[
n
];
for
(
i
in
result
)
{
if
(
this
.
sort_compare
(
elem
,
result
[
i
])
<
0
)
break
;
fn
(
result
,
i
,
elem
.
row
);
delete
result
[
i
];
}
list
.
push
(
elem
);
}
// add the rest of rows
for
(
i
in
result
)
fn
(
result
,
i
);
this
.
env
.
file_list
=
list
;
// update files list with document session info
if
(
folder
&&
this
.
sessions
[
folder
])
$
.
each
(
list
,
function
(
i
,
file
)
{
if
(
folder
==
file_api
.
file_path
(
file
.
filename
))
file_api
.
file_session_data_set
(
file
,
file_api
.
sessions
[
folder
]);
});
this
.
env
.
folders_loop_lock
=
false
;
};
// sort files list (without API request)
this
.
file_list_sort
=
function
(
col
,
reverse
)
{
var
n
,
len
,
list
=
this
.
env
.
file_list
,
table
=
$
(
'#filelist'
),
tbody
=
$
(
'<tbody>'
,
table
);
this
.
env
.
sort_col
=
col
;
this
.
env
.
sort_reverse
=
reverse
;
if
(
!
list
||
!
list
.
length
)
return
;
// sort the list
list
.
sort
(
function
(
a
,
b
)
{
return
file_api
.
sort_compare
(
a
,
b
);
});
// add rows to the new body
for
(
n
=
0
,
len
=
list
.
length
;
n
<
len
;
n
++
)
{
tbody
.
append
(
list
[
n
].
row
);
}
// replace table bodies
$
(
'tbody'
,
table
).
replaceWith
(
tbody
);
};
// Files list record
this
.
file_list_row
=
function
(
file
,
data
,
index
)
{
var
c
,
col
,
row
=
''
;
for
(
c
in
rcmail
.
env
.
files_coltypes
)
{
c
=
rcmail
.
env
.
files_coltypes
[
c
];
if
(
c
==
'name'
)
col
=
'<td class="name filename '
+
this
.
file_type_class
(
data
.
type
)
+
'">'
+
'<span>'
+
escapeHTML
(
data
.
name
)
+
'</span></td>'
;
else
if
(
c
==
'mtime'
)
col
=
'<td class="mtime">'
+
data
.
mtime
+
'</td>'
;
else
if
(
c
==
'size'
)
col
=
'<td class="size">'
+
this
.
file_size
(
data
.
size
)
+
'</td>'
;
else
if
(
c
==
'options'
)
col
=
'<td class="options"><span></span></td>'
;
else
col
=
'<td class="'
+
c
+
'"></td>'
;
row
+=
col
;
}
row
=
$
(
'<tr>'
)
.
html
(
row
)
.
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
if
(
!
this
.
env
.
folder
)
$
(
'td.name span'
,
row
).
attr
(
'title'
,
file
);
return
row
.
get
(
0
);
};
// Sessions list record
this
.
session_list_row
=
function
(
id
,
data
)
{
var
c
,
col
,
row
=
''
,
classes
=
[
'session'
];
for
(
c
in
rcmail
.
env
.
sessions_coltypes
)
{
c
=
rcmail
.
env
.
sessions_coltypes
[
c
];
if
(
c
==
'name'
)
col
=
'<td class="name filename '
+
this
.
file_type_class
(
data
.
type
)
+
'">'
+
'<span>'
+
escapeHTML
(
file_api
.
file_name
(
data
.
file
))
+
'</span></td>'
;
else
if
(
c
==
'owner'
)
col
=
'<td class="owner">'
+
escapeHTML
(
data
.
owner_name
||
data
.
owner
)
+
'</td>'
;
else
if
(
c
==
'options'
)
col
=
'<td class="options"><span></span></td>'
;
row
+=
col
;
}
if
(
data
.
is_owner
)
classes
.
push
(
'owner'
);
else
if
(
data
.
is_invited
)
classes
.
push
(
'invited'
);
row
=
$
(
'<tr>'
)
.
html
(
row
)
.
attr
({
id
:
'rcmrow'
+
id
,
'class'
:
classes
.
join
(
' '
)});
return
row
.
get
(
0
);
};
this
.
file_search
=
function
(
value
,
all_folders
)
{
if
(
value
)
{
this
.
env
.
search
=
{
name
:
value
};
rcmail
.
command
(
'files-list'
,
{
search
:
this
.
env
.
search
,
all_folders
:
all_folders
});
}
else
this
.
search_reset
();
};
this
.
file_search_reset
=
function
()
{
if
(
this
.
env
.
search
)
{
this
.
env
.
search
=
null
;
rcmail
.
command
(
'files-list'
);
}
};
// handler for folder info response
this
.
folder_info_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
)
||
!
response
.
result
)
return
;
var
folder
=
response
.
result
.
folder
,
prefix
=
folder
+
file_api
.
env
.
directory_separator
;
if
(
response
.
result
.
sessions
)
this
.
sessions
[
folder
]
=
response
.
result
.
sessions
;
// update files list with document session info
$
.
each
(
file_api
.
env
.
file_list
||
[],
function
(
i
,
file
)
{
// skip files from a different folder (in multi-folder listing)
if
(
file
.
filename
.
indexOf
(
prefix
)
>=
0
)
file_api
.
file_session_data_set
(
file
,
response
.
result
.
sessions
)
});
// refresh sessions info in time intervals
if
(
this
.
env
.
caps
&&
this
.
env
.
caps
.
DOCEDIT
&&
(
rcmail
.
fileslist
||
rcmail
.
env
.
file
))
this
.
file_list_worker
=
setTimeout
(
function
()
{
file_api
.
request
(
'folder_info'
,
{
folder
:
folder
,
sessions
:
1
},
'folder_info_response'
);
},
(
rcmail
.
env
.
files_interval
||
60
)
*
1000
);
};
// Set html classes on a file list entry according to defined document sessions
this
.
file_session_data_set
=
function
(
file
,
sessions
)
{
var
classes
=
[],
old_class
=
file
.
row
.
className
;
if
(
$
(
file
.
row
).
is
(
'.selected'
))
classes
.
push
(
'selected'
);
$
.
each
(
sessions
||
[],
function
(
session_id
,
session
)
{
if
(
file
.
filename
==
session
.
file
)
{
if
(
$
.
inArray
(
'session'
,
classes
)
<
0
)
classes
.
push
(
'session'
);
if
(
session
.
is_owner
&&
$
.
inArray
(
'owner'
,
classes
)
<
0
)
classes
.
push
(
'owner'
);
else
if
(
session
.
is_invited
&&
$
.
inArray
(
'invited'
,
classes
)
<
0
)
classes
.
push
(
'invited'
);
}
});
if
(
classes
.
length
||
old_class
.
length
)
$
(
file
.
row
).
attr
(
'class'
,
classes
.
join
(
' '
));
};
this
.
file_get
=
function
(
file
,
params
)
{
if
(
!
params
)
params
=
{};
params
.
token
=
this
.
env
.
token
;
params
.
file
=
file
;
rcmail
.
redirect
(
this
.
env
.
url
+
this
.
url
(
'file_get'
,
params
),
false
);
};
// file(s) delete request
this
.
file_delete
=
function
(
files
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.filedeleting'
);
this
.
request
(
'file_delete'
,
{
file
:
files
},
'file_delete_response'
);
};
// file(s) delete response handler
this
.
file_delete_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
var
rco
,
dir
,
self
=
this
;
this
.
display_message
(
'kolab_files.filedeletenotice'
,
'confirmation'
);
if
(
rcmail
.
env
.
file
)
{
rco
=
rcmail
.
opener
();
dir
=
this
.
file_path
(
rcmail
.
env
.
file
);
// check if opener window contains files list, if not we can just close current window
if
(
rco
&&
rco
.
fileslist
&&
(
opener
.
file_api
.
env
.
folder
==
dir
||
!
opener
.
file_api
.
env
.
folder
))
self
=
opener
.
file_api
;
// also try parent for framed UI (Elastic)
else
if
(
rcmail
.
is_framed
()
&&
parent
.
rcmail
.
fileslist
&&
(
parent
.
file_api
.
env
.
folder
==
dir
||
!
parent
.
file_api
.
env
.
folder
))
self
=
parent
.
file_api
;
}
// @TODO: consider list modification "in-place" instead of full reload
self
.
file_list
();
self
.
quota
();
if
(
rcmail
.
env
.
file
)
{
if
(
rcmail
.
is_framed
())
{
parent
.
$
(
'.ui-dialog:visible > .ui-dialog-buttonpane button.cancel'
).
click
();
}
else
window
.
close
();
}
};
// file(s) move request
this
.
file_move
=
function
(
files
,
folder
)
{
if
(
!
files
||
!
files
.
length
||
!
folder
)
return
;
var
count
=
0
,
list
=
{};
$
.
each
(
files
,
function
(
i
,
v
)
{
var
name
=
folder
+
file_api
.
env
.
directory_separator
+
file_api
.
file_name
(
v
);
if
(
name
!=
v
)
{
list
[
v
]
=
name
;
count
++
;
}
});
if
(
!
count
)
return
;
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.filemoving'
);
this
.
request
(
'file_move'
,
{
file
:
list
},
'file_move_response'
);
};
// file(s) move response handler
this
.
file_move_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
if
(
response
.
result
&&
response
.
result
.
already_exist
&&
response
.
result
.
already_exist
.
length
)
this
.
file_move_ask_user
(
response
.
result
.
already_exist
,
true
);
else
{
this
.
display_message
(
'kolab_files.filemovenotice'
,
'confirmation'
);
this
.
file_list
();
}
};
// file(s) copy request
this
.
file_copy
=
function
(
files
,
folder
)
{
if
(
!
files
||
!
files
.
length
||
!
folder
)
return
;
var
count
=
0
,
list
=
{};
$
.
each
(
files
,
function
(
i
,
v
)
{
var
name
=
folder
+
file_api
.
env
.
directory_separator
+
file_api
.
file_name
(
v
);
if
(
name
!=
v
)
{
list
[
v
]
=
name
;
count
++
;
}
});
if
(
!
count
)
return
;
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.filecopying'
);
this
.
request
(
'file_copy'
,
{
file
:
list
},
'file_copy_response'
);
};
// file(s) copy response handler
this
.
file_copy_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
if
(
response
.
result
&&
response
.
result
.
already_exist
&&
response
.
result
.
already_exist
.
length
)
this
.
file_move_ask_user
(
response
.
result
.
already_exist
);
else
{
this
.
display_message
(
'kolab_files.filecopynotice'
,
'confirmation'
);
this
.
quota
();
}
};
// when file move/copy operation returns file-exists error
// this displays a dialog where user can decide to skip
// or overwrite destination file(s)
this
.
file_move_ask_user
=
function
(
list
,
move
)
{
var
file
=
list
[
0
],
buttons
=
{},
button_classes
=
[
'mainaction save file overwrite'
],
text
=
rcmail
.
gettext
(
'kolab_files.filemoveconfirm'
).
replace
(
'$file'
,
file
.
dst
),
dialog
=
$
(
'<div></div>'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.fileoverwrite'
)]
=
function
()
{
var
file
=
list
.
shift
(),
f
=
{},
action
=
move
?
'file_move'
:
'file_copy'
;
f
[
file
.
src
]
=
file
.
dst
;
file_api
.
file_move_ask_list
=
list
;
file_api
.
file_move_ask_mode
=
move
;
kolab_dialog_close
(
this
,
true
);
file_api
.
req
=
file_api
.
set_busy
(
true
,
move
?
'kolab_files.filemoving'
:
'kolab_files.filecopying'
);
file_api
.
request
(
action
,
{
file
:
f
,
overwrite
:
1
},
'file_move_ask_user_response'
);
};
if
(
list
.
length
>
1
)
{
button_classes
.
push
(
'save file overwrite all'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.fileoverwriteall'
)]
=
function
()
{
var
f
=
{},
action
=
move
?
'file_move'
:
'file_copy'
;
$
.
each
(
list
,
function
()
{
f
[
this
.
src
]
=
this
.
dst
;
});
kolab_dialog_close
(
this
,
true
);
file_api
.
req
=
file_api
.
set_busy
(
true
,
move
?
'kolab_files.filemoving'
:
'kolab_files.filecopying'
);
file_api
.
request
(
action
,
{
file
:
f
,
overwrite
:
1
},
action
+
'_response'
);
};
}
var
skip_func
=
function
()
{
list
.
shift
();
kolab_dialog_close
(
this
,
true
);
if
(
list
.
length
)
file_api
.
file_move_ask_user
(
list
,
move
);
else
if
(
move
)
file_api
.
file_list
();
};
button_classes
.
push
(
'cancel file skip'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.fileskip'
)]
=
skip_func
;
if
(
list
.
length
>
1
)
{
button_classes
.
push
(
'cancel file skip all'
);
buttons
[
rcmail
.
gettext
(
'kolab_files.fileskipall'
)]
=
function
()
{
kolab_dialog_close
(
this
,
true
);
if
(
move
)
file_api
.
file_list
();
};
}
// open jquery UI dialog
kolab_dialog_show
(
dialog
.
html
(
text
),
{
title
:
rcmail
.
gettext
(
'confirmationtitle'
),
close
:
skip_func
,
buttons
:
buttons
,
button_classes
:
button_classes
,
height
:
50
,
minWidth
:
400
,
width
:
400
});
};
// file move (with overwrite) response handler
this
.
file_move_ask_user_response
=
function
(
response
)
{
var
move
=
this
.
file_move_ask_mode
,
list
=
this
.
file_move_ask_list
;
this
.
response
(
response
);
if
(
list
&&
list
.
length
)
this
.
file_move_ask_user
(
list
,
mode
);
else
{
this
.
display_message
(
'kolab_files.file'
+
(
move
?
'move'
:
'copy'
)
+
'notice'
,
'confirmation'
);
if
(
move
)
this
.
file_list
();
}
};
// file(s) create (or clone) request
this
.
file_create
=
function
(
file
,
type
,
edit
,
cloneof
)
{
this
.
file_create_edit_file
=
edit
?
file
:
null
;
this
.
file_create_edit_type
=
edit
?
type
:
null
;
this
.
file_create_folder
=
this
.
file_path
(
file
);
if
(
cloneof
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.filecopying'
);
this
.
request
(
'file_copy'
,
{
file
:
cloneof
,
'new'
:
file
},
'file_create_response'
);
}
else
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.filecreating'
);
this
.
request
(
'file_create'
,
{
file
:
file
,
'content-type'
:
type
,
content
:
''
},
'file_create_response'
);
}
};
// file(s) create response handler
this
.
file_create_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
// @TODO: we could update metadata instead
if
(
this
.
file_create_folder
==
this
.
env
.
folder
)
this
.
file_list
();
// open the file for editing if editable
if
(
this
.
file_create_edit_file
)
{
var
viewer
=
this
.
file_type_supported
(
this
.
file_create_edit_type
,
this
.
env
.
caps
);
this
.
file_open
(
this
.
file_create_edit_file
,
viewer
,
{
action
:
'edit'
});
}
};
// file(s) rename request
this
.
file_rename
=
function
(
oldfile
,
newfile
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.fileupdating'
);
this
.
request
(
'file_move'
,
{
file
:
oldfile
,
'new'
:
newfile
},
'file_rename_response'
);
};
// file(s) move response handler
this
.
file_rename_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
// @TODO: we could update metadata instead
this
.
file_list
();
};
// file upload request
this
.
file_upload
=
function
(
form
)
{
var
form
=
$
(
form
),
field
=
$
(
'input[type=file]'
,
form
).
get
(
0
),
files
=
field
.
files
?
field
.
files
.
length
:
field
.
value
?
1
:
0
;
if
(
!
files
||
!
this
.
file_upload_size_check
(
field
.
files
))
return
;
// submit form and read server response
this
.
file_upload_form
(
form
,
'file_upload'
,
function
(
event
)
{
var
doc
,
response
;
try
{
doc
=
this
.
contentDocument
?
this
.
contentDocument
:
this
.
contentWindow
.
document
;
response
=
doc
.
body
.
innerHTML
;
// response may be wrapped in <pre> tag
if
(
response
.
slice
(
0
,
5
).
toLowerCase
()
==
'<pre>'
&&
response
.
slice
(
-
6
).
toLowerCase
()
==
'</pre>'
)
{
response
=
doc
.
body
.
firstChild
.
firstChild
.
nodeValue
;
}
response
=
eval
(
'('
+
response
+
')'
);
}
catch
(
err
)
{
response
=
{
status
:
'ERROR'
};
}
file_api
.
file_upload_progress_stop
(
event
.
data
.
ts
);
// refresh the list on upload success
file_api
.
file_upload_response
(
response
);
});
};
// refresh the list on upload success
this
.
file_upload_response
=
function
(
response
)
{
if
(
this
.
response_parse
(
response
))
{
this
.
file_list
();
this
.
quota
();
}
};
// check upload max size
this
.
file_upload_size_check
=
function
(
files
)
{
var
i
,
size
=
0
,
maxsize
=
rcmail
.
env
.
files_max_upload
;
if
(
maxsize
&&
files
)
{
for
(
i
=
0
;
i
<
files
.
length
;
i
++
)
size
+=
files
[
i
].
size
||
files
[
i
].
fileSize
;
if
(
size
>
maxsize
)
{
rcmail
.
alert_dialog
(
rcmail
.
get_label
(
'kolab_files.uploadsizeerror'
).
replace
(
'$size'
,
kolab_files_file_size
(
maxsize
)));
return
false
;
}
}
return
true
;
};
// post the given form to a hidden iframe
this
.
file_upload_form
=
function
(
form
,
action
,
onload
)
{
var
ts
=
new
Date
().
getTime
(),
frame_name
=
'fileupload'
+
ts
;
// upload progress support
if
(
rcmail
.
env
.
files_progress_name
)
{
var
fname
=
rcmail
.
env
.
files_progress_name
,
field
=
$
(
'input[name='
+
fname
+
']'
,
form
);
if
(
!
field
.
length
)
{
field
=
$
(
'<input>'
).
attr
({
type
:
'hidden'
,
name
:
fname
});
field
.
prependTo
(
form
);
}
field
.
val
(
ts
);
this
.
file_upload_progress
(
ts
,
true
);
}
rcmail
.
display_progress
({
name
:
ts
});
// have to do it this way for IE
// otherwise the form will be posted to a new window
if
(
document
.
all
)
{
var
html
=
'<iframe id="'
+
frame_name
+
'" name="'
+
frame_name
+
'"'
+
' src="'
+
rcmail
.
assets_path
(
'program/resources/blank.gif'
)
+
'"'
+
' style="width:0;height:0;visibility:hidden;"></iframe>'
;
document
.
body
.
insertAdjacentHTML
(
'BeforeEnd'
,
html
);
}
// for standards-compliant browsers
else
$
(
'<iframe>'
)
.
attr
({
name
:
frame_name
,
id
:
frame_name
})
.
css
({
border
:
'none'
,
width
:
0
,
height
:
0
,
visibility
:
'hidden'
})
.
appendTo
(
document
.
body
);
// handle upload errors, parsing iframe content in onload
$
(
'#'
+
frame_name
).
on
(
'load'
,
{
ts
:
ts
},
onload
);
$
(
form
).
attr
({
target
:
frame_name
,
action
:
this
.
env
.
url
+
this
.
url
(
action
,
{
folder
:
this
.
env
.
folder
,
token
:
this
.
env
.
token
}),
method
:
'POST'
}).
attr
(
form
.
encoding
?
'encoding'
:
'enctype'
,
'multipart/form-data'
)
.
submit
();
};
// handler when files are dropped to a designated area.
// compose a multipart form data and submit it to the server
this
.
file_drop
=
function
(
e
)
{
var
files
=
e
.
target
.
files
||
e
.
dataTransfer
.
files
;
if
(
!
files
||
!
files
.
length
||
!
this
.
file_upload_size_check
(
files
))
return
;
// prepare multipart form data composition
var
ts
=
new
Date
().
getTime
(),
formdata
=
window
.
FormData
?
new
FormData
()
:
null
,
fieldname
=
'file[]'
,
boundary
=
'------multipartformboundary'
+
(
new
Date
).
getTime
(),
dashdash
=
'--'
,
crlf
=
'\r\n'
,
multipart
=
dashdash
+
boundary
+
crlf
;
// inline function to submit the files to the server
var
submit_data
=
function
()
{
var
multiple
=
files
.
length
>
1
;
rcmail
.
display_progress
({
name
:
ts
});
if
(
rcmail
.
env
.
files_progress_name
)
file_api
.
file_upload_progress
(
ts
,
true
);
// complete multipart content and post request
multipart
+=
dashdash
+
boundary
+
dashdash
+
crlf
;
$
.
ajax
({
type
:
'POST'
,
dataType
:
'json'
,
url
:
file_api
.
env
.
url
+
file_api
.
url
(
'file_upload'
,
{
folder
:
file_api
.
env
.
folder
}),
contentType
:
formdata
?
false
:
'multipart/form-data; boundary='
+
boundary
,
processData
:
false
,
timeout
:
0
,
// disable default timeout set in ajaxSetup()
data
:
formdata
||
multipart
,
headers
:
{
'X-Session-Token'
:
file_api
.
env
.
token
},
success
:
function
(
data
)
{
file_api
.
file_upload_progress_stop
(
ts
);
file_api
.
file_upload_response
(
data
);
},
error
:
function
(
o
,
status
,
err
)
{
file_api
.
file_upload_progress_stop
(
ts
);
rcmail
.
http_error
(
o
,
status
,
err
);
},
xhr
:
function
()
{
var
xhr
=
jQuery
.
ajaxSettings
.
xhr
();
if
(
!
formdata
&&
xhr
.
sendAsBinary
)
xhr
.
send
=
xhr
.
sendAsBinary
;
return
xhr
;
}
});
};
// upload progress supported (and handler exists)
// add progress ID to the request - need to be added before files
if
(
rcmail
.
env
.
files_progress_name
)
{
if
(
formdata
)
formdata
.
append
(
rcmail
.
env
.
files_progress_name
,
ts
);
else
multipart
+=
'Content-Disposition: form-data; name="'
+
rcmail
.
env
.
files_progress_name
+
'"'
+
crlf
+
crlf
+
ts
+
crlf
+
dashdash
+
boundary
+
crlf
;
}
// get contents of all dropped files
var
f
,
j
,
i
=
0
,
last
=
files
.
length
-
1
;
for
(
j
=
0
;
j
<=
last
&&
(
f
=
files
[
i
]);
i
++
)
{
if
(
!
f
.
name
)
f
.
name
=
f
.
fileName
;
if
(
!
f
.
size
)
f
.
size
=
f
.
fileSize
;
if
(
!
f
.
type
)
f
.
type
=
'application/octet-stream'
;
// file name contains non-ASCII characters, do UTF8-binary string conversion.
if
(
!
formdata
&&
/[^\x20-\x7E]/
.
test
(
f
.
name
))
f
.
name_bin
=
unescape
(
encodeURIComponent
(
f
.
name
));
// do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+)
if
(
formdata
)
{
formdata
.
append
(
fieldname
,
f
);
if
(
j
==
last
)
return
submit_data
();
}
// use FileReader supporetd by Firefox 3.6
else
if
(
window
.
FileReader
)
{
var
reader
=
new
FileReader
();
// closure to pass file properties to async callback function
reader
.
onload
=
(
function
(
file
,
j
)
{
return
function
(
e
)
{
multipart
+=
'Content-Disposition: form-data; name="'
+
fieldname
+
'"'
;
multipart
+=
'; filename="'
+
(
f
.
name_bin
||
file
.
name
)
+
'"'
+
crlf
;
multipart
+=
'Content-Length: '
+
file
.
size
+
crlf
;
multipart
+=
'Content-Type: '
+
file
.
type
+
crlf
+
crlf
;
multipart
+=
reader
.
result
+
crlf
;
multipart
+=
dashdash
+
boundary
+
crlf
;
if
(
j
==
last
)
// we're done, submit the data
return
submit_data
();
}
})(
f
,
j
);
reader
.
readAsBinaryString
(
f
);
}
j
++
;
}
};
// upload progress requests
this
.
file_upload_progress
=
function
(
id
,
init
)
{
if
(
init
&&
id
)
this
.
uploads
[
id
]
=
this
.
env
.
folder
;
setTimeout
(
function
()
{
if
(
id
&&
file_api
.
uploads
[
id
])
file_api
.
request
(
'upload_progress'
,
{
id
:
id
},
'file_upload_progress_response'
);
},
rcmail
.
env
.
files_progress_time
*
1000
);
};
// upload progress response
this
.
file_upload_progress_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
))
return
;
var
param
=
response
.
result
;
if
(
!
param
.
id
||
!
this
.
uploads
[
param
.
id
])
return
;
if
(
param
.
total
)
{
param
.
name
=
param
.
id
;
if
(
!
param
.
done
)
param
.
text
=
kolab_files_progress_str
(
param
);
rcmail
.
display_progress
(
param
);
}
if
(
!
param
.
done
&&
param
.
total
)
this
.
file_upload_progress
(
param
.
id
);
else
delete
this
.
uploads
[
param
.
id
];
};
this
.
file_upload_progress_stop
=
function
(
id
)
{
if
(
id
)
{
delete
this
.
uploads
[
id
];
rcmail
.
display_progress
({
name
:
id
});
}
};
// open file in new window, using file API viewer
this
.
file_open
=
function
(
file
,
viewer
,
params
)
{
var
args
=
{
_task
:
'files'
,
_action
:
params
&&
params
.
action
?
params
.
action
:
'open'
,
_file
:
file
,
_viewer
:
viewer
||
0
,
_frame
:
1
};
if
(
rcmail
.
is_framed
())
args
.
_framed
=
1
;
if
(
params
&&
params
.
session
)
args
.
_session
=
params
.
session
;
if
(
rcmail
.
env
.
extwin
)
args
.
_extwin
=
1
;
href
=
'?'
+
$
.
param
(
args
);
if
(
params
&&
params
.
local
)
location
.
href
=
href
;
else
rcmail
.
open_window
(
href
,
false
,
true
);
};
// save file
this
.
file_save
=
function
(
file
,
content
)
{
rcmail
.
enable_command
(
'files-save'
,
false
);
// because we currently can edit only text files
// and we do not expect them to be very big, we save
// file in a very simple way, no upload progress, etc.
this
.
req
=
this
.
set_busy
(
true
,
'saving'
);
this
.
request
(
'file_update'
,
{
file
:
file
,
content
:
content
,
info
:
1
},
'file_save_response'
);
};
// file save response handler
this
.
file_save_response
=
function
(
response
)
{
rcmail
.
enable_command
(
'files-save'
,
true
);
if
(
!
this
.
response
(
response
))
return
;
// update file properties table
var
table
=
$
(
'#fileinfobox table'
),
file
=
response
.
result
;
if
(
file
)
{
$
(
'td.filetype'
,
table
).
text
(
file
.
type
);
$
(
'td.filesize'
,
table
).
text
(
this
.
file_size
(
file
.
size
));
$
(
'td.filemtime'
,
table
).
text
(
file
.
mtime
);
}
};
// document session delete request
this
.
document_delete
=
function
(
id
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.sessionterminating'
);
this
.
request
(
'document_delete'
,
{
id
:
id
},
'document_delete_response'
);
};
// document session delete response handler
this
.
document_delete_response
=
function
(
response
,
params
)
{
if
(
!
this
.
response
(
response
))
return
;
var
list
=
rcmail
.
sessionslist
;
// remove session from the list (if sessions list exist)
if
(
list
)
list
.
remove_row
(
params
.
id
);
if
(
this
.
env
.
sessions_list
)
delete
this
.
env
.
sessions_list
[
params
.
id
];
// @todo: force sessions info update, update files list
};
// Invite document session participants
this
.
document_invite
=
function
(
id
,
attendees
,
comment
)
{
var
list
=
[];
// expect attendees to be email => name hash
$
.
each
(
attendees
||
{},
function
()
{
list
.
push
(
this
);
});
if
(
list
.
length
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.documentinviting'
);
this
.
request
(
'document_invite'
,
{
id
:
id
,
users
:
list
,
comment
:
comment
||
''
},
'document_invite_response'
);
}
};
// document invite response handler
this
.
document_invite_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
)
||
!
response
.
result
)
return
;
var
info
=
rcmail
.
env
.
file_data
,
table
=
$
(
'#document-editors-dialog table > tbody'
);
$
.
each
(
response
.
result
.
list
||
{},
function
()
{
var
record
=
kolab_files_attendee_record
(
this
.
user
,
this
.
status
,
this
.
user_name
);
table
.
append
(
record
);
if
(
info
.
session
&&
info
.
session
.
invitations
)
info
.
session
.
invitations
.
push
(
$
.
extend
({
status
:
'invited'
,
record
:
record
},
this
));
});
};
// Cancel invitations to an editing session
this
.
document_cancel
=
function
(
id
,
attendees
)
{
if
(
attendees
.
length
)
{
this
.
req
=
this
.
set_busy
(
true
,
'kolab_files.documentcancelling'
);
this
.
request
(
'document_cancel'
,
{
id
:
id
,
users
:
attendees
},
'document_cancel_response'
);
}
};
// document_cancel response handler
this
.
document_cancel_response
=
function
(
response
)
{
if
(
!
this
.
response
(
response
)
||
!
response
.
result
)
return
;
var
info
=
rcmail
.
env
.
file_data
;
$
.
each
(
response
.
result
.
list
||
{},
function
(
i
,
user
)
{
var
invitations
=
[];
$
.
each
(
info
.
session
.
invitations
,
function
(
i
,
u
)
{
if
(
u
.
user
==
user
&&
u
.
record
)
u
.
record
.
remove
();
else
invitations
.
push
(
u
);
});
info
.
session
.
invitations
=
invitations
;
});
};
// handle auth errors on folder list
this
.
folder_list_auth_errors
=
function
(
result
)
{
if
(
result
&&
result
.
auth_errors
)
{
if
(
!
this
.
auth_errors
)
this
.
auth_errors
=
{};
$
.
each
(
result
.
auth_errors
||
{},
function
(
i
,
v
)
{
// for normal errors we display only an error message, other will display a dialog
if
(
v
.
error
)
{
if
(
v
.
error
==
580
)
{
rcmail
.
display_message
(
rcmail
.
gettext
(
'kolab_files.storageautherror'
).
replace
(
'$title'
,
i
),
'error'
);
}
delete
result
.
auth_errors
[
i
];
}
});
$
.
extend
(
this
.
auth_errors
,
result
.
auth_errors
);
}
// ask for password to the first storage on the list
var
ref
=
this
;
$
.
each
(
this
.
auth_errors
||
[],
function
(
i
,
v
)
{
if
(
file_api
.
folder_list_auth_dialog
(
i
,
v
))
return
false
;
});
};
// create dialog for user credentials of external storage
this
.
folder_list_auth_dialog
=
function
(
label
,
driver
)
{
var
args
=
{
width
:
400
,
height
:
300
,
buttons
:
{}},
dialog
=
$
(
'#files-folder-auth-dialog'
),
content
=
this
.
folder_list_auth_form
(
driver
);
if
(
$
(
'#files-folder-auth-dialog'
).
is
(
':visible'
))
return
false
;
dialog
.
find
(
'table.propform'
).
remove
();
$
(
'.auth-options'
,
dialog
).
before
(
content
);
args
.
buttons
[
this
.
t
(
'kolab_files.save'
)]
=
function
()
{
var
data
=
{
folder
:
label
,
list
:
1
,
permissions
:
1
,
level
:
-
2
};
$
(
'input'
,
dialog
).
each
(
function
()
{
data
[
this
.
name
]
=
this
.
type
==
'checkbox'
&&
!
this
.
checked
?
''
:
this
.
value
;
});
file_api
.
req
=
file_api
.
set_busy
(
true
,
'kolab_files.authenticating'
);
file_api
.
request
(
'folder_auth'
,
data
,
'folder_auth_response'
);
kolab_dialog_close
(
this
);
};
args
.
buttons
[
this
.
t
(
'kolab_files.cancel'
)]
=
function
()
{
delete
file_api
.
auth_errors
[
label
];
kolab_dialog_close
(
this
);
// go to the next one
file_api
.
folder_list_auth_errors
();
};
args
.
title
=
this
.
t
(
'kolab_files.folderauthtitle'
).
replace
(
'$title'
,
label
);
args
.
button_classes
=
[
'mainaction save'
,
'cancel'
];
// show dialog window
kolab_dialog_show
(
dialog
,
args
,
function
()
{
// focus first empty input
$
(
'input'
,
dialog
).
each
(
function
()
{
if
(
!
this
.
value
)
{
this
.
focus
();
return
false
;
}
});
});
return
true
;
};
// folder_auth handler
this
.
folder_auth_response
=
function
(
response
,
params
)
{
if
(
!
this
.
response
(
response
))
{
this
.
folder_list_auth_errors
();
return
;
}
delete
this
.
auth_errors
[
response
.
result
.
folder
];
// go to the next one
this
.
folder_list_auth_errors
();
// update the list
this
.
folder_list_merge
(
response
.
result
.
folder
,
response
.
result
.
list
,
params
.
level
);
};
// Update folders list with additional folders
this
.
folder_list_merge
=
function
(
folder
,
list
,
level
)
{
if
(
!
list
||
!
list
.
length
)
return
;
var
i
,
last
,
folders
,
result
=
{},
index
=
[],
ref
=
this
;
if
(
this
.
list_merge_lock
)
{
return
setTimeout
(
function
()
{
ref
.
folder_list_merge
(
folder
,
list
);
},
50
);
}
this
.
list_merge_lock
=
true
;
// Parse result
folders
=
this
.
folder_list_parse
(
list
);
if
(
level
<
0
)
level
*=
-
1
;
// Add folders from the external source to the list
$
.
each
(
folders
,
function
(
i
,
f
)
{
if
(
ref
.
env
.
folders
[
i
])
{
last
=
i
;
return
;
}
// We don't use this id
delete
f
.
id
;
// Append row to the list
var
row
=
file_api
.
folder_list_row
(
i
,
f
);
if
(
row
)
ref
.
list_element
.
append
(
row
);
// Need env.folders update so all parents are available
// in successive folder_list_row() calls
ref
.
env
.
folders
[
i
]
=
f
;
index
.
push
(
i
);
// Load deeper folder hierarchies
if
(
level
&&
f
.
depth
==
level
)
ref
.
folder_list_update_wait
(
i
);
});
// Reset folders list widget
rcmail
.
folder_list
.
reset
(
true
,
true
);
// Rebuild folders list with correct order
for
(
i
in
this
.
env
.
folders
)
{
result
[
i
]
=
this
.
env
.
folders
[
i
];
if
(
i
===
last
)
break
;
}
for
(
i
in
index
)
{
result
[
index
[
i
]]
=
this
.
env
.
folders
[
index
[
i
]];
}
for
(
i
in
this
.
env
.
folders
)
{
if
(
!
result
[
i
])
{
result
[
i
]
=
this
.
env
.
folders
[
i
];
}
}
this
.
env
.
folders
=
result
;
if
((
folder
=
this
.
env
.
folder
)
||
(
folder
=
this
.
env
.
init_folder
))
{
if
(
this
.
env
.
folders
[
folder
])
{
this
.
env
.
init_folder
=
null
;
if
(
folder
!=
rcmail
.
folder_list
.
get_selection
())
rcmail
.
folder_list
.
select
(
folder
);
}
}
this
.
list_merge_lock
=
false
;
};
// returns content of the external storage authentication form
this
.
folder_list_auth_form
=
function
(
driver
)
{
var
rows
=
[];
$
.
each
(
driver
.
form
,
function
(
fi
,
fv
)
{
var
id
=
'authinput'
+
fi
,
attrs
=
{
type
:
fi
.
match
(
/pass/
)
?
'password'
:
'text'
,
size
:
25
,
name
:
fi
,
id
:
id
},
input
=
$
(
'<input>'
).
attr
(
attrs
);
if
(
driver
.
form_values
&&
driver
.
form_values
[
fi
])
input
.
attr
({
value
:
driver
.
form_values
[
fi
]});
rows
.
push
(
$
(
'<tr>'
)
.
append
(
$
(
'<td class="title">'
).
append
(
$
(
'<label>'
).
attr
(
'for'
,
id
).
text
(
fv
)))
.
append
(
$
(
'<td>'
).
append
(
input
))
);
});
return
$
(
'<table class="propform">'
).
append
(
rows
);
};
};
File Metadata
Details
Attached
Mime Type
text/html
Expires
Mon, Aug 25, 3:13 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
225769
Default Alt Text
kolab_files.js (130 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment