Mercurial > hg > rc1
comparison plugins/contextmenu/contextmenu.js @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:50:29 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e000243b222 |
---|---|
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 }); |