]> source.dussan.org Git - redmine.git/commitdiff
Calendar:
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 7 Oct 2007 20:07:11 +0000 (20:07 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 7 Oct 2007 20:07:11 +0000 (20:07 +0000)
* 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

23 files changed:
app/controllers/my_controller.rb
app/controllers/projects_controller.rb
app/views/common/_calendar.rhtml [new file with mode: 0644]
app/views/my/blocks/_calendar.rhtml
app/views/projects/calendar.rhtml
lang/bg.yml
lang/cs.yml
lang/de.yml
lang/en.yml
lang/es.yml
lang/fr.yml
lang/it.yml
lang/ja.yml
lang/nl.yml
lang/pl.yml
lang/pt-br.yml
lang/pt.yml
lang/ro.yml
lang/sv.yml
lang/zh.yml
lib/redmine/helpers/calendar.rb [new file with mode: 0644]
public/stylesheets/application.css
test/unit/calendar_test.rb [new file with mode: 0644]

index 11aa7f1d04172f583b1967064b7be7e85350368d..bbb3a6e227cf60fe4acc78a25878b61f5c3b9784 100644 (file)
@@ -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
 
index d2d132458e06fe90e64d65d6d662722701685fb2..cf132551841c1ef54de9ef4fe05d4c3a11718e5d 100644 (file)
@@ -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 (file)
index 0000000..7534a12
--- /dev/null
@@ -0,0 +1,36 @@
+<table class="cal">
+<thead>
+<tr><td></td><% 7.times do |i| %><th><%= day_name( (calendar.first_wday+i)%7 ) %></th><% end %></tr>
+</thead>
+<tbody>
+<tr>
+<% day = calendar.startdt
+while day <= calendar.enddt %>
+<%= "<th>#{day.cweek}</th>" if day.cwday == calendar.first_wday %>
+<td class="<%= day.month==calendar.month ? 'even' : 'odd' %><%= ' today' if Date.today == day %>">
+<p class="day-num"><%= day.day %></p>  
+<% calendar.events_on(day).each do |i| %>
+  <% if i.is_a? Issue %>
+  <div class="tooltip">
+  <%= 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)) %>
+  <span class="tip"><%= render_issue_tooltip i %></span>
+  </div>
+  <% else %>
+  <%= link_to_version i, :class => "icon icon-package" %>
+  <% end %>
+<% end %>
+</td>
+<%= '</tr><tr>' if day.cwday==calendar.last_wday and day!=calendar.enddt %>
+<% day = day + 1
+end %>
+</tr>
+</tbody>
+</table>
index a2d556d90b9ad74b79c7bc85ed4d678d39201cf0..bad729363b04345abc5155de64f733ff5565fef9 100644 (file)
@@ -1,47 +1,8 @@
 <h3><%= l(:label_calendar) %></h3>
 
-<%
-@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? %>
 
-<table class="cal">
-<thead><tr>
-<td></td>
-<% 1.upto(7) do |d| %>
-    <th align="center" width="14%"><%= day_name(d) %></th>
-<% end %>
-</tr></thead>
-<tbdoy>
-<tr height="100">
-<% day = @date_from
-while day <= @date_to
-       if day.cwday == 1 %>
-       <th valign="middle"><%= day.cweek %></th>
-       <% end %>       
-       <td valign="top" width="14%" class="<%= day.month==@month ? "even" : "odd" %>">
-       <p align="right"><%= day==Date.today ? "<b>#{day.day}</b>" : day.day %></p>     
-       <% 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 %>
-               <small><%= link_to_issue i %>: <%=h i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %></small><br />
-       <% end %>
-    </td>
-       <%= '</tr><tr height="100">' if day.cwday >= 7 and day!=@date_to %>
-       <%
-       day = day + 1
-end %>
-</tr>
-</tbody>
-</table>
\ No newline at end of file
+<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %>
index b6f2958f383bf81b73b1896fdc4cfcabbdb57548..2c02d59ad765386dcfaf7069147cdf1f09c207bd 100644 (file)
 </td></tr>
 </table>
 
-<table class="cal">
-<thead>
-<tr>
-<td></td>
-<% 1.upto(7) do |d| %>
-    <th style="width:14%"><%= day_name(d) %></th>
-<% end %>
-</tr>
-</thead>
-<tbody>
-<tr style="height:100px">
-<% day = @date_from
-while day <= @date_to
-       if day.cwday == 1 %>
-       <th><%= day.cweek %></th>
-       <% end %>       
-       <td valign="top" class="<%= day.month==@month ? "even" : "odd" %> <%= Date.today == day ? 'today' : '' %>" style="width:14%;">
-       <p class="textright"><%= day==Date.today ? "<b>#{day.day}</b>" : day.day %></p> 
-       <% ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq.each do |i| %>
-           <% if i.is_a? Issue %>
-           <div class="tooltip">
-               <%= 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 %>
-               <small>
-               <%= h("#{i.project.name} -") unless @project && @project == i.project %>
-               <%= link_to_issue i %>:
-        <%= h(truncate(i.subject, 30)) %>
-               </small>
-        <span class="tip">
-        <%= render_issue_tooltip i %>
-        </span>                
-               </div>
-               <% else %>
-        <small><%= link_to_version i, :class => "icon icon-package" %></small>
-               <% end %>
-       <% end %>
-    </td>
-       <%= '</tr><tr style="height:100px">' if day.cwday >= 7 and day!=@date_to %>
-       <%
-       day = day + 1
-end %>
-</tr>
-</tbody>
-</table>
+<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %>
 
 <%= image_tag 'arrow_from.png' %>&nbsp;&nbsp;<%= l(:text_tip_task_begin_day) %><br />
 <%= image_tag 'arrow_to.png' %>&nbsp;&nbsp;<%= l(:text_tip_task_end_day) %><br />
index fe9efff0982c4d4b7b52f7982d263951916aeb20..12a5378d65c2cff9f342f5f3b3a51c773423ef70 100644 (file)
@@ -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: Невалиден потребител или парола.
index abf1f6e5a078a306896e521d348f18402cd2d700..078f824f69881564ee7e22ff35f127d91144e86b 100644 (file)
@@ -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
index 8345d99d4b74c83fdb6407b9432bb54b993ecf0b..4707855798cd0fd5539b247e0a26e4abf8b62b21 100644 (file)
@@ -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
index 34e49565fd9676237691cb70a74838c5d9f2c085..79e8f61d83587de0985767e74b526140be882c31 100644 (file)
@@ -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
index 12a6518a21cba3eb020496367f8343e78802a32f..2e8e6efbc73da2fc0f00b27f1bf3a260be1deb8c 100644 (file)
@@ -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
index 566f6573a34c31893508aed3060164786c2b9d32..bb875288e4ffe0f8b76cfc9b931a9dbe768302a2 100644 (file)
@@ -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.
index 2d0e0a1d04e1b2b4c631d07bc8e6fce75fb44042..4d114b15e75aafc32c89cee411e2641ad92bdb84 100644 (file)
@@ -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.
index c19199c4b82feaa95d001194c244f424fc4df283..433320aa1888ba71a5759e8a96ab197790ecbeba 100644 (file)
@@ -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: ユーザ名もしくはパスワードが無効
index 19c6a0de00b7ddaa430a1d91788a2ef84e4eacc2..7e252d9d1b6a91e54d5b3660f7df64ebd7663f0d 100644 (file)
@@ -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
index 9b0af1fda08f48b29cdf6eddb3de9d00c526b8d8..4db0d6761ecb8b6929137e01f54e1ab3a1b67221 100644 (file)
@@ -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
index b278edc58dcfb053b06fb7becf3a8e35ef3244cc..59a5e1ccbbd001c407469efc472f2dc2b2a480df 100644 (file)
@@ -51,6 +51,7 @@ general_csv_separator: ','
 general_csv_encoding: ISO-8859-1\r
 general_pdf_encoding: ISO-8859-1\r
 general_day_names: Segunda,Terca,Quarta,Quinta,Sexta,Sabado,Domingo\r
+general_first_day_of_week: '1'\r
 \r
 notice_account_updated: Conta foi alterada com sucesso.\r
 notice_account_invalid_creditentials: Usuario ou senha invalido.\r
index da75aa99cea20096521f42017cf18f436fe5aca4..b4e4a0cbd9b9174c6158ef4e804999e788d72e06 100644 (file)
@@ -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.
index 996df529d3309e44b7ac9130fe08e2362e3c8532..25c4887095fa5c8fcae65157730dc9150d6b310f 100644 (file)
@@ -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.
index a457ca11a30c6684d3af5605e63a6c9b7acc6d85..e59e9233e829274ad740b27b66bb6a45a8b76efd 100644 (file)
@@ -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
index ff0e12529f92d863c103118be2d6fa93768c8c31..b881ee4df143265baa9ba6d76224bbc03bcb0e52 100644 (file)
@@ -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 (file)
index 0000000..347f1c5
--- /dev/null
@@ -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
index fdeec2bbc7703d7e0598289a264626dd0503b9ca..9bae7bcd957d02dd72e7ce37594fa7bd2434ece5 100644 (file)
@@ -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 (file)
index 0000000..98d8569
--- /dev/null
@@ -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