;]
[askyou.git] / public / javascripts / context_menu.js
blobdc18e0af1ec2f75de9dceefa4b2f5650b48f620d
1 /* redMine - project management software
2    Copyright (C) 2006-2008  Jean-Philippe Lang */
4 var observingContextMenuClick;
6 ContextMenu = Class.create();
7 ContextMenu.prototype = {
8         initialize: function (url) {
9         this.url = url;
10         this.createMenu();
12         if (!observingContextMenuClick) {
13                 Event.observe(document, 'click', this.Click.bindAsEventListener(this));
14                 Event.observe(document, (window.opera ? 'click' : 'contextmenu'), this.RightClick.bindAsEventListener(this));
15                 observingContextMenuClick = true;
16         }
17         
18         this.unselectAll();
19         this.lastSelected = null;
20         },
21   
22         RightClick: function(e) {
23                 this.hideMenu();
24                 // do not show the context menu on links
25                 if (Event.element(e).tagName == 'A') { return; }
26                 // right-click simulated by Alt+Click with Opera
27                 if (window.opera && !e.altKey) { return; }
28                 var tr = Event.findElement(e, 'tr');
29                 if (tr == document || tr == undefined  || !tr.hasClassName('hascontextmenu')) { return; }
30                 Event.stop(e);
31                 if (!this.isSelected(tr)) {
32                         this.unselectAll();
33                         this.addSelection(tr);
34                         this.lastSelected = tr;
35                 }
36                 this.showMenu(e);
37         },
39   Click: function(e) {
40         this.hideMenu();
41         if (Event.element(e).tagName == 'A') { return; }
42     if (window.opera && e.altKey) {     return; }
43     if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) {      
44       var tr = Event.findElement(e, 'tr');
45       if (tr!=null && tr!=document && tr.hasClassName('hascontextmenu')) {
46         // a row was clicked, check if the click was on checkbox
47         var box = Event.findElement(e, 'input');
48         if (box!=document && box!=undefined) {
49           // a checkbox may be clicked
50           if (box.checked) {
51             tr.addClassName('context-menu-selection');
52           } else {
53             tr.removeClassName('context-menu-selection');
54           }
55         } else {
56           if (e.ctrlKey) {
57             this.toggleSelection(tr);
58           } else if (e.shiftKey) {
59             if (this.lastSelected != null) {
60               var toggling = false;
61               var rows = $$('.hascontextmenu');
62               for (i=0; i<rows.length; i++) {
63                 if (toggling || rows[i]==tr) {
64                   this.addSelection(rows[i]);
65                 }
66                 if (rows[i]==tr || rows[i]==this.lastSelected) {
67                   toggling = !toggling;
68                 }
69               }
70             } else {
71               this.addSelection(tr);
72             }
73           } else {
74             this.unselectAll();
75             this.addSelection(tr);
76           }
77           this.lastSelected = tr;
78         }
79       } else {
80         // click is outside the rows
81         var t = Event.findElement(e, 'a');
82         if (t == document || t == undefined) {
83           this.unselectAll();
84         } else {
85           if (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu')) {
86             Event.stop(e);
87           }
88         }
89       }
90     }
91     else{
92       this.RightClick(e);
93     }
94   },
95   
96   createMenu: function() {
97     if (!$('context-menu')) {
98       var menu = document.createElement("div");
99       menu.setAttribute("id", "context-menu");
100       menu.setAttribute("style", "display:none;");
101       document.getElementById("content").appendChild(menu);
102     }
103   },
104   
105   showMenu: function(e) {
106     var mouse_x = Event.pointerX(e);
107     var mouse_y = Event.pointerY(e);
108     var render_x = mouse_x;
109     var render_y = mouse_y;
110     var dims;
111     var menu_width;
112     var menu_height;
113     var window_width;
114     var window_height;
115     var max_width;
116     var max_height;
118     $('context-menu').style['left'] = (render_x + 'px');
119     $('context-menu').style['top'] = (render_y + 'px');         
120     Element.update('context-menu', '');
122     new Ajax.Updater({success:'context-menu'}, this.url, 
123       {asynchronous:true,
124        evalScripts:true,
125        parameters:Form.serialize(Event.findElement(e, 'form')),
126        onComplete:function(request){
127                                  dims = $('context-menu').getDimensions();
128                                  menu_width = dims.width;
129                                  menu_height = dims.height;
130                                  max_width = mouse_x + 2*menu_width;
131                                  max_height = mouse_y + menu_height;
132                         
133                                  var ws = window_size();
134                                  window_width = ws.width;
135                                  window_height = ws.height;
136                         
137                                  /* display the menu above and/or to the left of the click if needed */
138                                  if (max_width > window_width) {
139                                    render_x -= menu_width;
140                                    $('context-menu').addClassName('reverse-x');
141                                  } else {
142                                          $('context-menu').removeClassName('reverse-x');
143                                  }
144                                  if (max_height > window_height) {
145                                    render_y -= menu_height;
146                                    $('context-menu').addClassName('reverse-y');
147                                  } else {
148                                          $('context-menu').removeClassName('reverse-y');
149                                  }
150                                  if (render_x <= 0) render_x = 1;
151                                  if (render_y <= 0) render_y = 1;
152                                  $('context-menu').style['left'] = (render_x + 'px');
153                                  $('context-menu').style['top'] = (render_y + 'px');
154                                  
155          Effect.Appear('context-menu', {duration: 0.20});
156          if (window.parseStylesheets) { window.parseStylesheets(); } // IE
157       }})
158   },
159   
160   hideMenu: function() {
161     Element.hide('context-menu');
162   },
163   
164   addSelection: function(tr) {
165     tr.addClassName('context-menu-selection');
166     this.checkSelectionBox(tr, true);
167     this.clearDocumentSelection();
168   },
169   
170   toggleSelection: function(tr) {
171     if (this.isSelected(tr)) {
172       this.removeSelection(tr);
173     } else {
174       this.addSelection(tr);
175     }
176   },
177   
178   removeSelection: function(tr) {
179     tr.removeClassName('context-menu-selection');
180     this.checkSelectionBox(tr, false);
181   },
182   
183   unselectAll: function() {
184     var rows = $$('.hascontextmenu');
185     for (i=0; i<rows.length; i++) {
186       this.removeSelection(rows[i]);
187     }
188   },
189   
190   checkSelectionBox: function(tr, checked) {
191         var inputs = Element.getElementsBySelector(tr, 'input');
192         if (inputs.length > 0) { inputs[0].checked = checked; }
193   },
194   
195   isSelected: function(tr) {
196     return Element.hasClassName(tr, 'context-menu-selection');
197   },
198   
199   clearDocumentSelection: function() {
200     if (document.selection) {
201       document.selection.clear(); // IE
202     } else {
203       window.getSelection().removeAllRanges();
204     }
205   }
208 function toggleIssuesSelection(el) {
209         var boxes = el.getElementsBySelector('input[type=checkbox]');
210         var all_checked = true;
211         for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }
212         for (i = 0; i < boxes.length; i++) {
213                 if (all_checked) {
214                         boxes[i].checked = false;
215                         boxes[i].up('tr').removeClassName('context-menu-selection');
216                 } else if (boxes[i].checked == false) {
217                         boxes[i].checked = true;
218                         boxes[i].up('tr').addClassName('context-menu-selection');
219                 }
220         }
223 function window_size() {
224     var w;
225     var h;
226     if (window.innerWidth) {
227         w = window.innerWidth;
228         h = window.innerHeight;
229     } else if (document.documentElement) {
230         w = document.documentElement.clientWidth;
231         h = document.documentElement.clientHeight;
232     } else {
233         w = document.body.clientWidth;
234         h = document.body.clientHeight;
235     }
236     return {width: w, height: h};