From ec51cdd0f9926d0fe42e9563e0f5bf1a3db18196 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 7 Oct 2007 20:07:11 +0000 Subject: [PATCH] Calendar: * added an helper and moved the rendering code to a shared partial (used by project calendar and my calendar) * first day of week can now be set in lang files (general_first_day_of_week) git-svn-id: http://redmine.rubyforge.org/svn/trunk@815 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/my_controller.rb | 2 + app/controllers/projects_controller.rb | 22 +++----- app/views/common/_calendar.rhtml | 36 ++++++++++++ app/views/my/blocks/_calendar.rhtml | 49 ++--------------- app/views/projects/calendar.rhtml | 50 +---------------- lang/bg.yml | 1 + lang/cs.yml | 1 + lang/de.yml | 1 + lang/en.yml | 1 + lang/es.yml | 1 + lang/fr.yml | 1 + lang/it.yml | 1 + lang/ja.yml | 1 + lang/nl.yml | 1 + lang/pl.yml | 1 + lang/pt-br.yml | 1 + lang/pt.yml | 1 + lang/ro.yml | 1 + lang/sv.yml | 1 + lang/zh.yml | 1 + lib/redmine/helpers/calendar.rb | 76 ++++++++++++++++++++++++++ public/stylesheets/application.css | 7 ++- test/unit/calendar_test.rb | 43 +++++++++++++++ 23 files changed, 191 insertions(+), 109 deletions(-) create mode 100644 app/views/common/_calendar.rhtml create mode 100644 lib/redmine/helpers/calendar.rb create mode 100644 test/unit/calendar_test.rb 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 - - @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) + @month ||= Date.today.month + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) - @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| %><% end %> + + + +<% day = calendar.startdt +while day <= calendar.enddt %> +<%= "" if day.cwday == calendar.first_wday %> + +<%= '' if day.cwday==calendar.last_wday and day!=calendar.enddt %> +<% day = day + 1 +end %> + + +
<%= day_name( (calendar.first_wday+i)%7 ) %>
#{day.cweek} +

<%= 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 %> +
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| %> - -<% end %> - - - -<% day = @date_from -while day <= @date_to - if day.cwday == 1 %> - - <% end %> - - <%= '' if day.cwday >= 7 and day!=@date_to %> - <% - day = day + 1 -end %> - - -
<%= day_name(d) %>
<%= day.cweek %>"> -

<%= 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 %> -
\ 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| %> - -<% end %> - - - - -<% day = @date_from -while day <= @date_to - if day.cwday == 1 %> - - <% end %> - - <%= '' if day.cwday >= 7 and day!=@date_to %> - <% - day = day + 1 -end %> - - -
<%= day_name(d) %>
<%= day.cweek %> <%= 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 %> -
+<%= 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 -- 2.39.5