0
|
1 /**
|
|
2 * ContextMenu plugin script
|
|
3 *
|
|
4 * @licstart The following is the entire license notice for the
|
|
5 * JavaScript code in this file.
|
|
6 *
|
|
7 * Copyright (C) 2009-2014 Philip Weir
|
|
8 *
|
|
9 * The JavaScript code in this page is free software: you can redistribute it
|
|
10 * and/or modify it under the terms of the GNU General Public License
|
|
11 * as published by the Free Software Foundation, either version 3 of
|
|
12 * the License, or (at your option) any later version.
|
|
13 *
|
|
14 * @licend The above is the entire license notice
|
|
15 * for the JavaScript code in this file.
|
|
16 */
|
|
17
|
|
18 rcube_webmail.prototype.context_menu_skip_commands = new Array('mail-checkmail', 'mail-compose', 'addressbook-add', 'addressbook-import', 'addressbook-advanced-search', 'addressbook-search-create');
|
|
19 rcube_webmail.prototype.context_menu_overload_commands = new Array('move', 'copy');
|
|
20 rcube_webmail.prototype.context_menu_commands = new Array();
|
|
21 rcube_webmail.prototype.context_menu_popup_menus = new Array();
|
|
22 rcube_webmail.prototype.context_menu_popup_commands = {};
|
|
23
|
|
24 rcube_webmail.prototype.context_menu_command_pattern = /rcmail\.command\(\'([^\']+)\',\s?\'((?:\\\'|[^\'])*)\'/;
|
|
25
|
|
26 function rcm_listmenu_init(row, props, events) {
|
|
27 if (!events)
|
|
28 events = {};
|
|
29
|
|
30 var menu = rcm_callbackmenu_init(props, $.extend({
|
|
31 'beforeactivate': function(p) {
|
|
32 rcmail.env.contextmenu_selection = p.ref.list_selection(true);
|
|
33 },
|
|
34 'afteractivate': function(p) {
|
|
35 p.ref.menu_selection = p.ref.list_object.get_selection();
|
|
36 p.ref.list_selection(false, rcmail.env.contextmenu_selection);
|
|
37 }
|
|
38 }, events));
|
|
39
|
|
40 var list_object = props.list_object ? props.list_object : rcmail.message_list;
|
|
41 $("#" + row).on("contextmenu", function(e) {
|
|
42 if (uid = list_object.get_row_uid(this)) {
|
|
43 rcm_show_menu(e, this, uid, menu);
|
|
44 }
|
|
45 });
|
|
46 }
|
|
47
|
|
48 function rcm_foldermenu_init(el, props, events) {
|
|
49 if (!events)
|
|
50 events = {};
|
|
51
|
|
52 var menu = rcm_callbackmenu_init($.extend({'menu_name': 'folderlist', 'list_object': null}, props), $.extend({
|
|
53 'beforeactivate': function(p) {
|
|
54 if (rcmail.env.contextmenu_messagecount_request) {
|
|
55 rcmail.env.contextmenu_messagecount_request.abort();
|
|
56 }
|
|
57 rcmail.env.contextmenu_messagecount_request = null;
|
|
58 },
|
|
59 'activate': function(p) {
|
|
60 if ($.inArray(p.command, Array('expunge', 'purge', 'mark-all-read')) >= 0) {
|
|
61 // disable the commands by default
|
|
62 $(p.el).addClass('disabled').removeClass('active');
|
|
63
|
|
64 // if menu is opened on current folder (or special mark-all-read command) then enable the commands same as in UI
|
|
65 if ((rcmail.env.context_menu_source_id == rcmail.env.mailbox || p.command == 'mark-all-read') && rcm_check_button_state(p.btn, true)) {
|
|
66 $(p.el).addClass('active').removeClass('disabled');
|
|
67 }
|
|
68 // if menu is opened on difference folder then get message count for the folder
|
|
69 else if (rcmail.env.context_menu_source_id != rcmail.env.mailbox && !rcmail.env.contextmenu_messagecount_request) {
|
|
70 // folder check called async to prevent slowdown on menu load
|
|
71 rcmail.env.contextmenu_messagecount_request = $.ajax({
|
|
72 type: 'POST', url: rcmail.url('plugin.contextmenu.messagecount'), data: {'_mbox': rcmail.env.context_menu_source_id}, dataType: 'json', async: true,
|
|
73 success: function(data) {
|
|
74 if (data.messagecount > 0 && $('#rcm_folderlist').is(':visible')) {
|
|
75 // override the environment to check if commands should be abled
|
|
76 var temp_exists = rcmail.env.exists;
|
|
77 var temp_mailbox = rcmail.env.mailbox;
|
|
78 rcmail.env.exists = data.messagecount;
|
|
79 rcmail.env.mailbox = rcmail.env.context_menu_source_id;
|
|
80
|
|
81 $('#rcm_folderlist').find('a.cmd_expunge').addClass('active').removeClass('disabled');
|
|
82 if (rcmail.purge_mailbox_test()) {
|
|
83 $('#rcm_folderlist').find('a.cmd_purge').addClass('active').removeClass('disabled');
|
|
84 }
|
|
85
|
|
86 rcmail.env.exists = temp_exists;
|
|
87 rcmail.env.mailbox = temp_mailbox;
|
|
88 }
|
|
89 }
|
|
90 });
|
|
91 }
|
|
92 }
|
|
93 },
|
|
94 'beforecommand': function(p) {
|
|
95 if (rcmail.env.context_menu_source_id != rcmail.env.mailbox && $.inArray(p.command, Array('expunge', 'purge')) >= 0) {
|
|
96 var result = rcmail[p.command + '_mailbox'](rcmail.env.context_menu_source_id);
|
|
97
|
|
98 // update the unread count and trash icon
|
|
99 if (p.command == 'purge' && result !== false) {
|
|
100 rcmail.set_unread_count(rcmail.env.context_menu_source_id, 0, false);
|
|
101
|
|
102 if (rcmail.env.context_menu_source_id == rcmail.env.trash_mailbox)
|
|
103 rcmail.set_trash_count(0);
|
|
104 }
|
|
105
|
|
106 return {'abort': true, 'result': true};
|
|
107 }
|
|
108 else if (rcmail.env.context_menu_source_id != rcmail.env.mailbox && p.command == 'mark-all-read') {
|
|
109 rcmail.mark_all_read(rcmail.env.context_menu_source_id);
|
|
110 return {'abort': true, 'result': true};
|
|
111 }
|
|
112 }
|
|
113 }, events));
|
|
114
|
|
115 $(el).click(function(e) {
|
|
116 // hide menu when changing folder
|
|
117 menu.hide(e);
|
|
118 })
|
|
119 .on("contextmenu", function(e) {
|
|
120 var source = $(this).children('a');
|
|
121
|
|
122 // remove focus (and keyboard nav highlighting) from A
|
|
123 source.blur();
|
|
124
|
|
125 if (source.attr('rel') && source.attr('onclick') && source.attr('onclick').match(rcmail.context_menu_command_pattern)) {
|
|
126 rcm_show_menu(e, this, source.attr('rel'), menu);
|
|
127 }
|
|
128 });
|
|
129 }
|
|
130
|
|
131 function rcm_abookmenu_init(el, props, events) {
|
|
132 if (!events)
|
|
133 events = {};
|
|
134
|
|
135 var menu = rcm_callbackmenu_init($.extend({'menu_name': 'abooklist'}, props), $.extend({
|
|
136 'beforeactivate': function(p) {
|
|
137 p.ref.container.find('li.submenu').remove();
|
|
138 },
|
|
139 'activate': function(p) {
|
|
140 var ids = rcmail.env.context_menu_source_id.split(':', 2);
|
|
141 cur_source = ids[0];
|
|
142
|
|
143 if (p.command == 'group-create') {
|
|
144 // addressbook
|
|
145 if ($(p.source).hasClass('addressbook') && rcmail.env.address_sources[cur_source].groups && !rcmail.env.address_sources[cur_source].readonly) {
|
|
146 $(p.el).addClass('active').removeClass('disabled');
|
|
147 }
|
|
148 else {
|
|
149 $(p.el).addClass('disabled').removeClass('active');
|
|
150 }
|
|
151 }
|
|
152 else if (p.command == 'group-rename' || p.command == 'group-delete') {
|
|
153 // group
|
|
154 if ($(p.source).hasClass('contactgroup') && !rcmail.env.address_sources[cur_source].readonly) {
|
|
155 $(p.el).addClass('active').removeClass('disabled');
|
|
156 }
|
|
157 else {
|
|
158 $(p.el).addClass('disabled').removeClass('active');
|
|
159 }
|
|
160 }
|
|
161 else if (p.command == 'search-delete') {
|
|
162 // saved search
|
|
163 if ($(p.source).hasClass('contactsearch')) {
|
|
164 $(p.el).addClass('active').removeClass('disabled');
|
|
165 }
|
|
166 else {
|
|
167 $(p.el).addClass('disabled').removeClass('active');
|
|
168 }
|
|
169 }
|
|
170 },
|
|
171 'command': function(p) {
|
|
172 if (!$(p.el).hasClass('active'))
|
|
173 return;
|
|
174
|
|
175 var prev_source = rcmail.env.source;
|
|
176 var prev_group = rcmail.env.group;
|
|
177 var result = false;
|
|
178
|
|
179 var ids = rcmail.env.context_menu_source_id.split(':', 2);
|
|
180 cur_source = ids[0];
|
|
181 cur_id = ids[1];
|
|
182
|
|
183 rcmail.env.source = cur_source;
|
|
184 rcmail.env.group = cur_id;
|
|
185
|
|
186 // enable the required command
|
|
187 var prev_command = rcmail.commands[p.command];
|
|
188 rcmail.enable_command(p.command, true);
|
|
189
|
|
190 switch (p.command) {
|
|
191 case 'search-delete':
|
|
192 var result = false;
|
|
193
|
|
194 if ($(p.ref.selected_object).children('a').attr('rel')) {
|
|
195 var prev_search_id = rcmail.env.search_id;
|
|
196 var prev_search_request = rcmail.env.search_request;
|
|
197 rcmail.env.search_request = true;
|
|
198 rcmail.env.search_id = $(p.ref.selected_object).children('a').attr('rel').replace('S', '');
|
|
199
|
|
200 result = rcmail.command(p.command, p.args, p.el, p.evt);
|
|
201
|
|
202 rcmail.env.search_request = prev_search_request;
|
|
203 rcmail.env.search_id = prev_search_id;
|
|
204 }
|
|
205 break;
|
|
206 default:
|
|
207 result = rcmail.command(p.command, p.args, p.el, p.evt);
|
|
208 break;
|
|
209 }
|
|
210
|
|
211 rcmail.enable_command(p.command, prev_command);
|
|
212 rcmail.env.source = prev_source;
|
|
213 rcmail.env.group = prev_group;
|
|
214
|
|
215 return result;
|
|
216 }
|
|
217 }, events));
|
|
218
|
|
219 $(el).click(function(e) {
|
|
220 // hide menu when changing address book
|
|
221 menu.hide(e);
|
|
222 })
|
|
223 .on("contextmenu",function(e) {
|
|
224 var source = $(this).children('a');
|
|
225
|
|
226 // remove focus (and keyboard nav highlighting) from A
|
|
227 source.blur();
|
|
228
|
|
229 if (source.attr('rel') && source.attr('rel').match(/([A-Z0-9\-_]+(:[A-Z0-9\-_]+)?)/i)) {
|
|
230 rcm_show_menu(e, this, RegExp.$1, menu);
|
|
231 }
|
|
232 });
|
|
233 }
|
|
234
|
|
235 function rcm_callbackmenu_init(props, events) {
|
|
236 var std_events = {
|
|
237 'command': function(p) {
|
|
238 if (!$(p.el).hasClass('active'))
|
|
239 return;
|
|
240
|
|
241 if (p.ref.list_object) {
|
|
242 var prev_display_next = rcmail.env.display_next;
|
|
243
|
|
244 if (!(p.ref.list_object.selection.length == 1 && p.ref.list_object.in_selection(rcmail.env.context_menu_source_id)))
|
|
245 rcmail.env.display_next = false;
|
|
246
|
|
247 var prev_sel = p.ref.list_selection(true);
|
|
248 }
|
|
249
|
|
250 // enable the required command
|
|
251 var prev_command = rcmail.commands[p.command];
|
|
252 rcmail.enable_command(p.command, true);
|
|
253 var result = rcmail.command(p.command, p.args, p.el, p.evt);
|
|
254 rcmail.enable_command(p.command, prev_command);
|
|
255
|
|
256 if (p.ref.list_object) {
|
|
257 p.ref.list_selection(false, prev_sel);
|
|
258 rcmail.env.display_next = prev_display_next;
|
|
259 }
|
|
260
|
|
261 if ($.inArray(p.command, rcmail.context_menu_overload_commands) >= 0) {
|
|
262 rcmail.context_menu_commands[p.command] = rcmail.commands[p.command];
|
|
263 rcmail.enable_command(p.command, true);
|
|
264 }
|
|
265
|
|
266 return result;
|
|
267 },
|
|
268 'activate': function(p) {
|
|
269 $(p.el).addClass(p.enabled ? 'active' : 'disabled');
|
|
270 }
|
|
271 }
|
|
272
|
|
273 if (events)
|
|
274 $.extend(std_events, events);
|
|
275
|
|
276 if (!rcmail.env.contextmenus[props.menu_name]) {
|
|
277 var menu = new rcube_context_menu(props);
|
|
278 $.each(std_events, function(trigger, func) {
|
|
279 menu.addEventListener(trigger, function(p) { return func(p); });
|
|
280 });
|
|
281 menu.init();
|
|
282 rcmail.env.contextmenus[props.menu_name] = menu;
|
|
283 }
|
|
284 else {
|
|
285 var menu = rcmail.env.contextmenus[props.menu_name];
|
|
286 }
|
|
287
|
|
288 return menu;
|
|
289 }
|
|
290
|
|
291 function rcm_show_menu(e, obj, id, menu) {
|
|
292 // if contextmenus have been disabled then show browser context menu as normal
|
|
293 if (!rcmail.env.contextmenu)
|
|
294 return true;
|
|
295
|
|
296 e.preventDefault();
|
|
297 e.cancelBubble = true;
|
|
298 if (e.stopPropagation)
|
|
299 e.stopPropagation();
|
|
300
|
|
301 // hide any other open menus
|
|
302 for (var i = 0; i < rcmail.menu_stack.length; i++) {
|
|
303 rcmail.hide_menu(rcmail.menu_stack[i], e);
|
|
304 }
|
|
305
|
|
306 rcmail.env.context_menu_source_id = id;
|
|
307 menu.show(obj, e);
|
|
308 }
|
|
309
|
|
310 function rcm_hide_menu(e, sub_only) {
|
|
311 $.each($(sub_only ? '.rcmsubmenu' : 'div.contextmenu'), function() {
|
|
312 if ($(this).is(':visible')) {
|
|
313 $(this).hide();
|
|
314 rcmail.triggerEvent('menu-close', { name: $(this).attr('id'), props:{ menu: $(this).attr('id') }, originalEvent: e });
|
|
315 }
|
|
316 });
|
|
317
|
|
318 // close popup menus opened by the contextmenu
|
|
319 for (var i = rcmail.context_menu_popup_menus.length - 1; i >= 0; i--) {
|
|
320 rcmail.hide_menu(rcmail.context_menu_popup_menus[i], e);
|
|
321 rcmail.context_menu_popup_menus.pop();
|
|
322 }
|
|
323 }
|
|
324
|
|
325 function rcube_context_menu(p) {
|
|
326 this.menu_name = null;
|
|
327 this.menu_source = null;
|
|
328 this.list_object = rcmail.message_list;
|
|
329 this.source_class = 'contextRow';
|
|
330 this.mouseover_timeout = 400;
|
|
331
|
|
332 this.is_submenu = false;
|
|
333 this.parent_menu = this;
|
|
334 this.parent_object = null;
|
|
335 this.selected_object = null
|
|
336 this.container = null;
|
|
337 this.original_selection = new Array();
|
|
338 this.menu_selection = new Array();
|
|
339 this.submenus = new Array();
|
|
340 this.timers = new Array();
|
|
341
|
|
342 // overwrite default parameters
|
|
343 if (p && typeof p === 'object')
|
|
344 for (var n in p)
|
|
345 this[n] = p[n];
|
|
346
|
|
347 var ref = this;
|
|
348
|
|
349 this.init = function() {
|
|
350 if (!this.container) {
|
|
351 rcmail.triggerEvent('contextmenu_init', this);
|
|
352
|
|
353 this.container = $('<div id="rcm_'+ this.menu_name +'" style="display: none;"></div>');
|
|
354 this.container.addClass('contextmenu popupmenu');
|
|
355 this.container.addClass(this.is_submenu ? 'rcmsubmenu' : 'rcmmainmenu');
|
|
356
|
|
357 var rows = [], ul = $('<ul role="menu">'),
|
|
358 li = $('<li>'), link = $('<a>'), span = $('<span>');
|
|
359
|
|
360 ul.addClass('toolbarmenu iconized');
|
|
361 li.attr('role', 'menuitem');
|
|
362
|
|
363 link.attr('href', '#');
|
|
364 link.addClass('icon active');
|
|
365 link.attr('role', 'button');
|
|
366 link.attr('tabindex', '-1');
|
|
367 link.attr('aria-disabled', 'true');
|
|
368
|
|
369 span.addClass('icon');
|
|
370
|
|
371 // loop over possible menu elements and build settings object
|
|
372 sources = typeof this.menu_source == 'string' ? [this.menu_source] : this.menu_source;
|
|
373 this.menu_source = {}
|
|
374 $.each(sources, function(i) {
|
|
375 var source_elements;
|
|
376 if (typeof sources[i] == 'string') {
|
|
377 ref.menu_source[sources[i]] = {
|
|
378 'toggle': !$(sources[i]).is(':visible')
|
|
379 };
|
|
380 source_elements = $(sources[i]).children();
|
|
381 }
|
|
382 else {
|
|
383 ref.menu_source[i] = {
|
|
384 'toggle': false
|
|
385 };
|
|
386 source_elements = $(sources[i]);
|
|
387 }
|
|
388
|
|
389 ul.attr('aria-labelledby', $(sources[i]).attr('aria-labelledby'));
|
|
390
|
|
391 $.each(source_elements, function() {
|
|
392 var elem, command, args;
|
|
393
|
|
394 if ($(this).is('a')) {
|
|
395 elem = $(this).clone();
|
|
396 }
|
|
397 else if ($(this).is('span') && $(this).children().length == 2) {
|
|
398 elem = $(this).children(':first').clone();
|
|
399
|
|
400 if ($(this).children(':last').attr('onclick').match(rcmail.context_menu_popup_pattern)) {
|
|
401 $(elem).attr('onclick', $(this).children(':last').attr('onclick'));
|
|
402 }
|
|
403 }
|
|
404 else if ($(this).is('li') && $(this).children('a').length == 1) {
|
|
405 elem = $(this).children('a').clone();
|
|
406
|
|
407 if (!elem.attr('onclick') || !elem.attr('onclick').match(rcmail.context_menu_command_pattern))
|
|
408 return;
|
|
409 }
|
|
410 else if ($(this).parent().is('a')) {
|
|
411 elem = $(this).parent().clone();
|
|
412 }
|
|
413 else if (this.command && this.label) {
|
|
414 elem = $('<a>').attr('href', '#')
|
|
415 .attr('id', 'rcmjs')
|
|
416 .attr('onclick', "return rcmail.command('"+ this.command +"','"+ this.props +"',this,event)")
|
|
417 .addClass(this.classes)
|
|
418 .html(this.label);
|
|
419 }
|
|
420 else {
|
|
421 return;
|
|
422 }
|
|
423
|
|
424 // skip any element that does not look like a Roundcube button
|
|
425 if (!elem.attr('onclick')) {
|
|
426 return;
|
|
427 }
|
|
428
|
|
429 if (elem.attr('onclick').match(rcmail.context_menu_command_pattern)) {
|
|
430 command = RegExp.$1;
|
|
431 args = RegExp.$2;
|
|
432 }
|
|
433
|
|
434 // skip elements we don't need
|
|
435 if ($.inArray(rcmail.env.task + '-' + command, rcmail.context_menu_skip_commands) > -1 || elem.hasClass('rcm_ignore')) {
|
|
436 return;
|
|
437 }
|
|
438
|
|
439 var a = link.clone(), row = li.clone();
|
|
440
|
|
441 // add command name element
|
|
442 tmp = span.clone();
|
|
443 tmp.text($.trim(elem.text()).length > 0 ? $.trim(elem.text()) : elem.attr('title'));
|
|
444 tmp.addClass(elem.children('span').attr('class'));
|
|
445 a.append(tmp);
|
|
446 a.addClass(elem.attr('class'));
|
|
447 a.removeClass('button').removeClass('disabled');
|
|
448 a.addClass('rcm_elem_' + elem.attr('id'));
|
|
449
|
|
450 if (elem.attr('onclick').match(rcmail.context_menu_popup_pattern)) {
|
|
451 a.data('command', RegExp.$1);
|
|
452 a.append($('<span>').addClass('right-arrow'));
|
|
453 row.addClass('submenu');
|
|
454 a.click(function(e) {
|
|
455 if (!$(this).hasClass('active'))
|
|
456 return;
|
|
457
|
|
458 ref.submenu(a, e);
|
|
459 return false;
|
|
460 });
|
|
461
|
|
462 if (ref.mouseover_timeout > -1) {
|
|
463 a.mouseover(function(e) {
|
|
464 if (!$(this).hasClass('active'))
|
|
465 return;
|
|
466
|
|
467 ref.timers['submenu_show'] = window.setTimeout(function(a, e) {
|
|
468 ref.submenu(a, e);
|
|
469 }, ref.mouseover_timeout, a, e);
|
|
470 });
|
|
471
|
|
472 a.mouseout(function(e) {
|
|
473 if (!$(this).hasClass('active'))
|
|
474 return;
|
|
475
|
|
476 $(this).blur(); clearTimeout(ref.timers['submenu_show']);
|
|
477 });
|
|
478 }
|
|
479 }
|
|
480 else {
|
|
481 a.addClass('cmd_' + command);
|
|
482 a.data('command', command);
|
|
483 if (elem.attr('target'))
|
|
484 a.attr('target', elem.attr('target'));
|
|
485
|
|
486 a.click(function(e) {
|
|
487 if ($(this).parents('.rcmsubmenu').length == 0) {
|
|
488 rcm_hide_menu(e, true);
|
|
489 clearTimeout(ref.timers['submenu_hide']);
|
|
490 }
|
|
491
|
|
492 var cur_popups = rcmail.menu_stack.length;
|
|
493 var result;
|
|
494
|
|
495 var callback = ref.parent_menu.triggerEvent('beforecommand', {ref: ref, el: this, command: command, args: args});
|
|
496 if (!callback || !callback.abort) {
|
|
497 result = ref.parent_menu.triggerEvent('command', {ref: ref, el: this, command: command, args: args, evt: e});
|
|
498 }
|
|
499 else {
|
|
500 result = callback.result;
|
|
501 }
|
|
502
|
|
503 if (!callback || !callback.skipaftercommand)
|
|
504 ref.parent_menu.triggerEvent('aftercommand', {ref: ref, el: this, command: command, args: args});
|
|
505
|
|
506 if (rcmail.menu_stack.length > cur_popups) {
|
|
507 var popup_name = rcmail.menu_stack[rcmail.menu_stack.length - 1];
|
|
508 rcmail.context_menu_popup_menus.push(popup_name);
|
|
509
|
|
510 // make sure enabled commands match context menu message selection
|
|
511 $.each(rcmail.context_menu_popup_commands[popup_name], function(cmd, state) {
|
|
512 rcmail.enable_command(cmd, state);
|
|
513 });
|
|
514 }
|
|
515
|
|
516 // ensure menu is always hidden after action (for Safari)
|
|
517 ref.hide(e);
|
|
518
|
|
519 return result;
|
|
520 });
|
|
521
|
|
522 if (ref.mouseover_timeout > -1 && !ref.is_submenu) {
|
|
523 a.mouseover(function(e) {
|
|
524 ref.timers['submenu_hide'] = window.setTimeout(function(e) {
|
|
525 rcm_hide_menu(e, true);
|
|
526 }, ref.mouseover_timeout, e);
|
|
527 });
|
|
528
|
|
529 a.mouseout(function(e) { clearTimeout(ref.timers['submenu_hide']); });
|
|
530 }
|
|
531 }
|
|
532
|
|
533 row.append(a);
|
|
534 ref.parent_menu.triggerEvent('insertitem', {item: row});
|
|
535 rows.push(row);
|
|
536 });
|
|
537 });
|
|
538
|
|
539 ul.append(rows).appendTo(this.container);
|
|
540 this.parent_menu.triggerEvent('init', {ref: this});
|
|
541 this.container.appendTo($('body'));
|
|
542 }
|
|
543 };
|
|
544
|
|
545 this.show = function(obj, e) {
|
|
546 if (obj) {
|
|
547 this.hide(e);
|
|
548 }
|
|
549
|
|
550 var callback = this.parent_menu.triggerEvent('beforeactivate', {ref: this, source: obj});
|
|
551 if (!callback || !callback.abort) {
|
|
552 if (obj) {
|
|
553 $(obj).addClass(this.source_class);
|
|
554 }
|
|
555
|
|
556 $.each(ref.menu_source, function(id, props) {
|
|
557 if (props.toggle) {
|
|
558 $(id).parent().show();
|
|
559 }
|
|
560 });
|
|
561
|
|
562 $.each(this.container.find('a'), function() {
|
|
563 if ($(this).hasClass('rcm_active')) {
|
|
564 $(this).addClass('active');
|
|
565 }
|
|
566 else if (btn = $(this).attr('class').match(/rcm_elem_([a-z0-9]+)/)) {
|
|
567 $(this).parent('li')[(btn[1] == 'rcmjs' || $('#' + btn[1]).is(':visible')) ? 'show' : 'hide']();
|
|
568 $(this).removeClass('active').removeClass('disabled');
|
|
569
|
|
570 var enabled = false;
|
|
571 if (!rcm_check_button_state(btn[1], false) && (!ref.is_submenu || rcm_check_button_state(btn[1], true))) {
|
|
572 enabled = true;
|
|
573 }
|
|
574
|
|
575 var ret = ref.parent_menu.triggerEvent('activate', {el: this, btn: btn[1], source: obj, command: $(this).data('command'), enabled: enabled});
|
|
576 if (ret === true) {
|
|
577 $(this).addClass('active').removeClass('disabled');
|
|
578 }
|
|
579 else if (ret === false) {
|
|
580 $(this).addClass('disabled').removeClass('active');
|
|
581 }
|
|
582 }
|
|
583 });
|
|
584
|
|
585 $.each(ref.menu_source, function(id, props) {
|
|
586 if (props.toggle) {
|
|
587 $(id).parent().hide();
|
|
588 }
|
|
589 });
|
|
590
|
|
591 this.parent_menu.triggerEvent('afteractivate', {ref: this, source: obj});
|
|
592 }
|
|
593
|
|
594 // position menu on the screen
|
|
595 if (this.is_submenu) {
|
|
596 rcmail.element_position(this.container, this.parent_object);
|
|
597 }
|
|
598 else {
|
|
599 this.position(e, this.container);
|
|
600 }
|
|
601
|
|
602 if (!callback || callback.show !== false) {
|
|
603 this.selected_object = obj;
|
|
604 this.container.show();
|
|
605 rcmail.triggerEvent('menu-open', { name: this.container.attr('id'), props:{ menu: this.container.attr('id') }, originalEvent: e });
|
|
606 }
|
|
607 };
|
|
608
|
|
609 this.hide = function(e) {
|
|
610 // use window.event when e is not defined (legacy support for IE8)
|
|
611 var target = e ? e.target : window.event.srcElement;
|
|
612
|
|
613 if ($('div.contextmenu').is(':visible') && (rcmail.context_menu_popup_menus.length == 0 || $(target).parents('div.contextmenu').length == 0)) {
|
|
614 this.selected_object = null;
|
|
615 $('.' + this.source_class).removeClass(this.source_class);
|
|
616 rcm_hide_menu(e);
|
|
617
|
|
618 for (var i in rcmail.context_menu_commands) {
|
|
619 if (!rcmail.context_menu_commands[i]) {
|
|
620 rcmail.enable_command(i, false);
|
|
621 }
|
|
622 }
|
|
623
|
|
624 rcmail.context_menu_commands = new Array();
|
|
625 }
|
|
626 };
|
|
627
|
|
628 this.submenu = function(link, e) {
|
|
629 // use window.event when e is not defined (legacy support for IE8)
|
|
630 if (!e)
|
|
631 e = window.event;
|
|
632
|
|
633 if (e) {
|
|
634 e.cancelBubble = true;
|
|
635 if (e.stopPropagation)
|
|
636 e.stopPropagation();
|
|
637 }
|
|
638
|
|
639 rcm_hide_menu(e, true);
|
|
640
|
|
641 var id = rcmail.gui_containers[$(link).data('command')] ? rcmail.gui_containers[$(link).data('command')].attr('id') : $(link).data('command');
|
|
642 if (!this.submenus[id]) {
|
|
643 var elem = !$('#' + id).is('ul') ? '#' + id + ' ul' : '#' + id; // check if the container returned is a ul else there should be one directly beneath it
|
|
644 this.submenus[id] = new rcube_context_menu({'menu_name': id, 'menu_source': elem, 'parent_menu': this, 'parent_object': link, 'is_submenu': true, 'list_object': this.list_object});
|
|
645 this.submenus[id].init();
|
|
646 }
|
|
647
|
|
648 this.submenus[id].show(null, e);
|
|
649 };
|
|
650
|
|
651 this.position = function(e, menu) {
|
|
652 // temporarily show element to calculate its size
|
|
653 menu.css({left: '-1000px', top: '-1000px'}).show();
|
|
654
|
|
655 var win = $(window),
|
|
656 win_height = win.height(),
|
|
657 elem_height = $(menu).height(),
|
|
658 elem_width = $(menu).width(),
|
|
659 top = e.pageY,
|
|
660 left = e.pageX;
|
|
661
|
|
662 if (top + elem_height > win_height) {
|
|
663 top -= elem_height;
|
|
664
|
|
665 if (top < 0)
|
|
666 top = Math.max(0, (win_height - elem_height) / 2);
|
|
667 }
|
|
668
|
|
669 if (left + elem_width > win.width())
|
|
670 left -= elem_width;
|
|
671
|
|
672 menu.hide();
|
|
673 menu.css({left: left + 'px', top: top + 'px'});
|
|
674 };
|
|
675
|
|
676 this.list_selection = function(show, prev_sel) {
|
|
677 // make the system think no preview pane exists while we do some fake message selects
|
|
678 // to enable/disable relevent commands for current selection
|
|
679 var prev_contentframe = rcmail.env.contentframe;
|
|
680 rcmail.env.contentframe = null;
|
|
681
|
|
682 if (show) {
|
|
683 if (this.list_object.selection.length == 0 || !this.list_object.in_selection(rcmail.env.context_menu_source_id)) {
|
|
684 prev_sel = this.list_object.get_selection();
|
|
685 this.list_object.highlight_row(rcmail.env.context_menu_source_id, true);
|
|
686
|
|
687 for (var i in prev_sel)
|
|
688 this.list_object.highlight_row(prev_sel[i], true);
|
|
689
|
|
690 this.list_object.triggerEvent('select');
|
|
691 }
|
|
692 else {
|
|
693 // trigger a select event to update active commands
|
|
694 // use case: select multiple message, open contextmenu; open contextmenu on a message not in selection; open contextmenu on selection
|
|
695 this.list_object.triggerEvent('select');
|
|
696 }
|
|
697 }
|
|
698 else if (prev_sel) {
|
|
699 for (var i in prev_sel)
|
|
700 this.list_object.highlight_row(prev_sel[i], true);
|
|
701
|
|
702 this.list_object.highlight_row(rcmail.env.context_menu_source_id, true);
|
|
703 this.list_object.triggerEvent('select');
|
|
704 }
|
|
705
|
|
706 rcmail.env.contentframe = prev_contentframe;
|
|
707
|
|
708 return prev_sel;
|
|
709 };
|
|
710
|
|
711 this.addEventListener = rcube_event_engine.prototype.addEventListener;
|
|
712 this.removeEventListener = rcube_event_engine.prototype.removeEventListener;
|
|
713 this.triggerEvent = rcube_event_engine.prototype.triggerEvent;
|
|
714 };
|
|
715
|
|
716 function rcm_override_mailbox_command(menu, props, before) {
|
|
717 if ($('div.contextmenu').is(':visible') && $.inArray(props.action, rcmail.context_menu_overload_commands) >= 0) {
|
|
718 if (before) {
|
|
719 rcmail.env.context_menu_prev_display_next = rcmail.env.display_next;
|
|
720 if (!(menu.list_object.selection.length == 1 && menu.list_object.in_selection(rcmail.env.context_menu_source_id)))
|
|
721 rcmail.env.display_next = false;
|
|
722
|
|
723 rcmail.env.context_menu_prev_sel = menu.list_selection(true);
|
|
724 }
|
|
725 else if (rcmail.env.context_menu_prev_sel) {
|
|
726 menu.list_selection(false, rcmail.env.context_menu_prev_sel);
|
|
727 rcmail.env.display_next = rcmail.env.context_menu_prev_display_next;
|
|
728 }
|
|
729 }
|
|
730 }
|
|
731
|
|
732 function rcm_check_button_state(btn, active) {
|
|
733 var classes = active ? rcmail.context_menu_button_active_class : rcmail.context_menu_button_disabled_class;
|
|
734 var found = false;
|
|
735
|
|
736 $.each(classes, function(i) {
|
|
737 if ($('#' + btn).hasClass(classes[i])) {
|
|
738 found = true;
|
|
739
|
|
740 // stop processing
|
|
741 return false;
|
|
742 }
|
|
743 });
|
|
744
|
|
745 return found;
|
|
746 }
|
|
747
|
|
748 function rcm_addressbook_selector(event, command, callback) {
|
|
749 var container = rcmail.rcm_addressbook_selector_element;
|
|
750
|
|
751 if (!container) {
|
|
752 var rows = [],
|
|
753 ul = $('<ul class="toolbarmenu">');
|
|
754
|
|
755 container = $('<div id="addressbook-selector" class="popupmenu"></div>');
|
|
756
|
|
757 // loop over address books
|
|
758 $.each(rcmail.env.address_sources, function() {
|
|
759 if (!this.readonly) {
|
|
760 rows.push(rcm_addressbook_selector_item(this));
|
|
761
|
|
762 if (this.groups) {
|
|
763 var ref = this;
|
|
764 $.each(rcmail.env.contactgroups, function() {
|
|
765 rows.push(rcm_addressbook_selector_item(this, ref.id));
|
|
766 });
|
|
767 }
|
|
768 }
|
|
769 });
|
|
770
|
|
771 ul.append(rows).appendTo(container);
|
|
772
|
|
773 // temporarily show element to calculate its size
|
|
774 container.css({left: '-1000px', top: '-1000px'})
|
|
775 .appendTo($('body')).show();
|
|
776
|
|
777 // set max-height if the list is long
|
|
778 if (rows.length > 10)
|
|
779 container.css('max-height', $('li', container)[0].offsetHeight * 10 + 9);
|
|
780
|
|
781 // register delegate event handler for folder item clicks
|
|
782 container.on('click', 'a.active', function(e) {
|
|
783 container.data('callback')(this, container.data('command'), e);
|
|
784 return false;
|
|
785 });
|
|
786
|
|
787 rcmail.rcm_addressbook_selector_element = container;
|
|
788 }
|
|
789
|
|
790 container.data('command', command);
|
|
791 container.data('callback', callback);
|
|
792
|
|
793 // customize menu for move or copy
|
|
794 container.find('li').show();
|
|
795
|
|
796 // search result may contain contacts from many sources, but if there is only one...
|
|
797 var source = rcmail.env.source;
|
|
798 if (source == '' && rcmail.env.selection_sources.length == 1)
|
|
799 source = rcmail.env.selection_sources[0];
|
|
800
|
|
801 // hide currently open address book from menu
|
|
802 if (source) {
|
|
803 $.each(container.find('a'), function() {
|
|
804 if (($(this).data('source') && $(this).data('source') == source) || $(this).data('id') == source)
|
|
805 $(this).parent('li').hide();
|
|
806 });
|
|
807 }
|
|
808
|
|
809 // position menu on the screen
|
|
810 rcmail.show_menu('addressbook-selector', true, event);
|
|
811 }
|
|
812
|
|
813 function rcm_group_selector(event, command, callback) {
|
|
814 var container = rcmail.rcm_addressgroup_selector_element;
|
|
815
|
|
816 if (!container) {
|
|
817 var rows = [],
|
|
818 ul = $('<ul class="toolbarmenu">');
|
|
819
|
|
820 container = $('<div id="addressgroup-selector" class="popupmenu"></div>');
|
|
821
|
|
822 // loop over address books
|
|
823 $.each(rcmail.env.address_sources, function() {
|
|
824 if (this.id === rcmail.env.source) {
|
|
825 var ref = this;
|
|
826 $.each(rcmail.env.contactgroups, function() {
|
|
827 rows.push(rcm_addressbook_selector_item(this, ref.id));
|
|
828 });
|
|
829 }
|
|
830 });
|
|
831
|
|
832 ul.append(rows).appendTo(container);
|
|
833
|
|
834 // remove indent added by rcm_addressbook_selector_item()
|
|
835 $(ul).find('a').removeAttr('style');
|
|
836
|
|
837 // temporarily show element to calculate its size
|
|
838 container.css({left: '-1000px', top: '-1000px'})
|
|
839 .appendTo($('body')).show();
|
|
840
|
|
841 // set max-height if the list is long
|
|
842 if (rows.length > 10)
|
|
843 container.css('max-height', $('li', container)[0].offsetHeight * 10 + 9);
|
|
844
|
|
845 // register delegate event handler for folder item clicks
|
|
846 container.on('click', 'a.active', {cmd: command}, function(e) {
|
|
847 container.data('callback')(this, e);
|
|
848 return false;
|
|
849 });
|
|
850
|
|
851 rcmail.rcm_addressgroup_selector_element = container;
|
|
852 }
|
|
853
|
|
854 container.data('callback', callback);
|
|
855
|
|
856 // customize menu for move or copy
|
|
857 container.find('li').show();
|
|
858
|
|
859 // hide currently open group from menu
|
|
860 if (rcmail.env.group) {
|
|
861 $.each(container.find('a'), function() {
|
|
862 if ($(this).data('id') == rcmail.env.group)
|
|
863 $(this).parent('li').hide();
|
|
864 });
|
|
865 }
|
|
866
|
|
867 // position menu on the screen
|
|
868 rcmail.show_menu('addressgroup-selector', true, event);
|
|
869 }
|
|
870
|
|
871 function rcm_addressbook_selector_item(obj, abook_id) {
|
|
872 if (abook_id && abook_id === obj.source || !abook_id) {
|
|
873 var a = $('<a>').attr('href', '#').addClass('icon'),
|
|
874 row = $('<li>');
|
|
875
|
|
876 if (obj.type == 'group') {
|
|
877 a.addClass('active contactgroup')
|
|
878 a.data('source', obj.source);
|
|
879 a.data('id', obj.id);
|
|
880 a.css('padding-left', '16px');
|
|
881 }
|
|
882 else {
|
|
883 a.addClass('addressbook active').data('id', obj.id);
|
|
884 }
|
|
885
|
|
886 // add address book name element
|
|
887 a.append($('<span>').text(obj.name));
|
|
888
|
|
889 return row.append(a);
|
|
890 }
|
|
891 }
|
|
892
|
|
893 $(document).ready(function() {
|
|
894 if (window.rcmail) {
|
|
895 rcmail.env.contextmenus = {};
|
|
896
|
|
897 rcmail.addEventListener('init', function() {
|
|
898 // no need to reattach events inside iframe
|
|
899 if (rcmail.is_framed())
|
|
900 return;
|
|
901
|
|
902 var body_mouseup = function(e) { $.each(rcmail.env.contextmenus, function() { this.hide(e); }); };
|
|
903 $(document.body).on('click contextmenu', body_mouseup);
|
|
904
|
|
905 // Hide menu after clicks in iframes (eg. preview pane)
|
|
906 $('iframe').on('load', function(e) {
|
|
907 try { $(this.contentDocument || this.contentWindow).on('mouseup', body_mouseup) }
|
|
908 catch (e) { /* catch possible "Permission denied" error in IE */ }
|
|
909 })
|
|
910 .contents().on('mouseup', body_mouseup);
|
|
911 });
|
|
912
|
|
913 if ((rcmail.env.task == 'mail' || rcmail.env.task == 'addressbook') && rcmail.env.action == '') {
|
|
914 // special handeling for move/copy functions (folder/address book selector)
|
|
915 rcmail.addEventListener('actionbefore', function(props) {
|
|
916 var menu = rcmail.env.task == 'addressbook' ? rcmail.env.contextmenus['contactlist'] : rcmail.env.contextmenus['messagelist'];
|
|
917 rcm_override_mailbox_command(menu, props, true);
|
|
918 });
|
|
919
|
|
920 rcmail.addEventListener('actionafter', function(props) {
|
|
921 var menu = rcmail.env.task == 'addressbook' ? rcmail.env.contextmenus['contactlist'] : rcmail.env.contextmenus['messagelist'];
|
|
922 rcm_override_mailbox_command(menu, props, false);
|
|
923 });
|
|
924 }
|
|
925
|
|
926 if (rcmail.env.task == 'mail' && rcmail.env.action == '') {
|
|
927 rcmail.register_command('plugin.contextmenu.collapseall', function(props, obj) {
|
|
928 $("#mailboxlist div.expanded").each(function() { $(this).click(); });
|
|
929 }, false);
|
|
930
|
|
931 rcmail.register_command('plugin.contextmenu.expandall', function(props, obj) {
|
|
932 $("#mailboxlist div.collapsed").each(function() { $(this).click(); });
|
|
933 }, false);
|
|
934
|
|
935 rcmail.register_command('plugin.contextmenu.openfolder', function(props, obj) {
|
|
936 var button_id = rcmail.buttons['plugin.contextmenu.openfolder'][0].id;
|
|
937
|
|
938 rcube_find_object(button_id).href = '?_task=mail&_mbox='+urlencode(rcmail.env.context_menu_source_id);
|
|
939 rcmail.sourcewin = window.open(rcube_find_object(button_id).href);
|
|
940 if (rcmail.sourcewin)
|
|
941 window.setTimeout(function() { rcmail.sourcewin.focus(); }, 20);
|
|
942
|
|
943 rcube_find_object(button_id).href = '#';
|
|
944 }, false);
|
|
945 }
|
|
946
|
|
947 if (rcmail.env.task == 'addressbook' && rcmail.env.action == '') {
|
|
948 // address book selector
|
|
949 rcmail.addEventListener('actionbefore', function(props) {
|
|
950 if ((props.action == 'move' || props.action == 'copy') && props.props == '') {
|
|
951 rcm_addressbook_selector(props.originalEvent, props.action, function(obj, cmd, evt) {
|
|
952 // search result may contain contacts from many sources, but if there is only one...
|
|
953 var source = rcmail.env.source;
|
|
954 if (source == '' && rcmail.env.selection_sources.length == 1)
|
|
955 source = rcmail.env.selection_sources[0];
|
|
956
|
|
957 if ($(obj).data('source')) {
|
|
958 rcmail.command(cmd, rcmail.env.contactgroups['G' + $(obj).data('source') + $(obj).data('id')], evt);
|
|
959 }
|
|
960 else {
|
|
961 rcmail.command(cmd, rcmail.env.address_sources[$(obj).data('id')], evt);
|
|
962 }
|
|
963 });
|
|
964
|
|
965 return false;
|
|
966 }
|
|
967 });
|
|
968
|
|
969 // address book group selector
|
|
970 rcmail.register_command('plugin.contextmenu.assigngroup', function(props, obj, event) {
|
|
971 rcm_group_selector(event, props, function(obj, evt) {
|
|
972 // search result may contain contacts from many sources, but if there is only one...
|
|
973 rcm_override_mailbox_command(rcmail.env.contextmenus['contactlist'], { action: 'copy' } , true);
|
|
974 rcmail.group_member_change('add', rcmail.contact_list.get_selection().join(','), rcmail.env.source, $(obj).data('id'));
|
|
975 rcm_override_mailbox_command(rcmail.env.contextmenus['contactlist'], { action: 'copy' } , false);
|
|
976 });
|
|
977 }, false);
|
|
978
|
|
979 // reset address book selector when groups change
|
|
980 rcmail.addEventListener('group_insert', function() { $("#addressbook-selector").remove(); $("#addressgroup-selector").remove(); rcmail.rcm_addressbook_selector_element = undefined; rcmail.rcm_addressgroup_selector_element = undefined; } );
|
|
981 rcmail.addEventListener('group_update', function() { $("#addressbook-selector").remove(); $("#addressgroup-selector").remove(); rcmail.rcm_addressbook_selector_element = undefined; rcmail.rcm_addressgroup_selector_element = undefined; } );
|
|
982 rcmail.addEventListener('group_delete', function() { $("#addressbook-selector").remove(); $("#addressgroup-selector").remove(); rcmail.rcm_addressbook_selector_element = undefined; rcmail.rcm_addressgroup_selector_element = undefined; } );
|
|
983 }
|
|
984
|
|
985 // special event listeners for intreacting with plugins which open popup menus (eg: zipdownload)
|
|
986 rcmail.addEventListener('menu-open', function(p) {
|
|
987 // check for popupmenus that arent part of contextmenu
|
|
988 if ($('div.contextmenu').is(':visible') && p.name.indexOf('rcm_') != 0) {
|
|
989 rcmail.context_menu_popup_commands[p.name] = {};
|
|
990 $('#' + p.name).find('a').each(function() {
|
|
991 if ($(this).attr('onclick') && $(this).attr('onclick').match(rcmail.context_menu_command_pattern)) {
|
|
992 var cmd = RegExp.$1;
|
|
993 rcmail.context_menu_popup_commands[p.name][cmd] = rcmail.commands[cmd];
|
|
994 }
|
|
995 });
|
|
996 }
|
|
997 });
|
|
998
|
|
999 rcmail.addEventListener('menu-close', function(p) {
|
|
1000 // check required args are present, other plugins trigger this event too
|
|
1001 if (!p.originalEvent) {
|
|
1002 return;
|
|
1003 }
|
|
1004
|
|
1005 // check for popupmenus that arent part of contextmenu
|
|
1006 var e = p.originalEvent.currentTarget ? p.originalEvent.currentTarget : p.originalEvent.srcElement;
|
|
1007 if ($('div.contextmenu').is(':visible') && p.name.indexOf('rcm_') != 0 && $(e).attr('class').indexOf('rcm_elem_') == -1) {
|
|
1008 rcm_hide_menu(p.originalEvent);
|
|
1009 }
|
|
1010 });
|
|
1011
|
|
1012 rcmail.addEventListener('get_single_uid', function() {
|
|
1013 if ($('#rcm_messagelist').is(':visible') && rcmail.env.contextmenus['messagelist'].menu_selection.length == 1) {
|
|
1014 return rcmail.env.contextmenus['messagelist'].menu_selection[0];
|
|
1015 }
|
|
1016 });
|
|
1017
|
|
1018 rcmail.addEventListener('get_single_cid', function() {
|
|
1019 if ($('#rcm_contactlist').is(':visible') && rcmail.env.contextmenus['contactlist'].menu_selection.length == 1) {
|
|
1020 return rcmail.env.contextmenus['contactlist'].menu_selection[0];
|
|
1021 }
|
|
1022 else if ($('#rcm_composeto').is(':visible') && rcmail.env.contextmenus['composeto'].menu_selection.length == 1) {
|
|
1023 return rcmail.env.contextmenus['composeto'].menu_selection[0];
|
|
1024 }
|
|
1025 });
|
|
1026 }
|
|
1027 }); |