stuff_to_do_plugin 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. data/COPYRIGHT.txt +18 -0
  2. data/CREDITS.txt +6 -0
  3. data/GPL.txt +339 -0
  4. data/README.rdoc +61 -0
  5. data/Rakefile +38 -0
  6. data/VERSION +1 -0
  7. data/app/controllers/stuff_to_do_controller.rb +161 -0
  8. data/app/helpers/stuff_to_do_helper.rb +88 -0
  9. data/app/models/stuff_to_do.rb +208 -0
  10. data/app/models/stuff_to_do_filter.rb +32 -0
  11. data/app/models/stuff_to_do_mailer.rb +16 -0
  12. data/app/views/settings/_stuff_to_do_settings.html.erb +27 -0
  13. data/app/views/stuff_to_do/_issue.html.erb +16 -0
  14. data/app/views/stuff_to_do/_item.html.erb +5 -0
  15. data/app/views/stuff_to_do/_left_panes.html.erb +51 -0
  16. data/app/views/stuff_to_do/_panes.html.erb +11 -0
  17. data/app/views/stuff_to_do/_project.html.erb +6 -0
  18. data/app/views/stuff_to_do/_right_panes.html.erb +25 -0
  19. data/app/views/stuff_to_do/_time_grid.html.erb +113 -0
  20. data/app/views/stuff_to_do/_time_grid_form.html.erb +32 -0
  21. data/app/views/stuff_to_do/index.html.erb +44 -0
  22. data/app/views/stuff_to_do_mailer/recommended_below_threshold.erb +3 -0
  23. data/app/views/stuff_to_do_mailer/recommended_below_threshold.text.html.rhtml +1 -0
  24. data/assets/images/b.png +0 -0
  25. data/assets/images/bl.png +0 -0
  26. data/assets/images/br.png +0 -0
  27. data/assets/images/closelabel.gif +0 -0
  28. data/assets/images/loading.gif +0 -0
  29. data/assets/images/tl.png +0 -0
  30. data/assets/images/tr.png +0 -0
  31. data/assets/javascripts/facebox.js +319 -0
  32. data/assets/javascripts/jquery-1.2.6.min.js +32 -0
  33. data/assets/javascripts/jquery-ui.js +2839 -0
  34. data/assets/javascripts/jquery.contextMenu.js +212 -0
  35. data/assets/javascripts/semantic.cache +15 -0
  36. data/assets/javascripts/stuff-to-do.js +270 -0
  37. data/assets/javascripts/ui/build.xml +24 -0
  38. data/assets/javascripts/ui/effects.blind.js +49 -0
  39. data/assets/javascripts/ui/effects.bounce.js +78 -0
  40. data/assets/javascripts/ui/effects.clip.js +54 -0
  41. data/assets/javascripts/ui/effects.core.js +510 -0
  42. data/assets/javascripts/ui/effects.drop.js +50 -0
  43. data/assets/javascripts/ui/effects.explode.js +79 -0
  44. data/assets/javascripts/ui/effects.fold.js +55 -0
  45. data/assets/javascripts/ui/effects.highlight.js +48 -0
  46. data/assets/javascripts/ui/effects.pulsate.js +55 -0
  47. data/assets/javascripts/ui/effects.scale.js +180 -0
  48. data/assets/javascripts/ui/effects.shake.js +57 -0
  49. data/assets/javascripts/ui/effects.slide.js +50 -0
  50. data/assets/javascripts/ui/effects.transfer.js +59 -0
  51. data/assets/javascripts/ui/i18n/ui.datepicker-ar.js +26 -0
  52. data/assets/javascripts/ui/i18n/ui.datepicker-bg.js +25 -0
  53. data/assets/javascripts/ui/i18n/ui.datepicker-ca.js +25 -0
  54. data/assets/javascripts/ui/i18n/ui.datepicker-cs.js +25 -0
  55. data/assets/javascripts/ui/i18n/ui.datepicker-da.js +25 -0
  56. data/assets/javascripts/ui/i18n/ui.datepicker-de.js +25 -0
  57. data/assets/javascripts/ui/i18n/ui.datepicker-eo.js +25 -0
  58. data/assets/javascripts/ui/i18n/ui.datepicker-es.js +25 -0
  59. data/assets/javascripts/ui/i18n/ui.datepicker-fa.js +25 -0
  60. data/assets/javascripts/ui/i18n/ui.datepicker-fi.js +25 -0
  61. data/assets/javascripts/ui/i18n/ui.datepicker-fr.js +25 -0
  62. data/assets/javascripts/ui/i18n/ui.datepicker-he.js +25 -0
  63. data/assets/javascripts/ui/i18n/ui.datepicker-hr.js +25 -0
  64. data/assets/javascripts/ui/i18n/ui.datepicker-hu.js +25 -0
  65. data/assets/javascripts/ui/i18n/ui.datepicker-hy.js +25 -0
  66. data/assets/javascripts/ui/i18n/ui.datepicker-id.js +25 -0
  67. data/assets/javascripts/ui/i18n/ui.datepicker-is.js +25 -0
  68. data/assets/javascripts/ui/i18n/ui.datepicker-it.js +25 -0
  69. data/assets/javascripts/ui/i18n/ui.datepicker-ja.js +26 -0
  70. data/assets/javascripts/ui/i18n/ui.datepicker-ko.js +25 -0
  71. data/assets/javascripts/ui/i18n/ui.datepicker-lt.js +25 -0
  72. data/assets/javascripts/ui/i18n/ui.datepicker-lv.js +25 -0
  73. data/assets/javascripts/ui/i18n/ui.datepicker-nl.js +25 -0
  74. data/assets/javascripts/ui/i18n/ui.datepicker-no.js +25 -0
  75. data/assets/javascripts/ui/i18n/ui.datepicker-pl.js +25 -0
  76. data/assets/javascripts/ui/i18n/ui.datepicker-pt-BR.js +25 -0
  77. data/assets/javascripts/ui/i18n/ui.datepicker-ro.js +25 -0
  78. data/assets/javascripts/ui/i18n/ui.datepicker-ru.js +25 -0
  79. data/assets/javascripts/ui/i18n/ui.datepicker-sk.js +25 -0
  80. data/assets/javascripts/ui/i18n/ui.datepicker-sl.js +26 -0
  81. data/assets/javascripts/ui/i18n/ui.datepicker-sq.js +25 -0
  82. data/assets/javascripts/ui/i18n/ui.datepicker-sv.js +25 -0
  83. data/assets/javascripts/ui/i18n/ui.datepicker-th.js +25 -0
  84. data/assets/javascripts/ui/i18n/ui.datepicker-tr.js +25 -0
  85. data/assets/javascripts/ui/i18n/ui.datepicker-uk.js +25 -0
  86. data/assets/javascripts/ui/i18n/ui.datepicker-zh-CN.js +25 -0
  87. data/assets/javascripts/ui/i18n/ui.datepicker-zh-TW.js +25 -0
  88. data/assets/javascripts/ui/svn.log +11 -0
  89. data/assets/javascripts/ui/ui.accordion.js +400 -0
  90. data/assets/javascripts/ui/ui.core.js +533 -0
  91. data/assets/javascripts/ui/ui.datepicker.js +1754 -0
  92. data/assets/javascripts/ui/ui.dialog.js +630 -0
  93. data/assets/javascripts/ui/ui.draggable.js +696 -0
  94. data/assets/javascripts/ui/ui.droppable.js +314 -0
  95. data/assets/javascripts/ui/ui.progressbar.js +114 -0
  96. data/assets/javascripts/ui/ui.resizable.js +805 -0
  97. data/assets/javascripts/ui/ui.selectable.js +266 -0
  98. data/assets/javascripts/ui/ui.slider.js +552 -0
  99. data/assets/javascripts/ui/ui.sortable.js +1012 -0
  100. data/assets/javascripts/ui/ui.tabs.js +572 -0
  101. data/assets/stylesheets/stuff_to_do.css +216 -0
  102. data/config/locales/bg.yml +18 -0
  103. data/config/locales/ca-fr.yml +18 -0
  104. data/config/locales/cs.yml +16 -0
  105. data/config/locales/da.yml +16 -0
  106. data/config/locales/de.yml +18 -0
  107. data/config/locales/en.yml +24 -0
  108. data/config/locales/es.yml +19 -0
  109. data/config/locales/fr.yml +17 -0
  110. data/config/locales/hu.yml +16 -0
  111. data/config/locales/it.yml +16 -0
  112. data/config/locales/ja.yml +18 -0
  113. data/config/locales/ko.yml +18 -0
  114. data/config/locales/lt.yml +18 -0
  115. data/config/locales/nl.yml +20 -0
  116. data/config/locales/pt-BR.yml +18 -0
  117. data/config/locales/ru.yml +19 -0
  118. data/config/locales/sv.yml +19 -0
  119. data/config/locales/tr.yml +18 -0
  120. data/config/routes.rb +3 -0
  121. data/init.rb +54 -0
  122. data/lang/bg.yml +17 -0
  123. data/lang/ca-fr.yml +17 -0
  124. data/lang/cs.yml +15 -0
  125. data/lang/da.yml +15 -0
  126. data/lang/de.yml +17 -0
  127. data/lang/en.yml +21 -0
  128. data/lang/es.yml +18 -0
  129. data/lang/fr.yml +16 -0
  130. data/lang/hu.yml +15 -0
  131. data/lang/it.yml +15 -0
  132. data/lang/ja.yml +17 -0
  133. data/lang/ko.yml +17 -0
  134. data/lang/lt.yml +17 -0
  135. data/lang/pt-br.yml +17 -0
  136. data/lang/ru.yml +15 -0
  137. data/lang/sv.yml +18 -0
  138. data/lang/tr.yml +17 -0
  139. data/lib/redmine_stuff_to_do/stuff_to_do_compatibility.rb +15 -0
  140. data/lib/stuff_to_do_array_patch.rb +8 -0
  141. data/lib/stuff_to_do_issue_patch.rb +57 -0
  142. data/lib/stuff_to_do_project_patch.rb +31 -0
  143. data/lib/stuff_to_do_user_patch.rb +10 -0
  144. data/rails/init.rb +1 -0
  145. data/spec/controllers/stuff_to_do_controller_add_to_time_grid_spec.rb +58 -0
  146. data/spec/controllers/stuff_to_do_controller_index_spec.rb +155 -0
  147. data/spec/controllers/stuff_to_do_controller_remove_from_time_grid_spec.rb +56 -0
  148. data/spec/controllers/stuff_to_do_controller_reorder_spec.rb +179 -0
  149. data/spec/controllers/stuff_to_do_controller_save_time_entries_spec.rb +56 -0
  150. data/spec/controllers/stuff_to_do_private_methods_spec.rb +82 -0
  151. data/spec/lib/stuff_to_do_issue_patch_spec.rb +60 -0
  152. data/spec/lib/stuff_to_do_project_patch_spec.rb +50 -0
  153. data/spec/lib/stuff_to_do_user_patch_spec.rb +8 -0
  154. data/spec/models/stuff_to_do_filter_spec.rb +3 -0
  155. data/spec/models/stuff_to_do_mailer_spec.rb +42 -0
  156. data/spec/models/stuff_to_do_spec.rb +426 -0
  157. data/spec/sanity_spec.rb +7 -0
  158. data/spec/spec_helper.rb +130 -0
  159. metadata +211 -0
@@ -0,0 +1,32 @@
1
+ class StuffToDoFilter
2
+ attr_accessor :users
3
+ attr_accessor :priorities
4
+ attr_accessor :statuses
5
+
6
+ def initialize
7
+ self.users = User.active
8
+ self.priorities = get_priorites
9
+ self.statuses = IssueStatus.find(:all)
10
+ end
11
+
12
+ def each
13
+ if StuffToDo.using_issues_as_items?
14
+ {
15
+ :users => self.users.sort,
16
+ :priorities => self.priorities.sort,
17
+ :statuses => self.statuses.sort
18
+ }.each do |group, items|
19
+ yield group, items
20
+ end
21
+ end
22
+
23
+ # Finally projects
24
+ yield :projects if StuffToDo.using_projects_as_items?
25
+ end
26
+
27
+ private
28
+ # Wrapper around Redmine's API since Enumerations changed in r2472
29
+ def get_priorites
30
+ RedmineStuffToDo::StuffToDoCompatibility::IssuePriority.all
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ class StuffToDoMailer < Mailer
2
+ def recommended_below_threshold(user, number_of_next_items)
3
+ recipients Setting.plugin_stuff_to_do_plugin['email_to'].split(',')
4
+ subject "What's Recommended is below the threshold"
5
+
6
+ body(
7
+ :threshold => Setting.plugin_stuff_to_do_plugin['threshold'],
8
+ :count => number_of_next_items,
9
+ :user => user
10
+ )
11
+
12
+ part :content_type => "text/plain", :body => render_message("recommended_below_threshold.erb", body)
13
+ part :content_type => "text/html", :body => render_message("recommended_below_threshold.text.html.rhtml", body)
14
+
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ <fieldset>
2
+ <legend><%= l(:stuff_to_do_label_project_manager_emails) %></legend>
3
+ <p>
4
+ <%= l(:stuff_to_do_text_settings) %>
5
+ </p>
6
+
7
+ <p>
8
+ <label><%= l(:stuff_to_do_label_threshold) %></label><%= text_field_tag 'settings[threshold]', @settings['threshold'] %>
9
+ </p>
10
+
11
+ <p>
12
+ <label><%= l(:stuff_to_do_label_email_to) %></label><%= text_field_tag 'settings[email_to]', @settings['email_to'] %>
13
+ </p>
14
+
15
+ </fieldset>
16
+
17
+ <p>
18
+ <label><%= l(:stuff_to_do_use_as_stuff_to_do) %></label>
19
+ <%= select_tag('settings[use_as_stuff_to_do]',
20
+ options_for_select(StuffToDo::USE.to_a, @settings['use_as_stuff_to_do'])) %>
21
+ </p>
22
+
23
+ <p>
24
+ <label><%= l(:stuff_to_do_use_time_grid) %></label>
25
+ <%= hidden_field_tag 'settings[use_time_grid]', 0 %>
26
+ <%= check_box_tag 'settings[use_time_grid]', 1, @settings['use_time_grid'].to_i == 1 %>
27
+ </p>
@@ -0,0 +1,16 @@
1
+ <li class="stuff-to-do-item <%= issue.css_classes if issue.respond_to?(:css_classes) %> <%= issue_counter.odd? ? "odd" : "even" %>" id="stuff_<%= issue.id %>">
2
+ <div class="issue-details">
3
+ <%= link_to(image_tag('ticket.png'), :controller => 'issues', :action => 'show', :id => issue) %>
4
+ #<%= h(issue.id) %>
5
+ - <%= h(issue.project.name) %> -
6
+ <%= h(issue.subject) %>
7
+ </div>
8
+
9
+ <% if issue.estimated_hours && issue.estimated_hours > 0 %>
10
+ <div class="estimate"><%= h(l_hours(issue.estimated_hours)) %> &nbsp;</div>
11
+ <% end %>
12
+
13
+ <div class="progress"><%= progress_bar(issue.done_ratio, :width => '100%') %></div>
14
+
15
+ <div style="clear:left;"></div>
16
+ </li>
@@ -0,0 +1,5 @@
1
+ <% if item.class == Issue %>
2
+ <%= render :partial => 'issue', :locals => {:issue_counter => item_counter}, :object => item %>
3
+ <% else %>
4
+ <%= render :partial => 'project', :locals => {:project_counter => item_counter}, :object => item %>
5
+ <% end %>
@@ -0,0 +1,51 @@
1
+
2
+ <div class="pane" id="doing-now-pane">
3
+ <h3>
4
+ <%= l(:stuff_to_do_what_im_doing_now) %>
5
+ <span class="subtitle"><%= l(:stuff_to_do_text_order_im_doing_it) %></span>
6
+ </h3>
7
+
8
+ <ol id="doing-now">
9
+ <% unless stuff_for(@doing_now).empty? %>
10
+ <%= render :partial => 'item', :collection => stuff_for(@doing_now) %>
11
+ <% else %>
12
+ <li class="empty-list">
13
+ <%= l(:stuff_to_do_drag_issue_create_list) %>
14
+ </li>
15
+ <% end %>
16
+ </ol>
17
+
18
+ <div class="pane-summary">
19
+ <div id="doing-now-total-progress">
20
+ <%= progress_bar_sum(issues_for(@doing_now), :done_ratio, { :width => '200px', :legend => l(:stuff_to_do_text_total_progress) }) %>
21
+ </div>
22
+
23
+ <div id="doing-now-estimates">
24
+ <p><%= l(:stuff_to_do_text_total_estimates) %> <%= l_hours(total_estimates(issues_for(@doing_now))) %></p>
25
+ </div>
26
+ </div>
27
+
28
+ </div>
29
+
30
+ <div class="pane" id="recommended-pane">
31
+ <h3>
32
+ <%= l(:stuff_to_do_what_is_recommended) %>
33
+ <span class="subtitle"><%= l(:stuff_to_do_text_by_project_manager) %></span>
34
+ </h3>
35
+
36
+ <ol id="recommended">
37
+ <%= render :partial => 'item', :collection => stuff_for(@recommended) %>
38
+ </ol>
39
+
40
+ <div class="pane-summary">
41
+ <div id="recommended-total-progress">
42
+ <%= progress_bar_sum(issues_for(@recommended), :done_ratio, { :width => '200px', :legend => l(:stuff_to_do_text_total_progress) }) %>
43
+ </div>
44
+
45
+ <div id="recommended-estimates">
46
+ <p><%= l(:stuff_to_do_text_total_estimates) %> <%= l_hours(total_estimates(issues_for(@recommended))) %></p>
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+
@@ -0,0 +1,11 @@
1
+ <div id="panes">
2
+
3
+ <div class="splitcontentleft">
4
+ <%= render :partial => 'left_panes' %>
5
+ </div>
6
+
7
+ <div class="splitcontentright">
8
+ <%= render :partial => 'right_panes' %>
9
+ </div>
10
+
11
+ </div>
@@ -0,0 +1,6 @@
1
+ <li class="stuff-to-do-item project <%= project_counter.odd? ? "odd" : "even" %>" id="stuff_project<%= project.id %>">
2
+ <div class="project-details">
3
+ <%= link_to(image_tag('package.png'), :controller => 'projects', :action => 'show', :id => project) %> <%= h project.name %>
4
+ </div>
5
+ <div style="clear:left;"></div>
6
+ </li>
@@ -0,0 +1,25 @@
1
+ <div class="pane" id="available-pane">
2
+ <h3><%= l(:stuff_to_do_what_is_available) %></h3>
3
+
4
+ <ol id="available">
5
+ <% unless @available.empty? %>
6
+ <%= render :partial => 'item', :collection => @available %>
7
+ <% else %>
8
+ <li class="empty-list">
9
+ <%= l(:stuff_to_do_drag_issue_remove_list) %>
10
+ </li>
11
+ <% end %>
12
+ </ol>
13
+
14
+ <div class="pane-summary">
15
+ <div id="available-total-progress">
16
+ <%= progress_bar_sum(@available, :done_ratio, { :width => '200px', :legend => l(:stuff_to_do_text_total_progress) }) %>
17
+ </div>
18
+
19
+ <div id="available-estimates">
20
+ <p><%= l(:stuff_to_do_text_total_estimates) %> <%= l_hours(total_estimates(@available)) %></p>
21
+ </div>
22
+ </div>
23
+
24
+ </div>
25
+ <%= javascript_tag("var filter = #{params[:filter].nil? ? 'null' : "'" + params[:filter].to_s + "'" }") %>
@@ -0,0 +1,113 @@
1
+ <div id="time-grid">
2
+ <h2><%= l(:stuff_to_do_time_grid) %></h2>
3
+
4
+ <div id="time-grid-error" class="flash error time-grid-flash" style="display:none"><%= h flash[:time_grid_error] %></div>
5
+ <div id="time-grid-warning" class="flash warning time-grid-flash" style="display:none"><%= h flash[:time_grid_warning] %></div>
6
+ <div id="time-grid-notice" class="flash notice time-grid-flash" style="display:none"><%= h flash[:time_grid_notice] %></div>
7
+
8
+ <%= render :partial => 'time_grid_form' %>
9
+
10
+ <%= submit_tag l(:button_save), :class => 'save-time-grid', :style => 'display:none;' %>
11
+
12
+ <table class="cal" id="time-grid-table">
13
+ <thead>
14
+ <tr>
15
+ <th class="time-grid-project"><%= l(:field_project) %></th>
16
+ <th class="time-grid-issue"><%= l(:field_issue) %></th>
17
+ <% day = @calendar.startdt
18
+ while day <= @calendar.enddt %>
19
+ <th class="time-grid-date">
20
+ <%= day_name(day.cwday) %>
21
+ <br />
22
+ <%= day.day %>
23
+ </th>
24
+ <% day = day + 1 %>
25
+ <% end %>
26
+ <th class="time-grid-running-total">Running Total</th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <% @issues.each do |issue| %>
31
+ <% content_tag_for(:tr, issue) do %>
32
+ <td class="time-grid-project">
33
+ <%= link_to(h(issue.project), :controller => 'projects', :action => 'show', :id => issue.project) %>
34
+ </td>
35
+ <td class="time-grid-issue">
36
+ <%= link_to("##{issue.id} " + h(issue.subject), :controller => 'issues', :action => 'show', :id => issue) %>
37
+ </td>
38
+ <% day = @calendar.startdt
39
+ while day <= @calendar.enddt %>
40
+ <td class="time-grid-date <%= h day -%> hascontextmenu">
41
+ <%= h total_hours_for_user_on_day(issue, User.current, day) %>
42
+ </td>
43
+ <% day = day + 1 %>
44
+ <% end %>
45
+ <td class="time-grid-running-total issue-<%= h issue.id -%>">
46
+ <%= h total_hours_for_issue_for_user(issue, User.current) %>
47
+ </td>
48
+ <% end %>
49
+ <% end %>
50
+ <tr class="daily-totals">
51
+ <td colspan="2" class="label">
52
+ Daily Totals
53
+ </td>
54
+ <% day = @calendar.startdt
55
+ while day <= @calendar.enddt %>
56
+ <td class="time-grid-date <%= h day -%> totals hascontextmenu">
57
+ <%= h total_hours_for_date(@issues, User.current, day) %>
58
+ </td>
59
+ <% day = day + 1 %>
60
+ <% end %>
61
+ <td class="time-grid-grand-total">
62
+ <%= h total_hours_for_user(@issues, User.current) %>
63
+ </td>
64
+ </tr>
65
+
66
+ </tbody>
67
+ </table>
68
+
69
+ <%= submit_tag l(:button_save), :class => 'save-time-grid', :style => 'display:none;' %>
70
+
71
+ </div>
72
+
73
+ <ul id="time-grid-menu" class="context-menu" style="display:none;">
74
+ <li>
75
+ <%= content_tag(:a, l(:button_log_time), :class => 'icon-time-add', :id => 'log-time', :href => '#logtime') %>
76
+ </li>
77
+ </ul>
78
+
79
+ <div id="logtime" style="display:none;">
80
+ <h2><%= l(:label_spent_time) %></h2>
81
+
82
+ <% labelled_tabular_form_for 'time_entry[]'.to_sym, @time_entry, :url => {}, :html => {:id => 'new-time-entry'} do |f| %>
83
+ <%= error_messages_for 'time_entry' %>
84
+ <%= back_url_hidden_field_tag %>
85
+
86
+ <div class="box">
87
+ <p><%= f.text_field :issue_id, :required => true, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p>
88
+ <p>
89
+ <%= f.text_field :spent_on, :size => 10, :required => true, :id => 'time_entry__core' %>
90
+ <% include_calendar_headers_tags %>
91
+ <%= image_tag("calendar.png", {:id => "time_entry__core_trigger",:class => "calendar-trigger"}) -%>
92
+ </p>
93
+ <p><%= f.text_field :hours, :size => 6, :required => true %></p>
94
+ <p><%= f.text_field :comments, :size => 100, :required => true %></p>
95
+ <p><%= f.select :activity_id, activity_collection_for_select_options, :required => true %></p>
96
+ <% @time_entry.custom_field_values.each do |value| %>
97
+ <p><%= custom_field_tag_with_label :time_entry, value %></p>
98
+ <% end %>
99
+ <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
100
+ </div>
101
+
102
+ <%= submit_tag l(:button_save) %>
103
+
104
+ <% end %>
105
+
106
+ </div>
107
+
108
+ <script type="text/javascript">
109
+ jQuery(function($) {
110
+ initTimeGrid();
111
+ attachSortables();
112
+ });
113
+ </script>
@@ -0,0 +1,32 @@
1
+ <% form_tag({:action => 'time_grid'}, :id => 'query_form') do %>
2
+ <fieldset id="date-range"><legend><%= l(:label_date_range) %></legend>
3
+ <%= select_month(@date.month, :prefix => "month", :discard_type => true) %>
4
+ <%= select_day(@date.day, :prefix => "day", :discard_type => true) %>
5
+ <%= select_year(@date.year, :prefix => "year", :discard_type => true) %>
6
+ </fieldset>
7
+
8
+ <p style="float:right; margin:0px;">
9
+ <%= link_to_remote("&#171; #{l(:label_previous)} #{l(:label_week).downcase}",
10
+ {:update => "time-grid", :url => { :action => 'time_grid', :date => @date - 7 }},
11
+ {:href => url_for(:action => 'time_grid', :date => @date - 7)})
12
+ %> |
13
+ <%= link_to_remote("#{l(:label_next)} #{l(:label_week).downcase} &#187;",
14
+ {:update => "time-grid", :url => { :action => 'time_grid', :date => @date + 7 }},
15
+ {:href => url_for(:action => 'time_grid', :date => @date + 7)})
16
+ %>
17
+ </p>
18
+
19
+ <p class="buttons">
20
+ <%= link_to_remote l(:button_apply),
21
+ { :url => { :action => 'time_grid' },
22
+ :update => "time-grid",
23
+ :with => "Form.serialize('query_form')"
24
+ }, :class => 'icon icon-checked' %>
25
+
26
+ <%= link_to_remote l(:button_clear),
27
+ { :url => { :action => 'time_grid' },
28
+ :update => "time-grid",
29
+ }, :class => 'icon icon-reload' %>
30
+ </p>
31
+ <% end %>
32
+
@@ -0,0 +1,44 @@
1
+ <% html_title(l(:stuff_to_do_title)) %>
2
+ <h1><%= l(:stuff_to_do_title) %></h1>
3
+
4
+ <div id="stuff-to-do-error" class="flash error" style="display:none">
5
+
6
+ </div>
7
+
8
+ <div class="menu">
9
+ <% if User.current.admin? %>
10
+ <div class="user">
11
+ <% form_tag({ :controller => 'stuff_to_do', :action => 'index'}, :method => :get, :id => 'user_switch' ) do %>
12
+ <label for="user_id"><%= l(:stuff_to_do_label_view_user_list) %></label>
13
+ <%= collection_select(:user, :id, @users.sort, :id, :name, { }, { :name => 'user_id'}) %>
14
+ <% end %>
15
+ </div>
16
+
17
+ <div class="filter">
18
+ <% form_tag({}, :id => 'filter_form') do %>
19
+ <label for="filter"><%= l(:stuff_to_do_label_filter) %></label>
20
+ <%= select_tag("filter", filter_options(@filters, params[:filter])) %>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
24
+ </div>
25
+ <div style="clear:right;"></div>
26
+
27
+ <%= render :partial => 'panes' %>
28
+
29
+ <div style="clear:both;"></div>
30
+
31
+ <%= render :partial => 'time_grid' if !Setting.plugin_stuff_to_do_plugin['use_time_grid'].blank? && Setting.plugin_stuff_to_do_plugin['use_time_grid'] != "0" %>
32
+
33
+ <% content_for :header_tags do %>
34
+ <%= stylesheet_link_tag "stuff_to_do.css", :plugin => "stuff_to_do_plugin", :media => 'all' %>
35
+ <%= javascript_include_tag 'jquery-1.2.6.min.js', :plugin => 'stuff_to_do_plugin' %>
36
+ <%= javascript_include_tag 'ui/ui.core.js', :plugin => 'stuff_to_do_plugin' %>
37
+ <%= javascript_include_tag 'ui/ui.sortable.js', :plugin => 'stuff_to_do_plugin' %>
38
+ <%= javascript_include_tag 'jquery.contextMenu.js', :plugin => 'stuff_to_do_plugin' %>
39
+ <%= javascript_include_tag 'facebox.js', :plugin => 'stuff_to_do_plugin' %>
40
+ <%= javascript_tag("jQuery.noConflict();") %>
41
+ <%= javascript_include_tag 'stuff-to-do.js', :plugin => 'stuff_to_do_plugin' %>
42
+ <%= javascript_tag("var user_id = #{@user.id};") %>
43
+ <%= javascript_tag "window._token = '#{form_authenticity_token}'" %>
44
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= @user.name %> has only <%= @count %> recommended items left in their Stuff To Do which is below the threshold of <%= @threshold %>.
2
+
3
+ <%= url_for :controller => 'stuff_to_do', :action => 'index', :user_id => @user.id, :only_path => false %>
@@ -0,0 +1 @@
1
+ <%= link_to @user.name, :controller => 'stuff_to_do', :action => 'index', :user_id => @user.id, :only_path => false %> has only <%= @count %> recommended items left in their <%= link_to "Stuff to Do", :controller => 'stuff_to_do', :action => 'index', :user_id => @user.id, :only_path => false %> which is below the threshold of <%= @threshold %>.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,319 @@
1
+ /*
2
+ * Facebox (for jQuery)
3
+ * version: 1.2 (05/05/2008)
4
+ * @requires jQuery v1.2 or later
5
+ *
6
+ * Examples at http://famspam.com/facebox/
7
+ *
8
+ * Licensed under the MIT:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
12
+ *
13
+ * Usage:
14
+ *
15
+ * jQuery(document).ready(function() {
16
+ * jQuery('a[rel*=facebox]').facebox()
17
+ * })
18
+ *
19
+ * <a href="#terms" rel="facebox">Terms</a>
20
+ * Loads the #terms div in the box
21
+ *
22
+ * <a href="terms.html" rel="facebox">Terms</a>
23
+ * Loads the terms.html page in the box
24
+ *
25
+ * <a href="terms.png" rel="facebox">Terms</a>
26
+ * Loads the terms.png image in the box
27
+ *
28
+ *
29
+ * You can also use it programmatically:
30
+ *
31
+ * jQuery.facebox('some html')
32
+ *
33
+ * The above will open a facebox with "some html" as the content.
34
+ *
35
+ * jQuery.facebox(function($) {
36
+ * $.get('blah.html', function(data) { $.facebox(data) })
37
+ * })
38
+ *
39
+ * The above will show a loading screen before the passed function is called,
40
+ * allowing for a better ajaxy experience.
41
+ *
42
+ * The facebox function can also display an ajax page or image:
43
+ *
44
+ * jQuery.facebox({ ajax: 'remote.html' })
45
+ * jQuery.facebox({ image: 'dude.jpg' })
46
+ *
47
+ * Want to close the facebox? Trigger the 'close.facebox' document event:
48
+ *
49
+ * jQuery(document).trigger('close.facebox')
50
+ *
51
+ * Facebox also has a bunch of other hooks:
52
+ *
53
+ * loading.facebox
54
+ * beforeReveal.facebox
55
+ * reveal.facebox (aliased as 'afterReveal.facebox')
56
+ * init.facebox
57
+ *
58
+ * Simply bind a function to any of these hooks:
59
+ *
60
+ * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
61
+ *
62
+ */
63
+ (function($) {
64
+ $.facebox = function(data, klass) {
65
+ $.facebox.loading()
66
+
67
+ if (data.ajax) fillFaceboxFromAjax(data.ajax)
68
+ else if (data.image) fillFaceboxFromImage(data.image)
69
+ else if (data.div) fillFaceboxFromHref(data.div)
70
+ else if ($.isFunction(data)) data.call($)
71
+ else $.facebox.reveal(data, klass)
72
+ }
73
+
74
+ /*
75
+ * Public, $.facebox methods
76
+ */
77
+
78
+ $.extend($.facebox, {
79
+ settings: {
80
+ opacity : 0,
81
+ overlay : true,
82
+ loadingImage : '/facebox/loading.gif',
83
+ closeImage : '/facebox/closelabel.gif',
84
+ imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ],
85
+ faceboxHtml : '\
86
+ <div id="facebox" style="display:none;"> \
87
+ <div class="popup"> \
88
+ <table> \
89
+ <tbody> \
90
+ <tr> \
91
+ <td class="tl"/><td class="b"/><td class="tr"/> \
92
+ </tr> \
93
+ <tr> \
94
+ <td class="b"/> \
95
+ <td class="body"> \
96
+ <div class="content"> \
97
+ </div> \
98
+ <div class="footer"> \
99
+ <a href="#" class="close"> \
100
+ <img src="/facebox/closelabel.gif" title="close" class="close_image" /> \
101
+ </a> \
102
+ </div> \
103
+ </td> \
104
+ <td class="b"/> \
105
+ </tr> \
106
+ <tr> \
107
+ <td class="bl"/><td class="b"/><td class="br"/> \
108
+ </tr> \
109
+ </tbody> \
110
+ </table> \
111
+ </div> \
112
+ </div>'
113
+ },
114
+
115
+ loading: function() {
116
+ init()
117
+ if ($('#facebox .loading').length == 1) return true
118
+ showOverlay()
119
+
120
+ $('#facebox .content').empty()
121
+ $('#facebox .body').children().hide().end().
122
+ append('<div class="loading"><img src="'+$.facebox.settings.loadingImage+'"/></div>')
123
+
124
+ $('#facebox').css({
125
+ top: getPageScroll()[1] + (getPageHeight() / 10),
126
+ left: 385.5
127
+ }).show()
128
+
129
+ $(document).bind('keydown.facebox', function(e) {
130
+ if (e.keyCode == 27) $.facebox.close()
131
+ return true
132
+ })
133
+ $(document).trigger('loading.facebox')
134
+ },
135
+
136
+ reveal: function(data, klass) {
137
+ $(document).trigger('beforeReveal.facebox')
138
+ if (klass) $('#facebox .content').addClass(klass)
139
+ $('#facebox .content').append(data)
140
+ $('#facebox .loading').remove()
141
+ $('#facebox .body').children().fadeIn('normal')
142
+ $('#facebox').css('left', $(window).width() / 2 - ($('#facebox table').width() / 2))
143
+ $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
144
+ },
145
+
146
+ close: function() {
147
+ $(document).trigger('close.facebox')
148
+ return false
149
+ }
150
+ })
151
+
152
+ /*
153
+ * Public, $.fn methods
154
+ */
155
+
156
+ $.fn.facebox = function(settings) {
157
+ init(settings)
158
+
159
+ function clickHandler() {
160
+ $.facebox.loading(true)
161
+
162
+ // support for rel="facebox.inline_popup" syntax, to add a class
163
+ // also supports deprecated "facebox[.inline_popup]" syntax
164
+ var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
165
+ if (klass) klass = klass[1]
166
+
167
+ fillFaceboxFromHref(this.href, klass)
168
+ return false
169
+ }
170
+
171
+ return this.click(clickHandler)
172
+ }
173
+
174
+ /*
175
+ * Private methods
176
+ */
177
+
178
+ // called one time to setup facebox on this page
179
+ function init(settings) {
180
+ if ($.facebox.settings.inited) return true
181
+ else $.facebox.settings.inited = true
182
+
183
+ $(document).trigger('init.facebox')
184
+ makeCompatible()
185
+
186
+ var imageTypes = $.facebox.settings.imageTypes.join('|')
187
+ $.facebox.settings.imageTypesRegexp = new RegExp('\.' + imageTypes + '$', 'i')
188
+
189
+ if (settings) $.extend($.facebox.settings, settings)
190
+ $('body').append($.facebox.settings.faceboxHtml)
191
+
192
+ var preload = [ new Image(), new Image() ]
193
+ preload[0].src = $.facebox.settings.closeImage
194
+ preload[1].src = $.facebox.settings.loadingImage
195
+
196
+ $('#facebox').find('.b:first, .bl, .br, .tl, .tr').each(function() {
197
+ preload.push(new Image())
198
+ preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
199
+ })
200
+
201
+ $('#facebox .close').click($.facebox.close)
202
+ $('#facebox .close_image').attr('src', $.facebox.settings.closeImage)
203
+ }
204
+
205
+ // getPageScroll() by quirksmode.com
206
+ function getPageScroll() {
207
+ var xScroll, yScroll;
208
+ if (self.pageYOffset) {
209
+ yScroll = self.pageYOffset;
210
+ xScroll = self.pageXOffset;
211
+ } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
212
+ yScroll = document.documentElement.scrollTop;
213
+ xScroll = document.documentElement.scrollLeft;
214
+ } else if (document.body) {// all other Explorers
215
+ yScroll = document.body.scrollTop;
216
+ xScroll = document.body.scrollLeft;
217
+ }
218
+ return new Array(xScroll,yScroll)
219
+ }
220
+
221
+ // Adapted from getPageSize() by quirksmode.com
222
+ function getPageHeight() {
223
+ var windowHeight
224
+ if (self.innerHeight) { // all except Explorer
225
+ windowHeight = self.innerHeight;
226
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
227
+ windowHeight = document.documentElement.clientHeight;
228
+ } else if (document.body) { // other Explorers
229
+ windowHeight = document.body.clientHeight;
230
+ }
231
+ return windowHeight
232
+ }
233
+
234
+ // Backwards compatibility
235
+ function makeCompatible() {
236
+ var $s = $.facebox.settings
237
+
238
+ $s.loadingImage = $s.loading_image || $s.loadingImage
239
+ $s.closeImage = $s.close_image || $s.closeImage
240
+ $s.imageTypes = $s.image_types || $s.imageTypes
241
+ $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
242
+ }
243
+
244
+ // Figures out what you want to display and displays it
245
+ // formats are:
246
+ // div: #id
247
+ // image: blah.extension
248
+ // ajax: anything else
249
+ function fillFaceboxFromHref(href, klass) {
250
+ // div
251
+ if (href.match(/#/)) {
252
+ var url = window.location.href.split('#')[0]
253
+ var target = href.replace(url,'')
254
+ $.facebox.reveal($(target).clone().show(), klass)
255
+
256
+ // image
257
+ } else if (href.match($.facebox.settings.imageTypesRegexp)) {
258
+ fillFaceboxFromImage(href, klass)
259
+ // ajax
260
+ } else {
261
+ fillFaceboxFromAjax(href, klass)
262
+ }
263
+ }
264
+
265
+ function fillFaceboxFromImage(href, klass) {
266
+ var image = new Image()
267
+ image.onload = function() {
268
+ $.facebox.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
269
+ }
270
+ image.src = href
271
+ }
272
+
273
+ function fillFaceboxFromAjax(href, klass) {
274
+ $.get(href, function(data) { $.facebox.reveal(data, klass) })
275
+ }
276
+
277
+ function skipOverlay() {
278
+ return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null
279
+ }
280
+
281
+ function showOverlay() {
282
+ if (skipOverlay()) return
283
+
284
+ if ($('facebox_overlay').length == 0)
285
+ $("body").append('<div id="facebox_overlay" class="facebox_hide"></div>')
286
+
287
+ $('#facebox_overlay').hide().addClass("facebox_overlayBG")
288
+ .css('opacity', $.facebox.settings.opacity)
289
+ .click(function() { $(document).trigger('close.facebox') })
290
+ .fadeIn(200)
291
+ return false
292
+ }
293
+
294
+ function hideOverlay() {
295
+ if (skipOverlay()) return
296
+
297
+ $('#facebox_overlay').fadeOut(200, function(){
298
+ $("#facebox_overlay").removeClass("facebox_overlayBG")
299
+ $("#facebox_overlay").addClass("facebox_hide")
300
+ $("#facebox_overlay").remove()
301
+ })
302
+
303
+ return false
304
+ }
305
+
306
+ /*
307
+ * Bindings
308
+ */
309
+
310
+ $(document).bind('close.facebox', function() {
311
+ $(document).unbind('keydown.facebox')
312
+ $('#facebox').fadeOut(function() {
313
+ $('#facebox .content').removeClass().addClass('content')
314
+ hideOverlay()
315
+ $('#facebox .loading').remove()
316
+ })
317
+ })
318
+
319
+ })(jQuery);