summaryrefslogtreecommitdiffstats
path: root/public
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2008-02-10 13:17:41 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2008-02-10 13:17:41 +0000
commit4155c97222cea69406060979efca3ebaaed9dcec (patch)
tree17bc056c97c1af47914bb2599995d2901749ce35 /public
parent43a6f312edde2399c9c986ed61b1e9b0e1066db6 (diff)
downloadredmine-4155c97222cea69406060979efca3ebaaed9dcec.tar.gz
redmine-4155c97222cea69406060979efca3ebaaed9dcec.zip
Issue list now supports bulk edit/move/delete (#563, #607). For now, issues from different projects can not be bulk edited/moved/deleted at once.
There are 2 ways to select a set of issues on the issue list: * by using checkbox and/or the little pencil that will select/unselect all issues (#567) * by clicking on the rows (but not on the links), Ctrl and Shift keys can be used to select multiple issues Context menu was disabled on links so that the default context menu of the browser is displayed when right-clicking on a link (#545). All this was tested with Firefox 2, IE 6/7, Opera 8 (use Alt+Click instead of Right-click) and Safari 2/3. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1130 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'public')
-rw-r--r--public/javascripts/application.js13
-rw-r--r--public/javascripts/context_menu.js186
2 files changed, 153 insertions, 46 deletions
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index 5ad04e91d..d77362a06 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -1,3 +1,6 @@
+/* redMine - project management software
+ Copyright (C) 2006-2008 Jean-Philippe Lang */
+
function checkAll (id, checked) {
var el = document.getElementById(id);
for (var i = 0; i < el.elements.length; i++) {
@@ -49,16 +52,6 @@ function promptToRemote(text, param, url) {
}
}
-/* checks that at least one checkbox is checked (used when submitting bulk edit form) */
-function checkBulkEdit(form) {
- for (var i = 0; i < form.elements.length; i++) {
- if (form.elements[i].checked) {
- return true;
- }
- }
- return false;
-}
-
function collapseScmEntry(id) {
var els = document.getElementsByClassName(id, 'browser');
for (var i = 0; i < els.length; i++) {
diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js
index 11754cde8..e3f128d89 100644
--- a/public/javascripts/context_menu.js
+++ b/public/javascripts/context_menu.js
@@ -1,47 +1,161 @@
+/* redMine - project management software
+ Copyright (C) 2006-2008 Jean-Philippe Lang */
+
+var observingContextMenuClick;
+
ContextMenu = Class.create();
ContextMenu.prototype = {
- initialize: function (options) {
- this.options = Object.extend({selector: '.hascontextmenu'}, options || { });
-
- Event.observe(document, 'click', function(e){
- var t = Event.findElement(e, 'a');
- if ((t != document) && (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu'))) {
- Event.stop(e);
- } else {
- $('context-menu').hide();
- if (this.selection) {
- this.selection.removeClassName('context-menu-selection');
- }
- }
-
- }.bind(this));
-
- $$(this.options.selector).invoke('observe', (window.opera ? 'click' : 'contextmenu'), function(e){
- if (window.opera && !e.ctrlKey) {
- return;
- }
- this.show(e);
- }.bind(this));
-
+ initialize: function (url) {
+ this.url = url;
+
+ // prevent selection when using Ctrl/Shit key
+ var tables = $$('table.issues');
+ for (i=0; i<tables.length; i++) {
+ tables[i].onselectstart = function () { return false; } // ie
+ tables[i].onmousedown = function () { return false; } // mozilla
+ }
+
+ if (!observingContextMenuClick) {
+ Event.observe(document, 'click', this.Click.bindAsEventListener(this));
+ Event.observe(document, (window.opera ? 'click' : 'contextmenu'), this.RightClick.bindAsEventListener(this));
+ observingContextMenuClick = true;
+ }
+
+ this.unselectAll();
+ this.lastSelected = null;
},
- show: function(e) {
+
+ RightClick: function(e) {
+ this.hideMenu();
+ // do not show the context menu on links
+ if (Event.findElement(e, 'a') != document) { return; }
+ // right-click simulated by Alt+Click with Opera
+ if (window.opera && !e.altKey) { return; }
+ var tr = Event.findElement(e, 'tr');
+ if ((tr == document) || !tr.hasClassName('hascontextmenu')) { return; }
Event.stop(e);
- Element.hide('context-menu');
- if (this.selection) {
- this.selection.removeClassName('context-menu-selection');
+ if (!this.isSelected(tr)) {
+ this.unselectAll();
+ this.addSelection(tr);
+ this.lastSelected = tr;
}
+ this.showMenu(e);
+ },
+
+ Click: function(e) {
+ this.hideMenu();
+ if (Event.findElement(e, 'a') != document) { return; }
+ if (window.opera && e.altKey) { return; }
+ if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) {
+ var tr = Event.findElement(e, 'tr');
+ if (tr!=document && tr.hasClassName('hascontextmenu')) {
+ // a row was clicked, check if the click was on checkbox
+ var box = Event.findElement(e, 'input');
+ if (box!=document) {
+ // a checkbox may be clicked
+ if (box.checked) {
+ tr.addClassName('context-menu-selection');
+ } else {
+ tr.removeClassName('context-menu-selection');
+ }
+ } else {
+ if (e.ctrlKey) {
+ 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');
+ if ((t != document) && (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu'))) {
+ Event.stop(e);
+ }
+ }
+ }
+ },
+
+ showMenu: function(e) {
$('context-menu').style['left'] = (Event.pointerX(e) + 'px');
$('context-menu').style['top'] = (Event.pointerY(e) + 'px');
Element.update('context-menu', '');
+ new Ajax.Updater({success:'context-menu'}, this.url,
+ {asynchronous:true,
+ evalScripts:true,
+ parameters:Form.serialize(Event.findElement(e, 'form')),
+ onComplete:function(request){
+ Effect.Appear('context-menu', {duration: 0.20});
+ if (window.parseStylesheets) { window.parseStylesheets(); } // IE
+ }})
+ },
+
+ hideMenu: function() {
+ Element.hide('context-menu');
+ },
+
+ addSelection: function(tr) {
+ tr.addClassName('context-menu-selection');
+ this.checkSelectionBox(tr, true);
+ },
+
+ toggleSelection: function(tr) {
+ if (this.isSelected(tr)) {
+ this.removeSelection(tr);
+ } else {
+ this.addSelection(tr);
+ }
+ },
+
+ removeSelection: function(tr) {
+ tr.removeClassName('context-menu-selection');
+ this.checkSelectionBox(tr, false);
+ },
+
+ unselectAll: function() {
+ var rows = $$('.hascontextmenu');
+ for (i=0; i<rows.length; i++) {
+ this.removeSelection(rows[i]);
+ }
+ },
+
+ checkSelectionBox: function(tr, checked) {
+ var inputs = Element.getElementsBySelector(tr, 'input');
+ if (inputs.length > 0) { inputs[0].checked = checked; }
+ },
+
+ isSelected: function(tr) {
+ return Element.hasClassName(tr, 'context-menu-selection');
+ }
+}
- var tr = Event.findElement(e, 'tr');
- tr.addClassName('context-menu-selection');
- this.selection = tr;
- var id = tr.id.substring(6, tr.id.length);
- /* TODO: do not hard code path */
- new Ajax.Updater({success:'context-menu'}, '../../issues/context_menu/' + id, {asynchronous:true, evalScripts:true, onComplete:function(request){
- Effect.Appear('context-menu', {duration: 0.20});
- if (window.parseStylesheets) { window.parseStylesheets(); }
- }})
+function toggleIssuesSelection(el) {
+ 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');
+ }
}
}