- 1 :
/**
- 2 :
* Kolab groupware utilities
- 3 :
*
- 4 :
* @author Thomas Bruederli <bruederli@kolabsys.com>
- 5 :
*
- 6 :
* @licstart The following is the entire license notice for the
- 7 :
* JavaScript code in this file.
- 8 :
*
- 9 :
* Copyright (C) 2015-2018, Kolab Systems AG <contact@kolabsys.com>
- 10 :
*
- 11 :
* This program is free software: you can redistribute it and/or modify
- 12 :
* it under the terms of the GNU Affero General Public License as
- 13 :
* published by the Free Software Foundation, either version 3 of the
- 14 :
* License, or (at your option) any later version.
- 15 :
*
- 16 :
* This program is distributed in the hope that it will be useful,
- 17 :
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- 18 :
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- 19 :
* GNU Affero General Public License for more details.
- 20 :
*
- 21 :
* You should have received a copy of the GNU Affero General Public License
- 22 :
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- 23 :
*
- 24 :
* @licend The above is the entire license notice
- 25 :
* for the JavaScript code in this file.
- 26 :
*/
- 27 :
- 28 :
var libkolab_audittrail = {}, libkolab = {};
- 29 :
- 30 :
libkolab_audittrail.quote_html = function(str)
- 31 :
{
- 32 :
return String(str).replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
- 33 :
};
- 34 :
- 35 :
// show object changelog in a dialog
- 36 :
libkolab_audittrail.object_history_dialog = function(p)
- 37 :
{
- 38 :
// render dialog
- 39 :
var $dialog = $(p.container);
- 40 :
- 41 :
// close show dialog first
- 42 :
if ($dialog.is(':ui-dialog'))
- 43 :
$dialog.dialog('close');
- 44 :
- 45 :
// hide and reset changelog table
- 46 :
$dialog.find('div.notfound-message').remove();
- 47 :
$dialog.find('.changelog-table').show().children('tbody')
- 48 :
.html('<tr><td colspan="4"><span class="loading">' + rcmail.gettext('loading') + '</span></td></tr>');
- 49 :
- 50 :
// open jquery UI dialog
- 51 :
$dialog.dialog({
- 52 :
modal: true,
- 53 :
resizable: true,
- 54 :
closeOnEscape: true,
- 55 :
title: p.title,
- 56 :
open: function() {
- 57 :
$dialog.attr('aria-hidden', 'false');
- 58 :
},
- 59 :
close: function() {
- 60 :
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
- 61 :
},
- 62 :
buttons: [
- 63 :
{
- 64 :
text: rcmail.gettext('close'),
- 65 :
click: function() { $dialog.dialog('close'); },
- 66 :
'class': 'cancel',
- 67 :
autofocus: true
- 68 :
}
- 69 :
],
- 70 :
minWidth: 450,
- 71 :
width: 650,
- 72 :
height: 350,
- 73 :
minHeight: 200
- 74 :
})
- 75 :
.show().children('.compare-button').hide();
- 76 :
- 77 :
// initialize event handlers for history dialog UI elements
- 78 :
if (!$dialog.data('initialized')) {
- 79 :
// compare button
- 80 :
$dialog.find('.compare-button input').click(function(e) {
- 81 :
var rev1 = $dialog.find('.changelog-table input.diff-rev1:checked').val(),
- 82 :
rev2 = $dialog.find('.changelog-table input.diff-rev2:checked').val();
- 83 :
- 84 :
if (rev1 && rev2 && rev1 != rev2) {
- 85 :
// swap revisions if the user got it wrong
- 86 :
if (rev1 > rev2) {
- 87 :
var tmp = rev2;
- 88 :
rev2 = rev1;
- 89 :
rev1 = tmp;
- 90 :
}
- 91 :
- 92 :
if (p.comparefunc) {
- 93 :
p.comparefunc(rev1, rev2);
- 94 :
}
- 95 :
}
- 96 :
else {
- 97 :
alert('Invalid selection!')
- 98 :
}
- 99 :
- 100 :
if (!rcube_event.is_keyboard(e) && this.blur) {
- 101 :
this.blur();
- 102 :
}
- 103 :
return false;
- 104 :
});
- 105 :
- 106 :
// delegate handlers for list actions
- 107 :
$dialog.find('.changelog-table tbody').on('click', 'td.actions a', function(e) {
- 108 :
var link = $(this),
- 109 :
action = link.hasClass('restore') ? 'restore' : 'show',
- 110 :
event = $('#eventhistory').data('event'),
- 111 :
rev = link.attr('data-rev');
- 112 :
- 113 :
// ignore clicks on first row (current revision)
- 114 :
if (link.closest('tr').hasClass('first')) {
- 115 :
return false;
- 116 :
}
- 117 :
- 118 :
// let the user confirm the restore action
- 119 :
if (action == 'restore' && !confirm(rcmail.gettext('revisionrestoreconfirm', p.module).replace('$rev', rev))) {
- 120 :
return false;
- 121 :
}
- 122 :
- 123 :
if (p.listfunc) {
- 124 :
p.listfunc(action, rev);
- 125 :
}
- 126 :
- 127 :
if (!rcube_event.is_keyboard(e) && this.blur) {
- 128 :
this.blur();
- 129 :
}
- 130 :
return false;
- 131 :
})
- 132 :
.on('click', 'input.diff-rev1', function(e) {
- 133 :
if (!this.checked) return true;
- 134 :
- 135 :
var rev1 = this.value, selection_valid = false;
- 136 :
$dialog.find('.changelog-table input.diff-rev2').each(function(i, elem) {
- 137 :
$(elem).prop('disabled', elem.value <= rev1);
- 138 :
if (elem.checked && elem.value > rev1) {
- 139 :
selection_valid = true;
- 140 :
}
- 141 :
});
- 142 :
if (!selection_valid) {
- 143 :
$dialog.find('.changelog-table input.diff-rev2:not([disabled])').last().prop('checked', true);
- 144 :
}
- 145 :
});
- 146 :
- 147 :
$dialog.addClass('changelog-dialog').data('initialized', true);
- 148 :
}
- 149 :
- 150 :
return $dialog;
- 151 :
};
- 152 :
- 153 :
// callback from server with changelog data
- 154 :
libkolab_audittrail.render_changelog = function(data, object, folder)
- 155 :
{
- 156 :
var Q = libkolab_audittrail.quote_html;
- 157 :
- 158 :
var $dialog = $('.changelog-dialog')
- 159 :
if (data === false || !data.length) {
- 160 :
return false;
- 161 :
}
- 162 :
- 163 :
var i, change, accessible, op_append,
- 164 :
first = data.length - 1, last = 0,
- 165 :
is_writeable = !!folder.editable,
- 166 :
op_labels = {
- 167 :
RECEIVE: 'actionreceive',
- 168 :
APPEND: 'actionappend',
- 169 :
MOVE: 'actionmove',
- 170 :
DELETE: 'actiondelete',
- 171 :
READ: 'actionread',
- 172 :
FLAGSET: 'actionflagset',
- 173 :
FLAGCLEAR: 'actionflagclear'
- 174 :
},
- 175 :
actions = '<a href="#show" class="iconbutton preview" title="'+ rcmail.gettext('showrevision','libkolab') +'" data-rev="{rev}" /> ' +
- 176 :
(is_writeable ? '<a href="#restore" class="iconbutton restore" title="'+ rcmail.gettext('restore','libkolab') + '" data-rev="{rev}" />' : ''),
- 177 :
tbody = $dialog.find('.changelog-table tbody').html('');
- 178 :
- 179 :
for (i=first; i >= 0; i--) {
- 180 :
change = data[i];
- 181 :
accessible = change.date && change.user;
- 182 :
- 183 :
if (change.op == 'MOVE' && change.mailbox) {
- 184 :
op_append = ' ⇢ ' + change.mailbox;
- 185 :
}
- 186 :
else if ((change.op == 'FLAGSET' || change.op == 'FLAGCLEAR') && change.flags) {
- 187 :
op_append = ': ' + change.flags;
- 188 :
}
- 189 :
else {
- 190 :
op_append = '';
- 191 :
}
- 192 :
- 193 :
$('<tr class="' + (i == first ? 'first' : (i == last ? 'last' : '')) + (accessible ? '' : 'undisclosed') + '">')
- 194 :
.append('<td class="diff">' + (accessible && change.op != 'DELETE' ?
- 195 :
'<input type="radio" name="rev1" class="diff-rev1" value="' + change.rev + '" title="" '+ (i == last ? 'checked="checked"' : '') +' /> '+
- 196 :
'<input type="radio" name="rev2" class="diff-rev2" value="' + change.rev + '" title="" '+ (i == first ? 'checked="checked"' : '') +' /></td>'
- 197 :
: ''))
- 198 :
.append('<td class="revision">' + Q(i+1) + '</td>')
- 199 :
.append('<td class="date">' + Q(change.date || '') + '</td>')
- 200 :
.append('<td class="user">' + Q(change.user || 'undisclosed') + '</td>')
- 201 :
.append('<td class="operation" title="' + op_append + '">' + Q(rcmail.gettext(op_labels[change.op] || '', 'libkolab') + op_append) + '</td>')
- 202 :
.append('<td class="actions">' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + '</td>')
- 203 :
.appendTo(tbody);
- 204 :
}
- 205 :
- 206 :
if (first > 0) {
- 207 :
$dialog.find('.compare-button').fadeIn(200);
- 208 :
$dialog.find('.changelog-table tr.last input.diff-rev1').click();
- 209 :
}
- 210 :
- 211 :
// set dialog size according to content
- 212 :
libkolab_audittrail.dialog_resize($dialog.get(0), $dialog.height() + 15, 600);
- 213 :
- 214 :
return $dialog;
- 215 :
};
- 216 :
- 217 :
// resize and reposition (center) the dialog window
- 218 :
libkolab_audittrail.dialog_resize = function(id, height, width)
- 219 :
{
- 220 :
var win = $(window), w = win.width(), h = win.height();
- 221 :
$(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) });
- 222 :
};
- 223 :
- 224 :
/**
- 225 :
* Open an attachment either in a browser window for inline view or download it
- 226 :
*/
- 227 :
libkolab.load_attachment = function(query, attachment)
- 228 :
{
- 229 :
query._frame = 1;
- 230 :
- 231 :
// open attachment in frame if it's of a supported mimetype similar as in app.js
- 232 :
if (attachment.id && attachment.mimetype && $.inArray(attachment.mimetype, rcmail.env.mimetypes) >= 0) {
- 233 :
if (rcmail.open_window(rcmail.url('get-attachment', query), true, true)) {
- 234 :
return;
- 235 :
}
- 236 :
}
- 237 :
- 238 :
query._frame = null;
- 239 :
query._download = 1;
- 240 :
rcmail.goto_url('get-attachment', query, false);
- 241 :
};
- 242 :
- 243 :
/**
- 244 :
* Build attachments list element
- 245 :
*/
- 246 :
libkolab.list_attachments = function(list, container, edit, data, ondelete, onload)
- 247 :
{
- 248 :
var ul = $('<ul>').addClass('attachmentslist');
- 249 :
- 250 :
$.each(list || [], function(i, elem) {
- 251 :
var li = $('<li>').addClass(elem.classname);
- 252 :
- 253 :
// name/link
- 254 :
$('<a>').attr({href: '#load', 'class': 'filename'})
- 255 :
.append($('<span class="attachment-name">').text(elem.name))
- 256 :
.click({record: data, attachment: elem}, function(e) {
- 257 :
if (onload) {
- 258 :
onload(e.data);
- 259 :
}
- 260 :
return false;
- 261 :
})
- 262 :
.appendTo(li);
- 263 :
- 264 :
if (edit) {
- 265 :
rcmail.env.attachments[elem.id] = elem;
- 266 :
// delete link
- 267 :
$('<a>').attr({href: '#delete', title: rcmail.gettext('delete'), 'class': 'delete'})
- 268 :
.click({id: elem.id}, function(e) {
- 269 :
$(this.parentNode).hide();
- 270 :
delete rcmail.env.attachments[e.data.id];
- 271 :
if (ondelete) {
- 272 :
ondelete(e.data.id);
- 273 :
}
- 274 :
return false;
- 275 :
})
- 276 :
.appendTo(li);
- 277 :
}
- 278 :
- 279 :
ul.append(li);
- 280 :
});
- 281 :
- 282 :
if (edit && rcmail.gui_objects.attachmentlist) {
- 283 :
ul.id = rcmail.gui_objects.attachmentlist.id;
- 284 :
rcmail.gui_objects.attachmentlist = ul.get(0);
- 285 :
}
- 286 :
- 287 :
container.empty().append(ul);
- 288 :
};
- 289 :
- 290 :
- 291 :
function kolab_folderlist(node, p)
- 292 :
{
- 293 :
// extends treelist.js
- 294 :
rcube_treelist_widget.call(this, node, p);
- 295 :
- 296 :
// private vars
- 297 :
var me = this;
- 298 :
var search_results;
- 299 :
var search_results_widget;
- 300 :
var search_results_container;
- 301 :
var listsearch_request;
- 302 :
var search_messagebox;
- 303 :
- 304 :
var Q = rcmail.quote_html;
- 305 :
- 306 :
// render the results for folderlist search
- 307 :
function render_search_results(results)
- 308 :
{
- 309 :
if (results.length) {
- 310 :
// create treelist widget to present the search results
- 311 :
if (!search_results_widget) {
- 312 :
var list_id = (me.container.attr('id') || p.id_prefix || '0');
- 313 :
- 314 :
search_results_container = $('<div class="searchresults"></div>')
- 315 :
.html(p.search_title ? '<h2 class="boxtitle" id="st:' + list_id + '">' + p.search_title + '</h2>' : '')
- 316 :
.insertAfter(me.container);
- 317 :
- 318 :
search_results_widget = new rcube_treelist_widget('<ul>', {
- 319 :
id_prefix: p.id_prefix,
- 320 :
id_encode: p.id_encode,
- 321 :
id_decode: p.id_decode,
- 322 :
selectable: false
- 323 :
});
- 324 :
- 325 :
// copy classes from main list
- 326 :
search_results_widget.container.addClass(me.container.attr('class')).attr('aria-labelledby', 'st:' + list_id);
- 327 :
- 328 :
// register click handler on search result's checkboxes to select the given item for listing
- 329 :
search_results_widget.container
- 330 :
.appendTo(search_results_container)
- 331 :
.on('click', 'input[type=checkbox], a.subscribed, span.subscribed', function(e) {
- 332 :
var node, has_children, li = $(this).closest('li'),
- 333 :
id = li.attr('id').replace(new RegExp('^'+p.id_prefix), '');
- 334 :
- 335 :
if (p.id_decode)
- 336 :
id = p.id_decode(id);
- 337 :
node = search_results_widget.get_node(id);
- 338 :
has_children = node.children && node.children.length;
- 339 :
- 340 :
e.stopPropagation();
- 341 :
e.bubbles = false;
- 342 :
- 343 :
// activate + subscribe
- 344 :
if ($(e.target).hasClass('subscribed')) {
- 345 :
search_results[id].subscribed = true;
- 346 :
$(e.target).attr('aria-checked', 'true');
- 347 :
li.children().first()
- 348 :
.toggleClass('subscribed')
- 349 :
.find('input[type=checkbox]').get(0).checked = true;
- 350 :
- 351 :
if (has_children && search_results[id].group == 'other user') {
- 352 :
li.find('ul li > div').addClass('subscribed')
- 353 :
.find('a.subscribed').attr('aria-checked', 'true');;
- 354 :
}
- 355 :
}
- 356 :
else if (!this.checked) {
- 357 :
return;
- 358 :
}
- 359 :
- 360 :
// copy item to the main list
- 361 :
add_result2list(id, li, true);
- 362 :
- 363 :
if (has_children) {
- 364 :
li.find('input[type=checkbox]').first().prop('disabled', true).prop('checked', true);
- 365 :
li.find('a.subscribed, span.subscribed').first().hide();
- 366 :
}
- 367 :
else {
- 368 :
li.remove();
- 369 :
}
- 370 :
- 371 :
// set partial subscription status
- 372 :
if (search_results[id].subscribed && search_results[id].parent && search_results[id].group == 'other') {
- 373 :
parent_subscription_status($(me.get_item(id, true)));
- 374 :
}
- 375 :
- 376 :
// set focus to cloned checkbox
- 377 :
if (rcube_event.is_keyboard(e)) {
- 378 :
$(me.get_item(id, true)).find('input[type=checkbox]').first().focus();
- 379 :
}
- 380 :
})
- 381 :
.on('click', function(e) {
- 382 :
var prop, id = String($(e.target).closest('li').attr('id')).replace(new RegExp('^'+p.id_prefix), '');
- 383 :
if (p.id_decode)
- 384 :
id = p.id_decode(id);
- 385 :
- 386 :
if (!rcube_event.is_keyboard(e) && e.target.blur)
- 387 :
e.target.blur();
- 388 :
- 389 :
// forward event
- 390 :
if (prop = search_results[id]) {
- 391 :
e.data = prop;
- 392 :
if (me.triggerEvent('click-item', e) === false) {
- 393 :
e.stopPropagation();
- 394 :
return false;
- 395 :
}
- 396 :
}
- 397 :
});
- 398 :
}
- 399 :
- 400 :
// add results to list
- 401 :
for (var prop, item, i=0; i < results.length; i++) {
- 402 :
prop = results[i];
- 403 :
item = $(prop.html);
- 404 :
search_results[prop.id] = prop;
- 405 :
search_results_widget.insert({
- 406 :
id: prop.id,
- 407 :
classes: [ prop.group || '' ],
- 408 :
html: item,
- 409 :
collapsed: true,
- 410 :
virtual: prop.virtual
- 411 :
}, prop.parent);
- 412 :
- 413 :
// disable checkbox if item already exists in main list
- 414 :
if (me.get_node(prop.id) && !me.get_node(prop.id).virtual) {
- 415 :
item.find('input[type=checkbox]').first().prop('disabled', true).prop('checked', true);
- 416 :
item.find('a.subscribed, span.subscribed').hide();
- 417 :
}
- 418 :
- 419 :
prop.li = item.parent().get(0);
- 420 :
me.triggerEvent('add-item', prop);
- 421 :
}
- 422 :
- 423 :
search_results_container.show();
- 424 :
}
- 425 :
}
- 426 :
- 427 :
// helper method to (recursively) add a search result item to the main list widget
- 428 :
function add_result2list(id, li, active)
- 429 :
{
- 430 :
var node = search_results_widget.get_node(id),
- 431 :
prop = search_results[id],
- 432 :
parent_id = prop.parent || null,
- 433 :
has_children = node.children && node.children.length,
- 434 :
dom_node = has_children ? li.children().first().clone(true, true) : li.children().first(),
- 435 :
childs = [];
- 436 :
- 437 :
// find parent node and insert at the right place
- 438 :
if (parent_id && me.get_node(parent_id)) {
- 439 :
dom_node.children('span,a').first().html(Q(prop.editname || prop.listname));
- 440 :
}
- 441 :
else if (parent_id && search_results[parent_id]) {
- 442 :
// copy parent tree from search results
- 443 :
add_result2list(parent_id, $(search_results_widget.get_item(parent_id)), false);
- 444 :
}
- 445 :
else if (parent_id) {
- 446 :
// use full name for list display
- 447 :
dom_node.children('span,a').first().html(Q(prop.name));
- 448 :
}
- 449 :
- 450 :
// replace virtual node with a real one
- 451 :
if (me.get_node(id)) {
- 452 :
$(me.get_item(id, true)).children().first()
- 453 :
.replaceWith(dom_node)
- 454 :
.removeClass('virtual');
- 455 :
}
- 456 :
else {
- 457 :
// copy childs, too
- 458 :
if (has_children && prop.group == 'other user') {
- 459 :
for (var cid, j=0; j < node.children.length; j++) {
- 460 :
if ((cid = node.children[j].id) && search_results[cid]) {
- 461 :
childs.push(search_results_widget.get_node(cid));
- 462 :
}
- 463 :
}
- 464 :
}
- 465 :
- 466 :
// move this result item to the main list widget
- 467 :
me.insert({
- 468 :
id: id,
- 469 :
classes: [ prop.group || '' ],
- 470 :
virtual: prop.virtual,
- 471 :
html: dom_node,
- 472 :
level: node.level,
- 473 :
collapsed: true,
- 474 :
children: childs
- 475 :
}, parent_id, prop.group);
- 476 :
}
- 477 :
- 478 :
delete prop.html;
- 479 :
prop.active = active;
- 480 :
me.triggerEvent('insert-item', { id: id, data: prop, item: li });
- 481 :
- 482 :
// register childs, too
- 483 :
if (childs.length) {
- 484 :
for (var cid, j=0; j < node.children.length; j++) {
- 485 :
if ((cid = node.children[j].id) && search_results[cid]) {
- 486 :
prop = search_results[cid];
- 487 :
delete prop.html;
- 488 :
prop.active = false;
- 489 :
me.triggerEvent('insert-item', { id: cid, data: prop });
- 490 :
}
- 491 :
}
- 492 :
}
- 493 :
}
- 494 :
- 495 :
// update the given item's parent's (partial) subscription state
- 496 :
function parent_subscription_status(li)
- 497 :
{
- 498 :
var top_li = li.closest(me.container.children('li')),
- 499 :
all_childs = $('li > div:not(.treetoggle)', top_li),
- 500 :
subscribed = all_childs.filter('.subscribed').length;
- 501 :
- 502 :
if (subscribed == 0) {
- 503 :
top_li.children('div:first').removeClass('subscribed partial');
- 504 :
}
- 505 :
else {
- 506 :
top_li.children('div:first')
- 507 :
.addClass('subscribed')[subscribed < all_childs.length ? 'addClass' : 'removeClass']('partial');
- 508 :
}
- 509 :
}
- 510 :
- 511 :
// do some magic when search is performed on the widget
- 512 :
this.addEventListener('search', function(search) {
- 513 :
// hide search results
- 514 :
if (search_results_widget) {
- 515 :
search_results_container.hide();
- 516 :
search_results_widget.reset();
- 517 :
}
- 518 :
search_results = {};
- 519 :
- 520 :
if (search_messagebox)
- 521 :
rcmail.hide_message(search_messagebox);
- 522 :
- 523 :
// send search request(s) to server
- 524 :
if (search.query && search.execute) {
- 525 :
// require a minimum length for the search string
- 526 :
if (rcmail.env.autocomplete_min_length && search.query.length < rcmail.env.autocomplete_min_length && search.query != '*') {
- 527 :
search_messagebox = rcmail.display_message(
- 528 :
rcmail.get_label('autocompletechars').replace('$min', rcmail.env.autocomplete_min_length));
- 529 :
return;
- 530 :
}
- 531 :
- 532 :
if (listsearch_request) {
- 533 :
// ignore, let the currently running request finish
- 534 :
if (listsearch_request.query == search.query) {
- 535 :
return;
- 536 :
}
- 537 :
else { // cancel previous search request
- 538 :
rcmail.multi_thread_request_abort(listsearch_request.id);
- 539 :
listsearch_request = null;
- 540 :
}
- 541 :
}
- 542 :
- 543 :
var sources = p.search_sources || [ 'folders' ];
- 544 :
var reqid = rcmail.multi_thread_http_request({
- 545 :
items: sources,
- 546 :
threads: rcmail.env.autocomplete_threads || 1,
- 547 :
action: p.search_action || 'listsearch',
- 548 :
postdata: { action:'search', q:search.query, source:'%s' },
- 549 :
lock: rcmail.display_message(rcmail.get_label('searching'), 'loading'),
- 550 :
onresponse: render_search_results,
- 551 :
whendone: function(data){
- 552 :
listsearch_request = null;
- 553 :
me.triggerEvent('search-complete', data);
- 554 :
}
- 555 :
});
- 556 :
- 557 :
listsearch_request = { id:reqid, query:search.query };
- 558 :
}
- 559 :
else if (!search.query && listsearch_request) {
- 560 :
rcmail.multi_thread_request_abort(listsearch_request.id);
- 561 :
listsearch_request = null;
- 562 :
}
- 563 :
});
- 564 :
- 565 :
this.container.on('click', 'a.subscribed, span.subscribed', function(e) {
- 566 :
var li = $(this).closest('li'),
- 567 :
id = li.attr('id').replace(new RegExp('^'+p.id_prefix), ''),
- 568 :
div = li.children().first(),
- 569 :
is_subscribed;
- 570 :
- 571 :
if (me.is_search()) {
- 572 :
id = id.replace(/--xsR$/, '');
- 573 :
li = $(me.get_item(id, true));
- 574 :
div = $(div).add(li.children().first());
- 575 :
}
- 576 :
- 577 :
if (p.id_decode)
- 578 :
id = p.id_decode(id);
- 579 :
- 580 :
div.toggleClass('subscribed');
- 581 :
is_subscribed = div.hasClass('subscribed');
- 582 :
$(this).attr('aria-checked', is_subscribed ? 'true' : 'false');
- 583 :
me.triggerEvent('subscribe', { id: id, subscribed: is_subscribed, item: li });
- 584 :
- 585 :
// update subscribe state of all 'virtual user' child folders
- 586 :
if (li.hasClass('other user')) {
- 587 :
$('ul li > div', li).each(function() {
- 588 :
$(this)[is_subscribed ? 'addClass' : 'removeClass']('subscribed');
- 589 :
$('.subscribed', div).attr('aria-checked', is_subscribed ? 'true' : 'false');
- 590 :
});
- 591 :
div.removeClass('partial');
- 592 :
}
- 593 :
// propagate subscription state to parent 'virtual user' folder
- 594 :
else if (li.closest('li.other.user').length) {
- 595 :
parent_subscription_status(li);
- 596 :
}
- 597 :
- 598 :
e.stopPropagation();
- 599 :
return false;
- 600 :
});
- 601 :
- 602 :
this.container.on('click', 'a.remove', function(e) {
- 603 :
var li = $(this).closest('li'),
- 604 :
id = li.attr('id').replace(new RegExp('^'+p.id_prefix), '');
- 605 :
- 606 :
if (me.is_search()) {
- 607 :
id = id.replace(/--xsR$/, '');
- 608 :
li = $(me.get_item(id, true));
- 609 :
}
- 610 :
- 611 :
if (p.id_decode)
- 612 :
id = p.id_decode(id);
- 613 :
- 614 :
me.triggerEvent('remove', { id: id, item: li });
- 615 :
- 616 :
e.stopPropagation();
- 617 :
return false;
- 618 :
});
- 619 :
}
- 620 :
- 621 :
// link prototype from base class
- 622 :
if (window.rcube_treelist_widget) {
- 623 :
kolab_folderlist.prototype = rcube_treelist_widget.prototype;
- 624 :
}
- 625 :
- 626 :
- 627 :
window.rcmail && rcmail.addEventListener('init', function(e) {
- 628 :
var loading_lock;
- 629 :
- 630 :
if (rcmail.env.task == 'mail') {
- 631 :
rcmail.register_command('kolab-mail-history', function() {
- 632 :
var dialog, uid = rcmail.get_single_uid(), rec = { uid: uid, mbox: rcmail.get_message_mailbox(uid) };
- 633 :
if (!uid || !window.libkolab_audittrail) {
- 634 :
return false;
- 635 :
}
- 636 :
- 637 :
// render dialog
- 638 :
$dialog = libkolab_audittrail.object_history_dialog({
- 639 :
module: 'libkolab',
- 640 :
container: '#mailmessagehistory',
- 641 :
title: rcmail.gettext('objectchangelog','libkolab')
- 642 :
});
- 643 :
- 644 :
$dialog.data('rec', rec);
- 645 :
- 646 :
// fetch changelog data
- 647 :
loading_lock = rcmail.set_busy(true, 'loading', loading_lock);
- 648 :
rcmail.http_post('plugin.message-changelog', { _uid: rec.uid, _mbox: rec.mbox }, loading_lock);
- 649 :
- 650 :
}, rcmail.env.action == 'show');
- 651 :
- 652 :
rcmail.addEventListener('plugin.message_render_changelog', function(data) {
- 653 :
var $dialog = $('#mailmessagehistory'),
- 654 :
rec = $dialog.data('rec');
- 655 :
- 656 :
if (data === false || !data.length || !rec) {
- 657 :
// display 'unavailable' message
- 658 :
$('<div class="notfound-message dialog-message warning">' + rcmail.gettext('objectchangelognotavailable','libkolab') + '</div>')
- 659 :
.insertBefore($dialog.find('.changelog-table').hide());
- 660 :
return;
- 661 :
}
- 662 :
- 663 :
data.module = 'libkolab';
- 664 :
libkolab_audittrail.render_changelog(data, rec, {});
- 665 :
});
- 666 :
- 667 :
rcmail.env.message_commands.push('kolab-mail-history');
- 668 :
}
- 669 :
- 670 :
if (rcmail.env.action == 'get-attachment') {
- 671 :
if (rcmail.gui_objects.attachmentframe) {
- 672 :
rcmail.gui_objects.messagepartframe = rcmail.gui_objects.attachmentframe;
- 673 :
rcmail.enable_command('image-scale', 'image-rotate', !!/^image\//.test(rcmail.env.mimetype));
- 674 :
rcmail.register_command('print-attachment', function() {
- 675 :
var frame = rcmail.get_frame_window(rcmail.gui_objects.attachmentframe.id);
- 676 :
if (frame) frame.print();
- 677 :
}, true);
- 678 :
}
- 679 :
- 680 :
if (rcmail.env.attachment_download_url) {
- 681 :
rcmail.register_command('download-attachment', function() {
- 682 :
rcmail.location_href(rcmail.env.attachment_download_url, window);
- 683 :
}, true);
- 684 :
}
- 685 :
}
- 686 :
});