stuff_to_do_plugin 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYRIGHT.txt +18 -0
- data/CREDITS.txt +6 -0
- data/GPL.txt +339 -0
- data/README.rdoc +61 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/app/controllers/stuff_to_do_controller.rb +161 -0
- data/app/helpers/stuff_to_do_helper.rb +88 -0
- data/app/models/stuff_to_do.rb +208 -0
- data/app/models/stuff_to_do_filter.rb +32 -0
- data/app/models/stuff_to_do_mailer.rb +16 -0
- data/app/views/settings/_stuff_to_do_settings.html.erb +27 -0
- data/app/views/stuff_to_do/_issue.html.erb +16 -0
- data/app/views/stuff_to_do/_item.html.erb +5 -0
- data/app/views/stuff_to_do/_left_panes.html.erb +51 -0
- data/app/views/stuff_to_do/_panes.html.erb +11 -0
- data/app/views/stuff_to_do/_project.html.erb +6 -0
- data/app/views/stuff_to_do/_right_panes.html.erb +25 -0
- data/app/views/stuff_to_do/_time_grid.html.erb +113 -0
- data/app/views/stuff_to_do/_time_grid_form.html.erb +32 -0
- data/app/views/stuff_to_do/index.html.erb +44 -0
- data/app/views/stuff_to_do_mailer/recommended_below_threshold.erb +3 -0
- data/app/views/stuff_to_do_mailer/recommended_below_threshold.text.html.rhtml +1 -0
- data/assets/images/b.png +0 -0
- data/assets/images/bl.png +0 -0
- data/assets/images/br.png +0 -0
- data/assets/images/closelabel.gif +0 -0
- data/assets/images/loading.gif +0 -0
- data/assets/images/tl.png +0 -0
- data/assets/images/tr.png +0 -0
- data/assets/javascripts/facebox.js +319 -0
- data/assets/javascripts/jquery-1.2.6.min.js +32 -0
- data/assets/javascripts/jquery-ui.js +2839 -0
- data/assets/javascripts/jquery.contextMenu.js +212 -0
- data/assets/javascripts/semantic.cache +15 -0
- data/assets/javascripts/stuff-to-do.js +270 -0
- data/assets/javascripts/ui/build.xml +24 -0
- data/assets/javascripts/ui/effects.blind.js +49 -0
- data/assets/javascripts/ui/effects.bounce.js +78 -0
- data/assets/javascripts/ui/effects.clip.js +54 -0
- data/assets/javascripts/ui/effects.core.js +510 -0
- data/assets/javascripts/ui/effects.drop.js +50 -0
- data/assets/javascripts/ui/effects.explode.js +79 -0
- data/assets/javascripts/ui/effects.fold.js +55 -0
- data/assets/javascripts/ui/effects.highlight.js +48 -0
- data/assets/javascripts/ui/effects.pulsate.js +55 -0
- data/assets/javascripts/ui/effects.scale.js +180 -0
- data/assets/javascripts/ui/effects.shake.js +57 -0
- data/assets/javascripts/ui/effects.slide.js +50 -0
- data/assets/javascripts/ui/effects.transfer.js +59 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ar.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-bg.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ca.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-cs.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-da.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-de.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-eo.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-es.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fa.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fi.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-he.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hu.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hy.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-id.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-is.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-it.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ja.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ko.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-lt.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-lv.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-nl.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-no.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-pl.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-pt-BR.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ro.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ru.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sk.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sl.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sq.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sv.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-th.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-tr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-uk.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-zh-CN.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-zh-TW.js +25 -0
- data/assets/javascripts/ui/svn.log +11 -0
- data/assets/javascripts/ui/ui.accordion.js +400 -0
- data/assets/javascripts/ui/ui.core.js +533 -0
- data/assets/javascripts/ui/ui.datepicker.js +1754 -0
- data/assets/javascripts/ui/ui.dialog.js +630 -0
- data/assets/javascripts/ui/ui.draggable.js +696 -0
- data/assets/javascripts/ui/ui.droppable.js +314 -0
- data/assets/javascripts/ui/ui.progressbar.js +114 -0
- data/assets/javascripts/ui/ui.resizable.js +805 -0
- data/assets/javascripts/ui/ui.selectable.js +266 -0
- data/assets/javascripts/ui/ui.slider.js +552 -0
- data/assets/javascripts/ui/ui.sortable.js +1012 -0
- data/assets/javascripts/ui/ui.tabs.js +572 -0
- data/assets/stylesheets/stuff_to_do.css +216 -0
- data/config/locales/bg.yml +18 -0
- data/config/locales/ca-fr.yml +18 -0
- data/config/locales/cs.yml +16 -0
- data/config/locales/da.yml +16 -0
- data/config/locales/de.yml +18 -0
- data/config/locales/en.yml +24 -0
- data/config/locales/es.yml +19 -0
- data/config/locales/fr.yml +17 -0
- data/config/locales/hu.yml +16 -0
- data/config/locales/it.yml +16 -0
- data/config/locales/ja.yml +18 -0
- data/config/locales/ko.yml +18 -0
- data/config/locales/lt.yml +18 -0
- data/config/locales/nl.yml +20 -0
- data/config/locales/pt-BR.yml +18 -0
- data/config/locales/ru.yml +19 -0
- data/config/locales/sv.yml +19 -0
- data/config/locales/tr.yml +18 -0
- data/config/routes.rb +3 -0
- data/init.rb +54 -0
- data/lang/bg.yml +17 -0
- data/lang/ca-fr.yml +17 -0
- data/lang/cs.yml +15 -0
- data/lang/da.yml +15 -0
- data/lang/de.yml +17 -0
- data/lang/en.yml +21 -0
- data/lang/es.yml +18 -0
- data/lang/fr.yml +16 -0
- data/lang/hu.yml +15 -0
- data/lang/it.yml +15 -0
- data/lang/ja.yml +17 -0
- data/lang/ko.yml +17 -0
- data/lang/lt.yml +17 -0
- data/lang/pt-br.yml +17 -0
- data/lang/ru.yml +15 -0
- data/lang/sv.yml +18 -0
- data/lang/tr.yml +17 -0
- data/lib/redmine_stuff_to_do/stuff_to_do_compatibility.rb +15 -0
- data/lib/stuff_to_do_array_patch.rb +8 -0
- data/lib/stuff_to_do_issue_patch.rb +57 -0
- data/lib/stuff_to_do_project_patch.rb +31 -0
- data/lib/stuff_to_do_user_patch.rb +10 -0
- data/rails/init.rb +1 -0
- data/spec/controllers/stuff_to_do_controller_add_to_time_grid_spec.rb +58 -0
- data/spec/controllers/stuff_to_do_controller_index_spec.rb +155 -0
- data/spec/controllers/stuff_to_do_controller_remove_from_time_grid_spec.rb +56 -0
- data/spec/controllers/stuff_to_do_controller_reorder_spec.rb +179 -0
- data/spec/controllers/stuff_to_do_controller_save_time_entries_spec.rb +56 -0
- data/spec/controllers/stuff_to_do_private_methods_spec.rb +82 -0
- data/spec/lib/stuff_to_do_issue_patch_spec.rb +60 -0
- data/spec/lib/stuff_to_do_project_patch_spec.rb +50 -0
- data/spec/lib/stuff_to_do_user_patch_spec.rb +8 -0
- data/spec/models/stuff_to_do_filter_spec.rb +3 -0
- data/spec/models/stuff_to_do_mailer_spec.rb +42 -0
- data/spec/models/stuff_to_do_spec.rb +426 -0
- data/spec/sanity_spec.rb +7 -0
- data/spec/spec_helper.rb +130 -0
- metadata +211 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
// jQuery Context Menu Plugin
|
2
|
+
//
|
3
|
+
// Version 1.00
|
4
|
+
//
|
5
|
+
// Cory S.N. LaViska
|
6
|
+
// A Beautiful Site (http://abeautifulsite.net/)
|
7
|
+
//
|
8
|
+
// Visit http://abeautifulsite.net/notebook/80 for usage and more information
|
9
|
+
//
|
10
|
+
// Terms of Use
|
11
|
+
//
|
12
|
+
// This software is licensed under a Creative Commons License and is copyrighted
|
13
|
+
// (C)2008 by Cory S.N. LaViska.
|
14
|
+
//
|
15
|
+
// For details, visit http://creativecommons.org/licenses/by/3.0/us/
|
16
|
+
//
|
17
|
+
if(jQuery)( function($) {
|
18
|
+
$.extend($.fn, {
|
19
|
+
|
20
|
+
contextMenu: function(o, callback) {
|
21
|
+
// Defaults
|
22
|
+
if( o.menu == undefined ) return false;
|
23
|
+
if( o.menuCssName == undefined ) o.menuCssName = 'contextMenu';
|
24
|
+
if( o.inSpeed == undefined ) o.inSpeed = 150;
|
25
|
+
if( o.outSpeed == undefined ) o.outSpeed = 75;
|
26
|
+
// 0 needs to be -1 for expected results (no fade)
|
27
|
+
if( o.inSpeed == 0 ) o.inSpeed = -1;
|
28
|
+
if( o.outSpeed == 0 ) o.outSpeed = -1;
|
29
|
+
// Loop each context menu
|
30
|
+
$(this).each( function() {
|
31
|
+
var el = $(this);
|
32
|
+
var offset = $(el).offset();
|
33
|
+
// Add contextMenu class
|
34
|
+
$('#' + o.menu).addClass(o.menuCssName);
|
35
|
+
// Simulate a true right click
|
36
|
+
$(this).mousedown( function(e) {
|
37
|
+
var evt = e;
|
38
|
+
$(this).mouseup( function(e) {
|
39
|
+
var srcElement = $(this);
|
40
|
+
$(this).unbind('mouseup');
|
41
|
+
if( evt.button == 2 ) {
|
42
|
+
// Hide context menus that may be showing
|
43
|
+
$("." + o.menuCssName).hide();
|
44
|
+
// Get this context menu
|
45
|
+
var menu = $('#' + o.menu);
|
46
|
+
|
47
|
+
if( $(el).hasClass('disabled') ) return false;
|
48
|
+
|
49
|
+
// Detect mouse position
|
50
|
+
var d = {}, x, y;
|
51
|
+
if( self.innerHeight ) {
|
52
|
+
d.pageYOffset = self.pageYOffset;
|
53
|
+
d.pageXOffset = self.pageXOffset;
|
54
|
+
d.innerHeight = self.innerHeight;
|
55
|
+
d.innerWidth = self.innerWidth;
|
56
|
+
} else if( document.documentElement &&
|
57
|
+
document.documentElement.clientHeight ) {
|
58
|
+
d.pageYOffset = document.documentElement.scrollTop;
|
59
|
+
d.pageXOffset = document.documentElement.scrollLeft;
|
60
|
+
d.innerHeight = document.documentElement.clientHeight;
|
61
|
+
d.innerWidth = document.documentElement.clientWidth;
|
62
|
+
} else if( document.body ) {
|
63
|
+
d.pageYOffset = document.body.scrollTop;
|
64
|
+
d.pageXOffset = document.body.scrollLeft;
|
65
|
+
d.innerHeight = document.body.clientHeight;
|
66
|
+
d.innerWidth = document.body.clientWidth;
|
67
|
+
}
|
68
|
+
(e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
|
69
|
+
(e.pageY) ? y = e.pageY : x = e.clientY + d.scrollTop;
|
70
|
+
|
71
|
+
// Show the menu
|
72
|
+
$(document).unbind('click');
|
73
|
+
$(menu).css({ top: y, left: x }).fadeIn(o.inSpeed);
|
74
|
+
// Hover events
|
75
|
+
$(menu).find('A').mouseover( function() {
|
76
|
+
$(menu).find('LI.hover').removeClass('hover');
|
77
|
+
$(this).parent().addClass('hover');
|
78
|
+
}).mouseout( function() {
|
79
|
+
$(menu).find('LI.hover').removeClass('hover');
|
80
|
+
});
|
81
|
+
|
82
|
+
// Keyboard
|
83
|
+
$(document).keypress( function(e) {
|
84
|
+
switch( e.keyCode ) {
|
85
|
+
case 38: // up
|
86
|
+
if( $(menu).find('LI.hover').size() == 0 ) {
|
87
|
+
$(menu).find('LI:last').addClass('hover');
|
88
|
+
} else {
|
89
|
+
$(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
|
90
|
+
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
|
91
|
+
}
|
92
|
+
break;
|
93
|
+
case 40: // down
|
94
|
+
if( $(menu).find('LI.hover').size() == 0 ) {
|
95
|
+
$(menu).find('LI:first').addClass('hover');
|
96
|
+
} else {
|
97
|
+
$(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
|
98
|
+
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
|
99
|
+
}
|
100
|
+
break;
|
101
|
+
case 13: // enter
|
102
|
+
$(menu).find('LI.hover A').trigger('click');
|
103
|
+
break;
|
104
|
+
case 27: // esc
|
105
|
+
$(document).trigger('click');
|
106
|
+
break
|
107
|
+
}
|
108
|
+
});
|
109
|
+
|
110
|
+
// When items are selected
|
111
|
+
$('#' + o.menu).find('A').unbind('click');
|
112
|
+
$('#' + o.menu).find('LI:not(.disabled) A').click( function() {
|
113
|
+
$(document).unbind('click').unbind('keypress');
|
114
|
+
$("." + o.menuCssName).hide();
|
115
|
+
// Callback
|
116
|
+
if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} );
|
117
|
+
return false;
|
118
|
+
});
|
119
|
+
|
120
|
+
// Hide bindings
|
121
|
+
setTimeout( function() { // Delay for Mozilla
|
122
|
+
$(document).click( function() {
|
123
|
+
$(document).unbind('click').unbind('keypress');
|
124
|
+
$(menu).fadeOut(o.outSpeed);
|
125
|
+
return false;
|
126
|
+
});
|
127
|
+
}, 0);
|
128
|
+
}
|
129
|
+
});
|
130
|
+
});
|
131
|
+
|
132
|
+
// Disable text selection
|
133
|
+
if( $.browser.mozilla ) {
|
134
|
+
$('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
|
135
|
+
} else if( $.browser.msie ) {
|
136
|
+
$('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
|
137
|
+
} else {
|
138
|
+
$('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
|
139
|
+
}
|
140
|
+
// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
|
141
|
+
$(el).add('UL.' + o.menuCssName).bind('contextmenu', function() { return false; });
|
142
|
+
|
143
|
+
});
|
144
|
+
return $(this);
|
145
|
+
},
|
146
|
+
|
147
|
+
// Disable context menu items on the fly
|
148
|
+
disableContextMenuItems: function(o) {
|
149
|
+
if( o == undefined ) {
|
150
|
+
// Disable all
|
151
|
+
$(this).find('LI').addClass('disabled');
|
152
|
+
return( $(this) );
|
153
|
+
}
|
154
|
+
$(this).each( function() {
|
155
|
+
if( o != undefined ) {
|
156
|
+
var d = o.split(',');
|
157
|
+
for( var i = 0; i < d.length; i++ ) {
|
158
|
+
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
|
159
|
+
|
160
|
+
}
|
161
|
+
}
|
162
|
+
});
|
163
|
+
return( $(this) );
|
164
|
+
},
|
165
|
+
|
166
|
+
// Enable context menu items on the fly
|
167
|
+
enableContextMenuItems: function(o) {
|
168
|
+
if( o == undefined ) {
|
169
|
+
// Enable all
|
170
|
+
$(this).find('LI.disabled').removeClass('disabled');
|
171
|
+
return( $(this) );
|
172
|
+
}
|
173
|
+
$(this).each( function() {
|
174
|
+
if( o != undefined ) {
|
175
|
+
var d = o.split(',');
|
176
|
+
for( var i = 0; i < d.length; i++ ) {
|
177
|
+
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
|
178
|
+
|
179
|
+
}
|
180
|
+
}
|
181
|
+
});
|
182
|
+
return( $(this) );
|
183
|
+
},
|
184
|
+
|
185
|
+
// Disable context menu(s)
|
186
|
+
disableContextMenu: function() {
|
187
|
+
$(this).each( function() {
|
188
|
+
$(this).addClass('disabled');
|
189
|
+
});
|
190
|
+
return( $(this) );
|
191
|
+
},
|
192
|
+
|
193
|
+
// Enable context menu(s)
|
194
|
+
enableContextMenu: function() {
|
195
|
+
$(this).each( function() {
|
196
|
+
$(this).removeClass('disabled');
|
197
|
+
});
|
198
|
+
return( $(this) );
|
199
|
+
},
|
200
|
+
|
201
|
+
// Destroy context menu(s)
|
202
|
+
destroyContextMenu: function() {
|
203
|
+
// Destroy specified context menus
|
204
|
+
$(this).each( function() {
|
205
|
+
// Disable action
|
206
|
+
$(this).unbind('mousedown').unbind('mouseup');
|
207
|
+
});
|
208
|
+
return( $(this) );
|
209
|
+
}
|
210
|
+
|
211
|
+
});
|
212
|
+
})(jQuery);
|
@@ -0,0 +1,15 @@
|
|
1
|
+
;; Object javascripts/
|
2
|
+
;; SEMANTICDB Tags save file
|
3
|
+
(semanticdb-project-database-file "javascripts/"
|
4
|
+
:tables (list
|
5
|
+
(semanticdb-table "stuff-to-do.js"
|
6
|
+
:major-mode 'javascript-mode
|
7
|
+
:tags '(("attachSortables" function nil nil [938 1844]) ("saveOrder" function nil nil [1846 2464]))
|
8
|
+
:file "stuff-to-do.js"
|
9
|
+
:pointmax 2466
|
10
|
+
)
|
11
|
+
)
|
12
|
+
:file "semantic.cache"
|
13
|
+
:semantic-tag-version "2.0pre4"
|
14
|
+
:semanticdb-version "2.0pre4"
|
15
|
+
)
|
@@ -0,0 +1,270 @@
|
|
1
|
+
// TODO: JSUnit test this
|
2
|
+
jQuery(function($) {
|
3
|
+
$("#user_id").change(function() { $("form#user_switch").submit(); });
|
4
|
+
$("#ajax-indicator").ajaxStart(function(){ $(this).show(); });
|
5
|
+
$("#ajax-indicator").ajaxStop(function(){ $(this).hide(); });
|
6
|
+
|
7
|
+
$("#filter").change(function() {
|
8
|
+
if ($('#filter').val() != '') {
|
9
|
+
$.ajax({
|
10
|
+
type: "GET",
|
11
|
+
url: 'stuff_to_do/available_issues.js',
|
12
|
+
data: $('#filter').serialize(),
|
13
|
+
success: function(response) {
|
14
|
+
$('#available-pane').html(response);
|
15
|
+
attachSortables();
|
16
|
+
},
|
17
|
+
error: function(response) {
|
18
|
+
$("div.error").html("Error filtering pane. Please refresh the page.").show();
|
19
|
+
}});
|
20
|
+
}
|
21
|
+
});
|
22
|
+
|
23
|
+
attachSortables = function() {
|
24
|
+
$("#available").sortable({
|
25
|
+
cancel: 'a',
|
26
|
+
connectWith: ["#doing-now", "#recommended", "#time-grid-table tbody"],
|
27
|
+
placeholder: 'drop-accepted',
|
28
|
+
dropOnEmpty: true,
|
29
|
+
update : function (event, ui) {
|
30
|
+
if ($('#available li.issue').length > 0) {
|
31
|
+
$("#available li.empty-list").hide();
|
32
|
+
} else {
|
33
|
+
$("#available li.empty-list").show();
|
34
|
+
}
|
35
|
+
},
|
36
|
+
receive : function (event, ui) { removeItemFromTimeGridIfNeeded(event,ui);}
|
37
|
+
});
|
38
|
+
|
39
|
+
$("#doing-now").sortable({
|
40
|
+
cancel: 'a',
|
41
|
+
connectWith: ["#available", "#recommended", "#time-grid-table tbody"],
|
42
|
+
dropOnEmpty: true,
|
43
|
+
placeholder: 'drop-accepted',
|
44
|
+
update : function (event, ui) { saveOrder(ui); },
|
45
|
+
receive : function (event, ui) { removeItemFromTimeGridIfNeeded(event,ui);}
|
46
|
+
});
|
47
|
+
|
48
|
+
$("#recommended").sortable({
|
49
|
+
cancel: 'a',
|
50
|
+
connectWith: ["#available", "#doing-now", "#time-grid-table tbody"],
|
51
|
+
dropOnEmpty: true,
|
52
|
+
placeholder: 'drop-accepted',
|
53
|
+
update : function (event, ui) { saveOrder(ui); },
|
54
|
+
receive : function (event, ui) { removeItemFromTimeGridIfNeeded(event,ui);}
|
55
|
+
});
|
56
|
+
|
57
|
+
$("#time-grid-table tbody").sortable({
|
58
|
+
connectWith: ["#available", "#doing-now", "#recommended"],
|
59
|
+
items: 'tr',
|
60
|
+
placeholder: 'drop-accepted',
|
61
|
+
// Cancel the drag and drop if it's reordering itself
|
62
|
+
update: function (event, ui) {
|
63
|
+
if (ui.sender == null && isDraggingToTimeGrid($(event.target))) {
|
64
|
+
$(this).sortable('cancel');
|
65
|
+
}
|
66
|
+
},
|
67
|
+
receive : function (event, ui) {
|
68
|
+
$(ui.sender).sortable('cancel');
|
69
|
+
if (isAddingAnIssueToTimeGrid($(event.target))) {
|
70
|
+
var std_item = ui.item;
|
71
|
+
// Only add issues that are missing.
|
72
|
+
if (!isProjectItem(std_item) && !isItemInTimeGrid(std_item)) {
|
73
|
+
addItemToTimeGrid(std_item);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
});
|
78
|
+
},
|
79
|
+
|
80
|
+
saveOrder = function() {
|
81
|
+
data = 'user_id=' + user_id + '&' + $("#doing-now").sortable('serialize') + '&' + $("#recommended").sortable('serialize');
|
82
|
+
if (filter != null) {
|
83
|
+
data = data + '&filter=' + filter;
|
84
|
+
}
|
85
|
+
|
86
|
+
data = addAuthenticityToken(data);
|
87
|
+
|
88
|
+
$.ajax({
|
89
|
+
type: "POST",
|
90
|
+
url: 'stuff_to_do/reorder.js',
|
91
|
+
data: data,
|
92
|
+
success: function(response) {
|
93
|
+
$('#panes').html(response);
|
94
|
+
attachSortables();
|
95
|
+
},
|
96
|
+
error: function(response) {
|
97
|
+
$("div#stuff-to-do-error").html("Error saving lists. Please refresh the page and try again.").show();
|
98
|
+
}});
|
99
|
+
|
100
|
+
},
|
101
|
+
|
102
|
+
addItemToTimeGrid = function(issue) {
|
103
|
+
$.ajax({
|
104
|
+
type: "POST",
|
105
|
+
url: 'stuff_to_do/add_to_time_grid.js',
|
106
|
+
data: addAuthenticityToken('issue_id=' + getRecordId(issue) + '&' + $('#query_form').serialize()),
|
107
|
+
success: function(response) {
|
108
|
+
$('#time-grid').html(response);
|
109
|
+
attachSortables();
|
110
|
+
},
|
111
|
+
error: function(response) {
|
112
|
+
$("div#time-grid-error").html("Error saving Time Grid. Please refresh the page and try again.").show();
|
113
|
+
}});
|
114
|
+
},
|
115
|
+
|
116
|
+
removeItemFromTimeGrid = function(issue) {
|
117
|
+
$.ajax({
|
118
|
+
type: "POST",
|
119
|
+
url: 'stuff_to_do/remove_from_time_grid.js',
|
120
|
+
data: addAuthenticityToken('issue_id=' + getRecordId(issue) + '&' + $('#query_form').serialize()),
|
121
|
+
success: function(response) {
|
122
|
+
$('#time-grid').html(response);
|
123
|
+
attachSortables();
|
124
|
+
},
|
125
|
+
error: function(response) {
|
126
|
+
$("div#time-grid-error").html("Error saving Time Grid. Please refresh the page and try again.").show();
|
127
|
+
}});
|
128
|
+
},
|
129
|
+
|
130
|
+
isProjectItem = function(element) {
|
131
|
+
return element.attr('id').match(/project/);
|
132
|
+
},
|
133
|
+
|
134
|
+
isItemInTimeGrid = function(element) {
|
135
|
+
var record_id = getRecordId(element);
|
136
|
+
return $('td.time-grid-issue issue_' + record_id).size() > 0;
|
137
|
+
},
|
138
|
+
|
139
|
+
isAddingAnIssueToTimeGrid = function(jqueryElement) {
|
140
|
+
return (jqueryElement.parents('#time-grid-table').length == 0);
|
141
|
+
},
|
142
|
+
|
143
|
+
isDraggingToTimeGrid = function(jqueryElement) {
|
144
|
+
return !isAddingAnIssueToTimeGrid(jqueryElement);
|
145
|
+
},
|
146
|
+
|
147
|
+
getRecordId = function(jqueryElement) {
|
148
|
+
return jqueryElement.attr('id').split('_').last();
|
149
|
+
},
|
150
|
+
|
151
|
+
removeItemFromTimeGridIfNeeded = function (event, ui) {
|
152
|
+
if (!isAddingAnIssueToTimeGrid($(event.target)) || !isAddingAnIssueToTimeGrid(ui.sender)) {
|
153
|
+
$(ui.sender).sortable('cancel');
|
154
|
+
removeItemFromTimeGrid(ui.item);
|
155
|
+
}
|
156
|
+
},
|
157
|
+
|
158
|
+
timeLogFacebox = function(issue_id, date) {
|
159
|
+
if (issue_id != undefined) {
|
160
|
+
$('#time_entry__issue_id').val(issue_id);
|
161
|
+
}
|
162
|
+
|
163
|
+
if (date != undefined) {
|
164
|
+
$('#time_entry__core').val(date); // Renamed below
|
165
|
+
}
|
166
|
+
|
167
|
+
$.facebox({div: '#logtime'});
|
168
|
+
bindTimeEntryForm(); // Rebind since Facebox copies it
|
169
|
+
// Need to rebind the calendar by renaming the time_entry
|
170
|
+
// fields and running setup.
|
171
|
+
$('#facebox #time_entry__core').attr("id", "time_entry__spent_on");
|
172
|
+
$('#facebox #time_entry__core_trigger').attr("id", "time_entry__spent_on_trigger");
|
173
|
+
Calendar.setup({inputField : 'time_entry__spent_on', ifFormat : '%Y-%m-%d', button : 'time_entry__spent_on_trigger' });
|
174
|
+
},
|
175
|
+
|
176
|
+
parseIssueId = function(jqueryElement) {
|
177
|
+
return jqueryElement.attr('id').split('_')[1];
|
178
|
+
},
|
179
|
+
|
180
|
+
parseDateFromGrid = function(jqueryElement) {
|
181
|
+
return jqueryElement.attr('class').split(' ')[1];
|
182
|
+
},
|
183
|
+
|
184
|
+
saveTimeEntriesRemotely = function(form) {
|
185
|
+
$.ajax({
|
186
|
+
type: "POST",
|
187
|
+
url: 'stuff_to_do/save_time_entry.js',
|
188
|
+
data: addAuthenticityToken($(form).serialize()),
|
189
|
+
success: function(response) {
|
190
|
+
$('#time-grid').before(response).remove();
|
191
|
+
$('.time-grid-flash').not(':empty').show();
|
192
|
+
jQuery(document).trigger('close.facebox');
|
193
|
+
},
|
194
|
+
error: function(response) {
|
195
|
+
alert(response.responseText);
|
196
|
+
}
|
197
|
+
});
|
198
|
+
},
|
199
|
+
|
200
|
+
bindContextMenuToTimeGrid = function() {
|
201
|
+
$("#time-grid-table tr td.time-grid-date").
|
202
|
+
contextMenu({ menu: 'time-grid-menu', menuCssName: 'context-menu' },
|
203
|
+
function(action, el, pos) {
|
204
|
+
timeLogFacebox(parseIssueId(el.parent()),
|
205
|
+
parseDateFromGrid(el));
|
206
|
+
});
|
207
|
+
},
|
208
|
+
|
209
|
+
bindTimeEntryForm = function() {
|
210
|
+
$('#facebox #logtime form').submit(function(){
|
211
|
+
saveTimeEntriesRemotely(this);
|
212
|
+
return false;
|
213
|
+
});
|
214
|
+
},
|
215
|
+
|
216
|
+
bindSaveTimeGridButtons = function() {
|
217
|
+
$('.save-time-grid').click(function(){
|
218
|
+
saveTimeEntriesRemotely();
|
219
|
+
return false;
|
220
|
+
});
|
221
|
+
},
|
222
|
+
|
223
|
+
initTimeGrid = function() {
|
224
|
+
bindContextMenuToTimeGrid();
|
225
|
+
bindTimeEntryForm();
|
226
|
+
bindSaveTimeGridButtons();
|
227
|
+
},
|
228
|
+
|
229
|
+
addAuthenticityToken = function(data) {
|
230
|
+
return data + '&authenticity_token=' + encodeURIComponent(window._token);
|
231
|
+
},
|
232
|
+
|
233
|
+
attachSortables();
|
234
|
+
|
235
|
+
// Fix the image paths in facebox
|
236
|
+
$.extend($.facebox.settings, {
|
237
|
+
loadingImage: '../images/loading.gif',
|
238
|
+
closeImage: '../plugin_assets/stuff_to_do_plugin/images/closelabel.gif',
|
239
|
+
faceboxHtml : '\
|
240
|
+
<div id="facebox" style="display:none;"> \
|
241
|
+
<div class="popup"> \
|
242
|
+
<table> \
|
243
|
+
<tbody> \
|
244
|
+
<tr> \
|
245
|
+
<td class="tl"/><td class="b"/><td class="tr"/> \
|
246
|
+
</tr> \
|
247
|
+
<tr> \
|
248
|
+
<td class="b"/> \
|
249
|
+
<td class="body"> \
|
250
|
+
<div class="content"> \
|
251
|
+
</div> \
|
252
|
+
<div class="footer"> \
|
253
|
+
<a href="#" class="close"> \
|
254
|
+
<img src="../plugin_assets/stuff_to_do_plugin/images/closelabel.gif" title="close" class="close_image" /> \
|
255
|
+
</a> \
|
256
|
+
</div> \
|
257
|
+
</td> \
|
258
|
+
<td class="b"/> \
|
259
|
+
</tr> \
|
260
|
+
<tr> \
|
261
|
+
<td class="bl"/><td class="b"/><td class="br"/> \
|
262
|
+
</tr> \
|
263
|
+
</tbody> \
|
264
|
+
</table> \
|
265
|
+
</div> \
|
266
|
+
</div>'
|
267
|
+
|
268
|
+
});
|
269
|
+
|
270
|
+
});
|