context_menu.js
236 lines
| 7.0 KiB
| application/javascript
|
JavascriptLexer
|
r8770 | /* Redmine - project management software | ||
Copyright (C) 2006-2012 Jean-Philippe Lang */ | ||||
|
r1116 | |||
var observingContextMenuClick; | ||||
|
r859 | ContextMenu = Class.create(); | ||
ContextMenu.prototype = { | ||||
|
r8769 | initialize: function (url) { | ||
this.url = url; | ||||
this.createMenu(); | ||||
|
r1116 | |||
|
r8769 | if (!observingContextMenuClick) { | ||
Event.observe(document, 'click', this.Click.bindAsEventListener(this)); | ||||
Event.observe(document, 'contextmenu', this.RightClick.bindAsEventListener(this)); | ||||
observingContextMenuClick = true; | ||||
} | ||||
|
r8770 | |||
|
r8769 | this.unselectAll(); | ||
this.lastSelected = null; | ||||
}, | ||||
|
r8770 | |||
|
r8769 | RightClick: function(e) { | ||
this.hideMenu(); | ||||
// do not show the context menu on links | ||||
if (Event.element(e).tagName == 'A') { return; } | ||||
var tr = Event.findElement(e, 'tr'); | ||||
if (tr == document || tr == undefined || !tr.hasClassName('hascontextmenu')) { return; } | ||||
Event.stop(e); | ||||
if (!this.isSelected(tr)) { | ||||
this.unselectAll(); | ||||
this.addSelection(tr); | ||||
this.lastSelected = tr; | ||||
} | ||||
this.showMenu(e); | ||||
}, | ||||
|
r1116 | |||
Click: function(e) { | ||||
|
r8769 | if (Event.element(e).tagName == 'A' && Event.element(e).hasClassName('submenu')) { | ||
Event.stop(e) | ||||
return; | ||||
} | ||||
this.hideMenu(); | ||||
if (Event.element(e).tagName == 'A' || Event.element(e).tagName == 'IMG') { return; } | ||||
|
r8770 | if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) { | ||
|
r1116 | var tr = Event.findElement(e, 'tr'); | ||
|
r2176 | if (tr!=null && tr!=document && tr.hasClassName('hascontextmenu')) { | ||
|
r1116 | // a row was clicked, check if the click was on checkbox | ||
var box = Event.findElement(e, 'input'); | ||||
|
r1580 | if (box!=document && box!=undefined) { | ||
|
r1116 | // a checkbox may be clicked | ||
if (box.checked) { | ||||
tr.addClassName('context-menu-selection'); | ||||
} else { | ||||
tr.removeClassName('context-menu-selection'); | ||||
} | ||||
} else { | ||||
|
r5097 | if (e.ctrlKey || e.metaKey) { | ||
|
r1116 | this.toggleSelection(tr); | ||
} else if (e.shiftKey) { | ||||
if (this.lastSelected != null) { | ||||
var toggling = false; | ||||
var rows = $$('.hascontextmenu'); | ||||
for (i=0; i<rows.length; i++) { | ||||
if (toggling || rows[i]==tr) { | ||||
this.addSelection(rows[i]); | ||||
} | ||||
if (rows[i]==tr || rows[i]==this.lastSelected) { | ||||
toggling = !toggling; | ||||
} | ||||
} | ||||
} else { | ||||
this.addSelection(tr); | ||||
} | ||||
} else { | ||||
this.unselectAll(); | ||||
this.addSelection(tr); | ||||
} | ||||
this.lastSelected = tr; | ||||
} | ||||
} else { | ||||
// click is outside the rows | ||||
var t = Event.findElement(e, 'a'); | ||||
|
r3430 | if (t == document || t == undefined) { | ||
this.unselectAll(); | ||||
} else { | ||||
if (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu')) { | ||||
Event.stop(e); | ||||
} | ||||
|
r1116 | } | ||
} | ||||
} | ||||
}, | ||||
|
r8770 | |||
|
r3428 | createMenu: function() { | ||
if (!$('context-menu')) { | ||||
var menu = document.createElement("div"); | ||||
menu.setAttribute("id", "context-menu"); | ||||
menu.setAttribute("style", "display:none;"); | ||||
document.getElementById("content").appendChild(menu); | ||||
} | ||||
}, | ||||
|
r8770 | |||
|
r1116 | showMenu: function(e) { | ||
|
r1308 | var mouse_x = Event.pointerX(e); | ||
var mouse_y = Event.pointerY(e); | ||||
var render_x = mouse_x; | ||||
var render_y = mouse_y; | ||||
var dims; | ||||
var menu_width; | ||||
var menu_height; | ||||
var window_width; | ||||
var window_height; | ||||
var max_width; | ||||
var max_height; | ||||
$('context-menu').style['left'] = (render_x + 'px'); | ||||
|
r8770 | $('context-menu').style['top'] = (render_y + 'px'); | ||
|
r1308 | Element.update('context-menu', ''); | ||
|
r8770 | new Ajax.Updater({success:'context-menu'}, this.url, | ||
|
r1116 | {asynchronous:true, | ||
|
r4390 | method: 'get', | ||
|
r1116 | evalScripts:true, | ||
parameters:Form.serialize(Event.findElement(e, 'form')), | ||||
onComplete:function(request){ | ||||
|
r8769 | dims = $('context-menu').getDimensions(); | ||
menu_width = dims.width; | ||||
menu_height = dims.height; | ||||
max_width = mouse_x + 2*menu_width; | ||||
max_height = mouse_y + menu_height; | ||||
|
r8770 | |||
|
r8769 | var ws = window_size(); | ||
window_width = ws.width; | ||||
window_height = ws.height; | ||||
|
r8770 | |||
|
r8769 | /* display the menu above and/or to the left of the click if needed */ | ||
if (max_width > window_width) { | ||||
render_x -= menu_width; | ||||
$('context-menu').addClassName('reverse-x'); | ||||
} else { | ||||
$('context-menu').removeClassName('reverse-x'); | ||||
} | ||||
if (max_height > window_height) { | ||||
render_y -= menu_height; | ||||
$('context-menu').addClassName('reverse-y'); | ||||
} else { | ||||
$('context-menu').removeClassName('reverse-y'); | ||||
} | ||||
if (render_x <= 0) render_x = 1; | ||||
if (render_y <= 0) render_y = 1; | ||||
$('context-menu').style['left'] = (render_x + 'px'); | ||||
$('context-menu').style['top'] = (render_y + 'px'); | ||||
|
r8770 | |||
|
r1116 | Effect.Appear('context-menu', {duration: 0.20}); | ||
if (window.parseStylesheets) { window.parseStylesheets(); } // IE | ||||
}}) | ||||
}, | ||||
|
r8770 | |||
|
r1116 | hideMenu: function() { | ||
Element.hide('context-menu'); | ||||
}, | ||||
|
r8770 | |||
|
r1116 | addSelection: function(tr) { | ||
tr.addClassName('context-menu-selection'); | ||||
this.checkSelectionBox(tr, true); | ||||
|
r3429 | this.clearDocumentSelection(); | ||
|
r1116 | }, | ||
|
r8770 | |||
|
r1116 | toggleSelection: function(tr) { | ||
if (this.isSelected(tr)) { | ||||
this.removeSelection(tr); | ||||
} else { | ||||
this.addSelection(tr); | ||||
} | ||||
}, | ||||
|
r8770 | |||
|
r1116 | removeSelection: function(tr) { | ||
tr.removeClassName('context-menu-selection'); | ||||
this.checkSelectionBox(tr, false); | ||||
}, | ||||
|
r8770 | |||
|
r1116 | unselectAll: function() { | ||
var rows = $$('.hascontextmenu'); | ||||
for (i=0; i<rows.length; i++) { | ||||
this.removeSelection(rows[i]); | ||||
} | ||||
}, | ||||
|
r8770 | |||
|
r1116 | checkSelectionBox: function(tr, checked) { | ||
|
r8769 | var inputs = Element.getElementsBySelector(tr, 'input'); | ||
if (inputs.length > 0) { inputs[0].checked = checked; } | ||||
|
r1116 | }, | ||
|
r8770 | |||
|
r1116 | isSelected: function(tr) { | ||
return Element.hasClassName(tr, 'context-menu-selection'); | ||||
|
r3429 | }, | ||
|
r8770 | |||
|
r3429 | clearDocumentSelection: function() { | ||
if (document.selection) { | ||||
document.selection.clear(); // IE | ||||
} else { | ||||
window.getSelection().removeAllRanges(); | ||||
} | ||||
|
r1116 | } | ||
} | ||||
|
r859 | |||
|
r1116 | function toggleIssuesSelection(el) { | ||
|
r8769 | var boxes = el.getElementsBySelector('input[type=checkbox]'); | ||
var all_checked = true; | ||||
for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } | ||||
for (i = 0; i < boxes.length; i++) { | ||||
if (all_checked) { | ||||
boxes[i].checked = false; | ||||
boxes[i].up('tr').removeClassName('context-menu-selection'); | ||||
} else if (boxes[i].checked == false) { | ||||
boxes[i].checked = true; | ||||
boxes[i].up('tr').addClassName('context-menu-selection'); | ||||
} | ||||
} | ||||
|
r859 | } | ||
|
r1308 | |||
function window_size() { | ||||
|
r8769 | var w; | ||
var h; | ||||
if (window.innerWidth) { | ||||
w = window.innerWidth; | ||||
h = window.innerHeight; | ||||
} else if (document.documentElement) { | ||||
w = document.documentElement.clientWidth; | ||||
h = document.documentElement.clientHeight; | ||||
} else { | ||||
w = document.body.clientWidth; | ||||
h = document.body.clientHeight; | ||||
} | ||||
return {width: w, height: h}; | ||||
|
r1308 | } | ||