Commit 9fd60b376de1d272968eb1b6661a6ff2d964bdc1

Authored by Austin Smith
1 parent cf089daf7f
Exists in master

transition from prototype to jquery for redmine 2.1+

Showing 6 changed files with 150 additions and 148 deletions Side-by-side Diff

app/controllers/taskboard_controller.rb View file @ 9fd60b3
... ... @@ -49,51 +49,24 @@
49 49  
50 50 def create_column
51 51 @column = TaskBoardColumn.new :project => @project, :title => params[:title]
52   - respond_to do |format|
53   - if @column.save
54   - format.js{ render :update do |page|
55   - page.replace_html 'column_manager',
56   - :partial => 'settings/column_manager',
57   - :locals => {
58   - :columns => TaskBoardColumn.find_all_by_project_id(@project.id),
59   - :statuses => IssueStatus.all
60   - }
61   - end}
62   - else
63   - format.js{ render :update do |page|
64   - page.replace_html 'column_manager', :label_task_board_application_error
65   - end}
66   - end
67   - end
  52 + @column.save
  53 + render 'settings/update'
68 54 end
69 55  
70 56 def delete_column
71 57 @column = TaskBoardColumn.find(params[:column_id])
72   - respond_to do |format|
73   - if @column.delete
74   - format.js{ render :update do |page|
75   - page.replace_html 'column_manager',
76   - :partial => 'settings/column_manager',
77   - :locals => {
78   - :columns => TaskBoardColumn.find_all_by_project_id(@project.id, :order => "weight ASC"),
79   - :statuses => IssueStatus.all
80   - }
81   - end}
82   - else
83   - format.js{ render :update do |page|
84   - page.replace_html 'column_manager', :label_task_board_application_error
85   - end}
86   - end
87   - end
  58 + @column.delete
  59 + render 'settings/update'
88 60 end
89 61  
90 62 def update_columns
91 63 params[:column].each do |column_id, new_state|
92   - @column = TaskBoardColumn.find(column_id.to_i)
93   - @column.weight = new_state[:weight].to_i
94   - @column.max_issues = new_state[:max_issues].to_i
95   - @column.save
96   - @column.issue_statuses.clear()
  64 + column = TaskBoardColumn.find(column_id.to_i)
  65 + print column.title + ' ' + new_state[:weight] + ". "
  66 + column.weight = new_state[:weight].to_i
  67 + column.max_issues = new_state[:max_issues].to_i
  68 + column.save!
  69 + column.issue_statuses.clear()
97 70 end
98 71 params[:status].each do |status_id, column_id|
99 72 status_id = status_id.to_i
... ... @@ -103,16 +76,7 @@
103 76 @column.issue_statuses << IssueStatus.find(status_id)
104 77 end
105 78 end
106   - respond_to do |format|
107   - format.js{ render :update do |page|
108   - page.replace_html 'column_manager',
109   - :partial => 'settings/column_manager',
110   - :locals => {
111   - :columns => TaskBoardColumn.find_all_by_project_id(@project.id, :order => "weight ASC"),
112   - :statuses => IssueStatus.all
113   - }
114   - end}
115   - end
  79 + render 'settings/update'
116 80 end
117 81  
118 82 private
app/views/settings/_column_manager.html.erb View file @ 9fd60b3
... ... @@ -59,7 +59,7 @@
59 59 </div>
60 60  
61 61 <script type="text/javascript">
62   - var taskboard_settings = new TaskBoardSettings('taskboard-columns', {constraint: false, tag: 'ul', handle: 'head', weightSelector: '.column-options .column-weight', overlap: 'horizontal'});
  62 + var taskboard_settings = new TaskBoardSettings('taskboard-columns', {tag: 'ul', items: '> ul:visible', handle: '.head', weightSelector: '.column-options .column-weight', axis: 'x'});
63 63 </script>
64 64 <% end %>
app/views/settings/update.js.erb View file @ 9fd60b3
  1 +$('#column_manager').html("<%= escape_javascript( render(
  2 +:partial => 'settings/column_manager',
  3 +:locals => {
  4 + :columns => TaskBoardColumn.find_all_by_project_id(@project.id, :order => 'weight asc'),
  5 + :statuses => IssueStatus.all
  6 +})) -%>");
app/views/taskboard/_issue_description.html.erb View file @ 9fd60b3
... ... @@ -9,17 +9,15 @@
9 9 </div>
10 10  
11 11 <script type="text/javascript">
12   - $('taskboard-unarchive').observe('click', function() {
13   - new Ajax.Request('/issues/<%= @issue.id %>/taskboard-unarchive', {
14   - method: 'post',
15   - onLoading: function() {
16   - $('ajax-indicator').show();
  12 + $('#taskboard-unarchive').on('click', function() {
  13 + $('#ajax-indicator').show();
  14 + new $.ajax('/issues/<%= @issue.id %>/taskboard-unarchive', {
  15 + type: 'post',
  16 + complete: function() {
  17 + $('#ajax-indicator').hide();
17 18 },
18   - onComplete: function() {
19   - $('ajax-indicator').hide();
20   - },
21   - onSuccess: function() {
22   - $('taskboard-issue').remove();
  19 + success: function() {
  20 + $('#taskboard-issue').remove();
23 21 }
24 22 });
25 23 });
app/views/taskboard/index.html.erb View file @ 9fd60b3
... ... @@ -42,12 +42,12 @@
42 42 var project_save_url = '/projects/<%= @project.id %>/taskboard/save';
43 43 var project_archive_url = '/projects/<%= @project.id %>/taskboard/archive-issues';
44 44 var sections = [];
45   - $$('#sortable-root .taskboard-pane ul').each(function(el) {
46   - sections.push(el);
  45 + $('#sortable-root .taskboard-pane ul').each(function() {
  46 + sections.push($(this).attr('id'));
47 47 });
48   - sections.each(function(el) {
49   - new TaskBoardPane(el.id, {constraint: false, containment: sections, scroll: window, dropOnEmpty: true, only: 'card'});
50   - });
  48 + for (var i in sections) {
  49 + new TaskBoardPane(sections[i], {connectWith: '#sortable-root .taskboard-pane ul', constraint: false, scroll: true, dropOnEmpty: true, items: '> .card'});
  50 + }
51 51 TaskBoardUtils.checkboxListener();
52 52 // Sortable.create('sortable-root', {tree: true, dropOnEmpty: true, constraint: false, overlap: 'vertical'});
53 53 </script>
assets/javascripts/task_board.js View file @ 9fd60b3
1   -var TaskBoardSortable = Class.create({
  1 +/* Simple JavaScript Inheritance
  2 + * By John Resig http://ejohn.org/
  3 + * MIT Licensed.
  4 + */
  5 +(function(){
  6 + var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  7 + this.Class = function(){};
  8 + Class.extend = function(prop) {
  9 + var _super = this.prototype;
  10 + initializing = true;
  11 + var prototype = new this();
  12 + initializing = false;
  13 + for (var name in prop) {
  14 + prototype[name] = typeof prop[name] == "function" &&
  15 + typeof _super[name] == "function" && fnTest.test(prop[name]) ?
  16 + (function(name, fn){
  17 + return function() {
  18 + var tmp = this._super;
  19 + this._super = _super[name];
  20 + var ret = fn.apply(this, arguments);
  21 + this._super = tmp;
  22 + return ret;
  23 + };
  24 + })(name, prop[name]) :
  25 + prop[name];
  26 + }
  27 + function Class() {
  28 + if ( !initializing && this.init )
  29 + this.init.apply(this, arguments);
  30 + }
  31 + Class.prototype = prototype;
  32 + Class.prototype.constructor = Class;
  33 + Class.extend = arguments.callee;
  34 +
  35 + return Class;
  36 + };
  37 +})();
  38 +
  39 +var TaskBoardSortable = Class.extend({
2 40  
3 41 sortable: null,
4 42 id: null,
5 43 options: {},
6 44  
7   - initialize: function(id, options) {
  45 + init: function(id, options) {
8 46 this.id = id;
9 47 this.options = options;
10   - this.options.onChange = this.onChange.bind(this);
11   - this.options.onUpdate = this.onUpdate.bind(this);
12   - Sortable.create(id, this.options);
  48 + this.options.change = this.onChange.bind(this);
  49 + this.options.update = this.onUpdate.bind(this);
  50 + this.root = $('#' + this.id);
  51 + this.root.sortable(this.options);
13 52 },
14 53  
15 54 onChange: function() { },
16 55  
17 56  
18 57  
19 58  
20 59  
21 60  
22 61  
23 62  
24 63  
25 64  
26 65  
27 66  
28 67  
29 68  
30 69  
31 70  
... ... @@ -18,72 +57,73 @@
18 57  
19 58 });
20 59  
21   -var TaskBoardPane = Class.create(TaskBoardSortable, {
  60 +var TaskBoardPane = TaskBoardSortable.extend({
22 61  
23   - initialize: function($super, id, options) {
24   - $super(id, options);
25   - this.max_issues = parseInt($(id).readAttribute('data-max-issues'));
26   - $(this.id).writeAttribute('data-card-count', this.getNumberOfCards());
  62 + init: function(id, options) {
  63 + this._super(id, options);
  64 + this.max_issues = parseInt(this.root.data('max-issues'));
  65 + this.root.data('card-count', this.getNumberOfCards());
27 66 },
28 67  
29 68 getNumberOfCards: function() {
30   - return $(this.id).select('.card').length;
  69 + return this.root.find('.card').length;
31 70 },
32 71  
33   - onUpdate: function(list) {
  72 + onUpdate: function(e, ui) {
34 73 // Add or remove 'empty' class
35   - if (list.hasClassName('empty') && list.descendants().length > 0) {
36   - list.removeClassName('empty');
  74 + var list = ui.item.parent();
  75 + if (list.hasClass('empty') && list.find('.card').length > 0) {
  76 + list.removeClass('empty');
37 77 }
38   - else if (list.descendants().length == 0) {
39   - list.addClassName('empty');
  78 + else if (list.find('.card').length == 0) {
  79 + list.addClass('empty');
40 80 }
41 81  
42 82 // Deal with max issue limit
43   - if (this.max_issues > 0 && $(this.id).childElements().length > this.max_issues) {
  83 + if (this.max_issues > 0 && this.root.find('.card').length > this.max_issues) {
44 84 var i = 1;
45   - $(this.id).childElements().each((function(card) {
  85 + var self = this;
  86 + this.root.find('.card').each(function() {
46 87 // Clear legal cards of the over-limit class
47   - if (i <= this.max_issues) {
48   - card.removeClassName('over-limit');
  88 + if (i <= self.max_issues) {
  89 + $(this).removeClass('over-limit');
49 90 }
50 91  
51 92 // Add a dashed line under the last legal issue, reset others
52   - if (this.max_issues == i) {
53   - card.addClassName('at-limit');
  93 + if (self.max_issues == i) {
  94 + $(this).addClass('at-limit');
54 95 }
55 96 else {
56   - card.removeClassName('at-limit');
  97 + $(this).removeClassName('at-limit');
57 98 }
58 99  
59 100 // Add over-limit class to over-limit issues
60   - if (i > this.max_issues) {
61   - console.log('over limit');
62   - card.addClassName('over-limit');
  101 + if (i > self.max_issues) {
  102 + $(this).addClass('over-limit');
63 103 }
64 104 i++;
65   - }).bind(this));
  105 + });
66 106 }
67 107 else {
68   - $(this.id).childElements().each(function(card) {
69   - card.removeClassName('over-limit');
70   - card.removeClassName('at-limit');
  108 + this.root.find('.card').each(function() {
  109 + $(this).removeClass('over-limit');
  110 + $(this).removeClass('at-limit');
71 111 });
72 112 }
73 113  
74 114 // handle card movements
75 115  
76 116 // a card has been moved into this column.
77   - if (this.getNumberOfCards() > $(this.id).readAttribute('data-card-count')) {
78   - list.childElements().each(function(card) {
79   - if (list.readAttribute('data-status-id') != card.readAttribute('data-status-id')) {
  117 + if (this.getNumberOfCards() > list.data('card-count')) {
  118 + list.find('.card').each(function() {
  119 + if (list.data('status-id') != $(this).data('status-id')) {
80 120 TaskBoardUtils.save([
81   - TaskBoardUtils.serialize($(list.id)), // save ordering of this column
82   - TaskBoardUtils.serialize($('column_' + card.readAttribute('data-status-id'))), // save ordering of previous column
83   - TaskBoardUtils.moveParam(card.readAttribute('data-issue-id'), list.readAttribute('data-status-id'))
  121 + TaskBoardUtils.column_serialize(list), // save ordering of this column
  122 + TaskBoardUtils.column_serialize($('#' + 'column_' + $(this).data('status-id'))), // save ordering of previous column
  123 + TaskBoardUtils.moveParam($(this).data('issue-id'), list.data('status-id'))
84 124 ], {
85 125 onSuccess: function() {
86   - card.writeAttribute('data-status-id', list.readAttribute('data-status-id'));
  126 + $(this).data('status-id', list.data('status-id'));
87 127 }
88 128 });
89 129 }
90 130  
91 131  
92 132  
... ... @@ -91,24 +131,24 @@
91 131 }
92 132  
93 133 // this column has been reordered
94   - else if(this.getNumberOfCards() == $(this.id).readAttribute('data-card-count')) {
95   - TaskBoardUtils.save([TaskBoardUtils.serialize($(list.id))]);
  134 + else if(this.getNumberOfCards() == list.data('card-count')) {
  135 + TaskBoardUtils.save([TaskBoardUtils.column_serialize(list)]);
96 136 }
97 137  
98 138 // We don't handle (this.getNumberOfCards() < $(this.id).readAttribute('data-card-count'))
99 139 // because the gaining column handles re-weighting for the losing column for AJAX efficiency.
100 140  
101   - list.writeAttribute('data-card-count', this.getNumberOfCards());
  141 + list.data('card-count', this.getNumberOfCards());
102 142 },
103 143  
104 144 });
105 145  
106 146 var TaskBoardUtils = {
107 147  
108   - serialize: function(list) {
  148 + column_serialize: function(list) {
109 149 var params = [];
110   - list.childElements().each(function(card) {
111   - params.push('sort[' + list.readAttribute('data-status-id') + '][]=' + card.readAttribute('data-issue-id'));
  150 + list.find('.card').each(function() {
  151 + params.push('sort[' + list.data('status-id') + '][]=' + $(this).data('issue-id'));
112 152 });
113 153 return params.join('&');
114 154 },
115 155  
116 156  
117 157  
118 158  
119 159  
... ... @@ -118,49 +158,43 @@
118 158 },
119 159  
120 160 save: function(params) {
121   - var options = Object.extend({
122   - method: 'post',
123   - parameters: params.join('&'),
124   - onLoading: function() {
125   - $('ajax-indicator').show();
126   - },
127   - onComplete: function() {
128   - $('ajax-indicator').hide();
  161 + $('#ajax-indicator').show();
  162 + $.ajax(project_save_url, {
  163 + type: 'post',
  164 + data: params.join('&'),
  165 + complete: function() {
  166 + $('#ajax-indicator').hide();
129 167 }
130   - }, arguments[1] || {});
131   -
132   - new Ajax.Request(project_save_url, options);
  168 + });
133 169 },
134 170  
135 171 checkboxListener: function() {
136 172 TaskBoardUtils.hideButtonsIfNoneChecked();
137   - $$('.card input[type="checkbox"]').invoke('observe', 'click', function(field) {
138   - if (!$('taskboard-buttons').visible() && this.checked) {
139   - $('taskboard-buttons').show();
  173 + $(document).on('click', '.card input[type="checkbox"]', function() {
  174 + if (!$('#taskboard-buttons').is(':visible') && this.checked) {
  175 + $('#taskboard-buttons').show();
140 176 }
141 177 if (!this.checked) {
142 178 TaskBoardUtils.hideButtonsIfNoneChecked();
143 179 }
144 180 });
145 181  
146   - $('edit-issues').observe('click', function() {
  182 + $(document).on('click', '#edit-issues', function() {
147 183 location.href = '/issues/bulk_edit?' + TaskBoardUtils.serializeCheckedButtons();
148 184 });
149 185  
150   - $('archive-issues').observe('click', function() {
151   - new Ajax.Request(project_archive_url, {
152   - method: 'post',
153   - parameters: TaskBoardUtils.serializeCheckedButtons(),
154   - onLoading: function() {
155   - $('ajax-indicator').show();
  186 + $(document).on('click', '#archive-issues', function() {
  187 + $('#ajax-indicator').show();
  188 + $.ajax(project_archive_url, {
  189 + type: 'post',
  190 + data: TaskBoardUtils.serializeCheckedButtons(),
  191 + complete: function() {
  192 + $('#ajax-indicator').hide();
156 193 },
157   - onComplete: function() {
158   - $('ajax-indicator').hide();
159   - },
160   - onSuccess: function() {
161   - $$('.card input[type="checkbox"]').each(function(cb) {
162   - if (cb.checked) {
163   - $('issue_' + cb.value).remove();
  194 + success: function() {
  195 + $('.card input[type="checkbox"]').each(function() {
  196 + if ($(this).is(':checked')) {
  197 + $('#issue_' + $(this).val()).remove();
164 198 }
165 199 });
166 200 }
167 201  
168 202  
169 203  
170 204  
171 205  
172 206  
... ... @@ -170,37 +204,37 @@
170 204  
171 205 hideButtonsIfNoneChecked: function() {
172 206 var found_checked = false;
173   - $$('.card input[type="checkbox"]').each(function(cb) {
174   - if (cb.checked) {
  207 + $('.card input[type="checkbox"]').each(function() {
  208 + if (this.checked) {
175 209 found_checked = true;
176   - throw $break;
  210 + return false;
177 211 }
178 212 });
179 213 if (!found_checked) {
180   - $('taskboard-buttons').hide();
  214 + $('#taskboard-buttons').hide();
181 215 }
182 216 },
183 217  
184 218 serializeCheckedButtons: function() {
185 219 var params = [];
186   - $$('.card input[type="checkbox"]').each(function(cb) {
187   - if (cb.checked) {
188   - params.push('ids[]=' + cb.value);
  220 + $('.card input[type="checkbox"]').each(function() {
  221 + if (this.checked) {
  222 + params.push('ids[]=' + $(this).val());
189 223 }
190 224 });
191 225 return params.join('&');
192 226 }
193 227 }
194 228  
195   -var TaskBoardSettings = Class.create(TaskBoardSortable, {
  229 +var TaskBoardSettings = TaskBoardSortable.extend({
196 230  
197   - onChange: function() {
  231 + onUpdate: function(e, ui) {
198 232 var weight = 0;
199   - $(this.id).select(this.options.tag).each((function(el) {
200   - var weightInput = el.down(this.options.weightSelector);
201   - console.log(weightInput);
202   - weightInput.writeAttribute('value', weight++);
203   - }).bind(this));
  233 + var self = this;
  234 + this.root.find(this.options.items).each(function() {
  235 + var weightInput = $(this).find(self.options.weightSelector);
  236 + if ($(weightInput).length > 0) $(weightInput).val(weight++);
  237 + });
204 238 }
205 239  
206 240 });