annotate public/javascripts/context_menu.js @ 8:0c83d98252d9 yuya

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