diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb
index 11aa7f1d0..bbb3a6e22 100644
--- a/app/controllers/my_controller.rb
+++ b/app/controllers/my_controller.rb
@@ -16,6 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class MyController < ApplicationController
+ helper :issues
+
layout 'base'
before_filter :require_login
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index d2d132458..cf1325518 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -512,26 +512,18 @@ class ProjectsController < ApplicationController
end
end
@year ||= Date.today.year
- @month ||= Date.today.month
+ @month ||= Date.today.month
+ @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month)
- @date_from = Date.civil(@year, @month, 1)
- @date_to = (@date_from >> 1)-1
- # start on monday
- @date_from = @date_from - (@date_from.cwday-1)
- # finish on sunday
- @date_to = @date_to + (7-@date_to.cwday)
-
- @events = []
+ events = []
@project.issues_with_subprojects(params[:with_subprojects]) do
- @events += Issue.find(:all,
+ events += Issue.find(:all,
:include => [:tracker, :status, :assigned_to, :priority, :project],
- :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)) and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')})", @date_from, @date_to, @date_from, @date_to]
+ :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt]
) unless @selected_tracker_ids.empty?
end
- @events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
-
- @ending_events_by_days = @events.group_by {|event| event.due_date}
- @starting_events_by_days = @events.group_by {|event| event.start_date}
+ events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])
+ @calendar.events = events
render :layout => false if request.xhr?
end
diff --git a/app/views/common/_calendar.rhtml b/app/views/common/_calendar.rhtml
new file mode 100644
index 000000000..7534a1223
--- /dev/null
+++ b/app/views/common/_calendar.rhtml
@@ -0,0 +1,36 @@
+
+
+ | <% 7.times do |i| %><%= day_name( (calendar.first_wday+i)%7 ) %> | <% end %>
+
+
+
+<% day = calendar.startdt
+while day <= calendar.enddt %>
+<%= "#{day.cweek} | " if day.cwday == calendar.first_wday %>
+
+ <%= day.day %>
+<% calendar.events_on(day).each do |i| %>
+ <% if i.is_a? Issue %>
+
+ <%= if day == i.start_date && day == i.due_date
+ image_tag('arrow_bw.png')
+ elsif day == i.start_date
+ image_tag('arrow_from.png')
+ elsif day == i.due_date
+ image_tag('arrow_to.png')
+ end %>
+ <%= h("#{i.project.name} -") unless @project && @project == i.project %>
+ <%= link_to_issue i %>: <%= h(truncate(i.subject, 30)) %>
+ <%= render_issue_tooltip i %>
+
+ <% else %>
+ <%= link_to_version i, :class => "icon icon-package" %>
+ <% end %>
+<% end %>
+ |
+<%= '
' if day.cwday==calendar.last_wday and day!=calendar.enddt %>
+<% day = day + 1
+end %>
+
+
+
diff --git a/app/views/my/blocks/_calendar.rhtml b/app/views/my/blocks/_calendar.rhtml
index a2d556d90..bad729363 100644
--- a/app/views/my/blocks/_calendar.rhtml
+++ b/app/views/my/blocks/_calendar.rhtml
@@ -1,47 +1,8 @@
<%= l(:label_calendar) %>
-<%
-@date_from = Date.today - (Date.today.cwday-1)
-@date_to = Date.today + (7-Date.today.cwday)
-@issues = Issue.find :all,
- :conditions => ["#{Issue.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to],
- :include => [:project, :tracker] unless @user.projects.empty?
-@issues ||= []
-%>
+<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week)
+ calendar.events = Issue.find :all,
+ :conditions => ["#{Issue.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", calendar.startdt, calendar.enddt, calendar.startdt, calendar.enddt],
+ :include => [:project, :tracker, :priority, :assigned_to] unless @user.projects.empty? %>
-
-
- |
-<% 1.upto(7) do |d| %>
- <%= day_name(d) %> |
-<% end %>
-
-
-
-<% day = @date_from
-while day <= @date_to
- if day.cwday == 1 %>
- <%= day.cweek %> |
- <% end %>
- ">
- <%= day==Date.today ? "#{day.day}" : day.day %>
- <% day_issues = []
- @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day }
- day_issues.each do |i| %>
- <%= if day == i.start_date and day == i.due_date
- image_tag('arrow_bw.png')
- elsif day == i.start_date
- image_tag('arrow_from.png')
- elsif day == i.due_date
- image_tag('arrow_to.png')
- end %>
- <%= link_to_issue i %>: <%=h i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
- <% end %>
- |
- <%= '
' if day.cwday >= 7 and day!=@date_to %>
- <%
- day = day + 1
-end %>
-
-
-
\ No newline at end of file
+<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %>
diff --git a/app/views/projects/calendar.rhtml b/app/views/projects/calendar.rhtml
index b6f2958f3..2c02d59ad 100644
--- a/app/views/projects/calendar.rhtml
+++ b/app/views/projects/calendar.rhtml
@@ -15,55 +15,7 @@
-
-
-
- |
-<% 1.upto(7) do |d| %>
- <%= day_name(d) %> |
-<% end %>
-
-
-
-
-<% day = @date_from
-while day <= @date_to
- if day.cwday == 1 %>
- <%= day.cweek %> |
- <% end %>
- <%= Date.today == day ? 'today' : '' %>" style="width:14%;">
- <%= day==Date.today ? "#{day.day}" : day.day %>
- <% ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq.each do |i| %>
- <% if i.is_a? Issue %>
-
- <%= if day == i.start_date and day == i.due_date
- image_tag('arrow_bw.png')
- elsif day == i.start_date
- image_tag('arrow_from.png')
- elsif day == i.due_date
- image_tag('arrow_to.png')
- end %>
-
- <%= h("#{i.project.name} -") unless @project && @project == i.project %>
- <%= link_to_issue i %>:
- <%= h(truncate(i.subject, 30)) %>
-
-
- <%= render_issue_tooltip i %>
-
-
- <% else %>
- <%= link_to_version i, :class => "icon icon-package" %>
- <% end %>
- <% end %>
- |
- <%= '
' if day.cwday >= 7 and day!=@date_to %>
- <%
- day = day + 1
-end %>
-
-
-
+<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %>
<%= image_tag 'arrow_from.png' %> <%= l(:text_tip_task_begin_day) %>
<%= image_tag 'arrow_to.png' %> <%= l(:text_tip_task_end_day) %>
diff --git a/lang/bg.yml b/lang/bg.yml
index fe9efff09..12a5378d6 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Понеделник,Вторник,Сряда,Четвъртък,Петък,Събота,Неделя
+general_first_day_of_week: '1'
notice_account_updated: Профилът е обновен успешно.
notice_account_invalid_creditentials: Невалиден потребител или парола.
diff --git a/lang/cs.yml b/lang/cs.yml
index abf1f6e5a..078f824f6 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: UTF-8
general_pdf_encoding: UTF-8
general_day_names: Pondělí,Úterý,Středa,Čtvrtek,Pátek,Sobota,Neděle
+general_first_day_of_week: '1'
notice_account_updated: Účet byl úspěšně změněn.
notice_account_invalid_creditentials: Chybné jméno nebo heslo
diff --git a/lang/de.yml b/lang/de.yml
index 8345d99d4..470785579 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -51,6 +51,7 @@ general_csv_separator: ';'
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag
+general_first_day_of_week: '1'
notice_account_updated: Konto wurde erfolgreich aktualisiert.
notice_account_invalid_creditentials: Benutzer oder Kennwort unzulässig
diff --git a/lang/en.yml b/lang/en.yml
index 34e49565f..79e8f61d8 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
+general_first_day_of_week: '7'
notice_account_updated: Account was successfully updated.
notice_account_invalid_creditentials: Invalid user or password
diff --git a/lang/es.yml b/lang/es.yml
index 12a6518a2..2e8e6efbc 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -51,6 +51,7 @@ general_csv_separator: ';'
general_csv_encoding: ISO-8859-15
general_pdf_encoding: ISO-8859-15
general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo
+general_first_day_of_week: '1'
notice_account_updated: Cuenta creada correctamente.
notice_account_invalid_creditentials: Inválido usuario o contraseña
diff --git a/lang/fr.yml b/lang/fr.yml
index 566f6573a..bb875288e 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -51,6 +51,7 @@ general_csv_separator: ';'
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche
+general_first_day_of_week: '1'
notice_account_updated: Le compte a été mis à jour avec succès.
notice_account_invalid_creditentials: Identifiant ou mot de passe invalide.
diff --git a/lang/it.yml b/lang/it.yml
index 2d0e0a1d0..4d114b15e 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Lunedì,Martedì,Mercoledì,Giovedì,Venerdì,Sabato,Domenica
+general_first_day_of_week: '1'
notice_account_updated: L'utenza è stata aggiornata.
notice_account_invalid_creditentials: Nome utente o password non validi.
diff --git a/lang/ja.yml b/lang/ja.yml
index c19199c4b..433320aa1 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -52,6 +52,7 @@ general_csv_separator: ','
general_csv_encoding: SJIS
general_pdf_encoding: SJIS
general_day_names: 月曜日,火曜日,水曜日,木曜日,金曜日,土曜日,日曜日
+general_first_day_of_week: '7'
notice_account_updated: アカウントが更新されました。
notice_account_invalid_creditentials: ユーザ名もしくはパスワードが無効
diff --git a/lang/nl.yml b/lang/nl.yml
index 19c6a0de0..7e252d9d1 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Maandag, Dinsdag, Woensdag, Donderdag, Vrijdag, Zaterdag, Zondag
+general_first_day_of_week: '7'
notice_account_updated: Account is met succes gewijzigd
notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord
diff --git a/lang/pl.yml b/lang/pl.yml
index 9b0af1fda..4db0d6761 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-2
general_pdf_encoding: ISO-8859-2
general_day_names: Poniedziałek,Wtorek,Środa,Czwartek,Piątek,Sobota,Niedziela
+general_first_day_of_week: '1'
notice_account_updated: Konto prawidłowo zaktualizowane.
notice_account_invalid_creditentials: Zły użytkownik lub hasło
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index b278edc58..59a5e1ccb 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Segunda,Terca,Quarta,Quinta,Sexta,Sabado,Domingo
+general_first_day_of_week: '1'
notice_account_updated: Conta foi alterada com sucesso.
notice_account_invalid_creditentials: Usuario ou senha invalido.
diff --git a/lang/pt.yml b/lang/pt.yml
index da75aa99c..b4e4a0cbd 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Segunda,Terça,Quarta,Quinta,Sexta,Sábado,Domingo
+general_first_day_of_week: '1'
notice_account_updated: Conta foi atualizada com sucesso.
notice_account_invalid_creditentials: Usuário ou senha inválidos.
diff --git a/lang/ro.yml b/lang/ro.yml
index 996df529d..25c488709 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Luni,Marti,Miercuri,Joi,Vineri,Sambata,Duminica
+general_first_day_of_week: '7'
notice_account_updated: Contul a fost creat cu succes.
notice_account_invalid_creditentials: Numele utilizator sau parola este invalida.
diff --git a/lang/sv.yml b/lang/sv.yml
index a457ca11a..e59e9233e 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -51,6 +51,7 @@ general_csv_separator: ','
general_csv_encoding: ISO-8859-1
general_pdf_encoding: ISO-8859-1
general_day_names: Måndag,Tisdag,Onsdag,Torsdag,Fredag,Lördag,Söndag
+general_first_day_of_week: '7'
notice_account_updated: Kontot har uppdaterats
notice_account_invalid_creditentials: Fel användarnamn eller lösenord
diff --git a/lang/zh.yml b/lang/zh.yml
index ff0e12529..b881ee4df 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -54,6 +54,7 @@ general_csv_separator: ','
general_csv_encoding: gb2312
general_pdf_encoding: Big5
general_day_names: 一,二,三,四,五,六,日
+general_first_day_of_week: '7'
notice_account_updated: 帐户更新成功。
notice_account_invalid_creditentials: 用户名或密码不正确
diff --git a/lib/redmine/helpers/calendar.rb b/lib/redmine/helpers/calendar.rb
new file mode 100644
index 000000000..347f1c5b5
--- /dev/null
+++ b/lib/redmine/helpers/calendar.rb
@@ -0,0 +1,76 @@
+# redMine - project management software
+# Copyright (C) 2006-2007 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module Helpers
+
+ # Simple class to compute the start and end dates of a calendar
+ class Calendar
+ include GLoc
+ attr_reader :startdt, :enddt
+
+ def initialize(date, lang = current_language, period = :month)
+ @date = date
+ @events = []
+ @ending_events_by_days = {}
+ @starting_events_by_days = {}
+ set_language lang
+ case period
+ when :month
+ @startdt = Date.civil(date.year, date.month, 1)
+ @enddt = (@startdt >> 1)-1
+ # starts from the first day of the week
+ @startdt = @startdt - (@startdt.cwday - first_wday)%7
+ # ends on the last day of the week
+ @enddt = @enddt + (last_wday - @enddt.cwday)%7
+ when :week
+ @startdt = date - (date.cwday - first_wday)%7
+ @enddt = date + (last_wday - date.cwday)%7
+ else
+ raise 'Invalid period'
+ end
+ end
+
+ # Sets calendar events
+ def events=(events)
+ @events = events
+ @ending_events_by_days = @events.group_by {|event| event.due_date}
+ @starting_events_by_days = @events.group_by {|event| event.start_date}
+ end
+
+ # Returns events for the given day
+ def events_on(day)
+ ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq
+ end
+
+ # Calendar current month
+ def month
+ @date.month
+ end
+
+ # Return the first day of week
+ # 1 = Monday ... 7 = Sunday
+ def first_wday
+ @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1
+ end
+
+ def last_wday
+ @last_dow ||= (first_wday + 5)%7 + 1
+ end
+ end
+ end
+end
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index fdeec2bbc..9bae7bcd9 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -212,9 +212,14 @@ vertical-align: bottom;
/***** Calendar *****/
table.cal {border-collapse: collapse; width: 100%; margin: 8px 0 6px 0;border: 1px solid #d7d7d7;}
+table.cal thead th {width: 14%;}
+table.cal tbody tr {height: 100px;}
table.cal th { background-color:#EEEEEE; padding: 4px; }
-table.cal td {border: 1px solid #d7d7d7;}
+table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
+table.cal td p.day-num {font-size: 1.1em; text-align:right;}
+table.cal td.odd p.day-num {color: #bbb;}
table.cal td.today {background:#ffffdd;}
+table.cal td.today p.day-num {font-weight: bold;}
/***** Tooltips ******/
.tooltip{position:relative;z-index:24;}
diff --git a/test/unit/calendar_test.rb b/test/unit/calendar_test.rb
new file mode 100644
index 000000000..98d856921
--- /dev/null
+++ b/test/unit/calendar_test.rb
@@ -0,0 +1,43 @@
+# redMine - project management software
+# Copyright (C) 2006-2007 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class CalendarTest < Test::Unit::TestCase
+
+ def test_monthly
+ c = Redmine::Helpers::Calendar.new(Date.today, :fr, :month)
+ assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday]
+
+ c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :month)
+ assert_equal ['2007-06-25'.to_date, '2007-08-05'.to_date], [c.startdt, c.enddt]
+
+ c = Redmine::Helpers::Calendar.new(Date.today, :en, :month)
+ assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday]
+ end
+
+ def test_weekly
+ c = Redmine::Helpers::Calendar.new(Date.today, :fr, :week)
+ assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday]
+
+ c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :week)
+ assert_equal ['2007-07-09'.to_date, '2007-07-15'.to_date], [c.startdt, c.enddt]
+
+ c = Redmine::Helpers::Calendar.new(Date.today, :en, :week)
+ assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday]
+ end
+end