summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/my_controller.rb1
-rw-r--r--app/helpers/calendars_helper.rb29
-rw-r--r--app/views/common/_calendar.html.erb73
-rw-r--r--lib/redmine/helpers/calendar.rb17
-rw-r--r--lib/redmine/i18n.rb4
-rw-r--r--public/stylesheets/application.css69
-rw-r--r--public/stylesheets/responsive.css32
-rw-r--r--test/functional/calendars_controller_test.rb164
-rw-r--r--test/functional/my_controller_test.rb32
9 files changed, 229 insertions, 192 deletions
diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb
index 48a68b626..9eaaa90e7 100644
--- a/app/controllers/my_controller.rb
+++ b/app/controllers/my_controller.rb
@@ -33,7 +33,6 @@ class MyController < ApplicationController
helper :custom_fields
helper :queries
helper :activities
- helper :calendars
def index
page
diff --git a/app/helpers/calendars_helper.rb b/app/helpers/calendars_helper.rb
deleted file mode 100644
index e207bc391..000000000
--- a/app/helpers/calendars_helper.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-# Redmine - project management software
-# Copyright (C) 2006-2023 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 CalendarsHelper
- include Redmine::Utils::DateCalculation
-
- def calendar_day_css_classes(calendar, day)
- css = day.month==calendar.month ? +'even' : +'odd'
- css << " today" if User.current.today == day
- css << " nwday" if non_working_week_days.include?(day.cwday)
- css
- end
-end
diff --git a/app/views/common/_calendar.html.erb b/app/views/common/_calendar.html.erb
index 63cb43c97..533ed2c4d 100644
--- a/app/views/common/_calendar.html.erb
+++ b/app/views/common/_calendar.html.erb
@@ -1,48 +1,37 @@
<%= form_tag({}, :data => {:cm_url => issues_context_menu_path}) do -%>
<%= hidden_field_tag 'back_url', url_for(:params => request.query_parameters), :id => nil %>
-<table class="cal">
-<thead>
- <tr>
- <th scope="col" title="<%= l(:label_week) %>" class="week-number"></th>
- <% 7.times do |i| %>
- <th scope="col"><%= day_name((calendar.first_wday + i) % 7) %></th>
- <% end %>
- </tr>
-</thead>
-<tbody>
-<tr>
-<% day = calendar.startdt %>
-<% while day <= calendar.enddt %>
- <% if day.cwday == calendar.first_wday %>
- <td class='week-number' title='<%= l(:label_week) %>'>
- <%= (day + (11 - day.cwday) % 7).cweek %>
- </td>
+<ul class="cal">
+ <li scope="col" title="<%= l(:label_week) %>" class="calhead week-number"></li>
+ <% 7.times do |i| %>
+ <li scope="col" class="calhead"><%= day_name((calendar.first_wday + i) % 7) %></li>
<% end %>
-<td class="<%= calendar_day_css_classes(calendar, day) %>">
-<p class="day-num"><%= day.day %></p>
-<% calendar.events_on(day).each do |i| %>
- <% if i.is_a? Issue %>
- <div class="<%= i.css_classes %> <%= 'starting' if day == i.start_date %> <%= 'ending' if day == i.due_date %> tooltip hascontextmenu">
- <%= "#{i.project} -" unless @project && @project == i.project %>
- <%= link_to_issue i, :truncate => 30 %>
- <span class="tip"><%= render_issue_tooltip i %></span>
- <%= check_box_tag 'ids[]', i.id, false, :style => 'display:none;', :id => nil %>
- </div>
- <% else %>
- <span class="icon icon-package">
- <%= "#{i.project} -" unless @project && @project == i.project %>
- <%= link_to_version i %>
- </span>
+ <% calendar.format_month.each_slice(7) do |week| %>
+ <li class='week-number'>
+ <span class="label-week"><%= l(:label_week) %></span> <%= calendar.week_number week.first %>
+ </li>
+ <% week.each do |day| %>
+ <li class="<%= calendar.day_css_classes day %> calbody">
+ <p class="day-num"><%= day.day %>
+ <span class="abbr-day">(<%= abbr_day_name(day.cwday) %>)</span>
+ </p>
+ <% calendar.events_on(day).each do |i| %>
+ <% if i.is_a? Issue %>
+ <%= tag.div class: [ i.css_classes, 'tooltip hascontextmenu', starting: day == i.start_date, ending: day == i.due_date] do %>
+ <%= "#{i.project} -" unless @project && @project == i.project %>
+ <%= link_to_issue i, :truncate => 30 %>
+ <span class="tip"><%= render_issue_tooltip i %></span>
+ <%= check_box_tag 'ids[]', i.id, false, :style => 'display:none;', :id => nil %>
+ <% end %>
+ <% else %>
+ <span class="icon icon-package">
+ <%= "#{i.project} -" unless @project && @project == i.project %>
+ <%= link_to_version i %>
+ </span>
+ <% end %>
+ <% end %>
+ </li>
+ <% end %>
<% end %>
-<% end %>
-</td>
-<% if day.cwday==calendar.last_wday and day!=calendar.enddt %>
- </tr><tr>
-<% end %>
-<% day = day + 1 %>
-<% end %>
-</tr>
-</tbody>
-</table>
+</ul>
<% end %>
<%= context_menu %>
diff --git a/lib/redmine/helpers/calendar.rb b/lib/redmine/helpers/calendar.rb
index 2f5b5d097..d6730840f 100644
--- a/lib/redmine/helpers/calendar.rb
+++ b/lib/redmine/helpers/calendar.rb
@@ -23,6 +23,8 @@ module Redmine
# Simple class to compute the start and end dates of a calendar
class Calendar
include Redmine::I18n
+ include Redmine::Utils::DateCalculation
+
attr_reader :startdt, :enddt
def initialize(date, lang = current_language, period = :month)
@@ -47,6 +49,21 @@ module Redmine
end
end
+ def format_month
+ (@startdt..@enddt).to_a
+ end
+
+ def week_number(day)
+ (day + (11 - day.cwday) % 7).cweek
+ end
+
+ def day_css_classes(day)
+ css = day.month==month ? +'even' : +'odd'
+ css << " today" if User.current.today == day
+ css << " nwday" if non_working_week_days.include?(day.cwday)
+ css
+ end
+
# Sets calendar events
def events=(events)
@events = events
diff --git a/lib/redmine/i18n.rb b/lib/redmine/i18n.rb
index 7010437fd..5421c45d5 100644
--- a/lib/redmine/i18n.rb
+++ b/lib/redmine/i18n.rb
@@ -103,6 +103,10 @@ module Redmine
::I18n.t('date.day_names')[day % 7]
end
+ def abbr_day_name(day)
+ ::I18n.t('date.abbr_day_names')[day % 7]
+ end
+
def day_letter(day)
::I18n.t('date.abbr_day_names')[day % 7].first
end
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 7d256832b..e63983706 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -1100,21 +1100,60 @@ vertical-align: bottom;
}
/***** Calendar *****/
-table.cal {width: 100%; margin: 0 0 6px 0; border: 1px solid #c0c0c0; border-spacing: 0; border-radius: 3px;}
-table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; }
-table.cal thead th.week-number {width: auto;}
-table.cal tbody tr {height: 100px;}
-table.cal td .icon {padding-top: 2px; padding-bottom: 3px;}
-table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em; border-bottom: 0; border-right: 0;}
-table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;}
-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;}
-table.cal td.nwday:not(.odd) {background-color:#f1f1f1;}
-table.cal .starting a.issue, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
-table.cal .ending a.issue, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
-table.cal .starting.ending a.issue, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
+ul.cal {
+ list-style: none;
+ width: 100%;
+ padding: 0;
+ display: grid;
+ grid-template-columns: 2rem repeat(7, 1fr);
+ margin: 0;
+ border: 1px solid #c0c0c0;
+ border-spacing: 0;
+ border-radius: 3px;
+}
+
+.cal .calhead {
+ background-color:#eee;
+ text-align: center;
+ font-weight: bold;
+ padding: 4px
+}
+
+.cal .week-number {
+ background-color:#eee;
+ border:none;
+ font-size: 1em;
+ padding: 4px;
+ text-align: center;
+}
+
+.cal .week-number .label-week {
+ display: none;
+}
+
+.cal .calbody {
+ border: 1px solid #d7d7d7;
+ vertical-align: top;
+ font-size: 0.9em;
+ border-bottom: 0;
+ border-right: 0;
+ line-height: 1.2;
+ min-height: calc(1.2em * 6);
+ padding: 2px;
+}
+
+.cal .calbody p.day-num {font-size: 1.1em; text-align:right;}
+.cal .calbody .abbr-day {display:none}
+.cal .calbody.odd p.day-num {color: #bbb;}
+.cal .calbody.today {background:#ffd;}
+.cal .calbody.today p.day-num {font-weight: bold;}
+
+.cal .calbody .icon {padding-top: 2px; padding-bottom: 3px;}
+.cal .calbody.nwday:not(.odd) {background-color:#f1f1f1;}
+.cal .starting a.issue, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
+.cal .ending a.issue, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
+.cal .starting.ending a.issue, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
+
p.cal.legend span {display:block;}
.controller-calendars p.buttons {margin-top: unset;}
diff --git a/public/stylesheets/responsive.css b/public/stylesheets/responsive.css
index d6282046d..482f73cf2 100644
--- a/public/stylesheets/responsive.css
+++ b/public/stylesheets/responsive.css
@@ -819,6 +819,38 @@
margin-left: 0;
width: 100%;
}
+
+ /* Calendar */
+ ul.cal {
+ display: block
+ }
+ .cal .calhead {
+ display: none
+ }
+
+ .cal .calbody {
+ min-height: calc(1.2em * 3);
+ }
+
+ .cal .calbody .abbr-day {
+ display: inline;
+ }
+
+ .cal .week-number {
+ border: 1px solid #c0c0c0;
+ text-align: left;
+ font-weight: bold;
+ background-color: #def;
+ }
+
+ .cal .week-number .label-week {
+ display: inline;
+ }
+
+ .cal .calbody p.day-num {
+ font-size: 1.1em;
+ text-align: left;
+ }
}
@media all and (max-width: 599px) {
diff --git a/test/functional/calendars_controller_test.rb b/test/functional/calendars_controller_test.rb
index e5a4a6e94..b6dcbdf01 100644
--- a/test/functional/calendars_controller_test.rb
+++ b/test/functional/calendars_controller_test.rb
@@ -65,19 +65,17 @@ class CalendarsControllerTest < Redmine::ControllerTest
# Assert context menu on issues
assert_select 'form[data-cm-url=?]', '/issues/context_menu'
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
- assert_select(
- 'div.issue.hascontextmenu.tooltip.starting',
- :text => /Add ingredients categories/
- ) do
- assert_select 'a.issue[href=?]', '/issues/2', :text => 'Feature request #2'
- assert_select 'span.tip' do
- assert_select 'img[class="gravatar"]'
- end
- assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '2'
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'div.issue.hascontextmenu.tooltip.starting',
+ :text => /Add ingredients categories/
+ ) do
+ assert_select 'a.issue[href=?]', '/issues/2', :text => 'Feature request #2'
+ assert_select 'span.tip' do
+ assert_select 'img[class="gravatar"]'
end
+ assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '2'
end
end
end
@@ -89,16 +87,14 @@ class CalendarsControllerTest < Redmine::ControllerTest
get(:show, :params => {:project_id => 1})
assert_response :success
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
- assert_select(
- 'div.issue.hascontextmenu.tooltip.ending',
- :text => /Cannot print recipes/
- ) do
- assert_select 'a.issue[href=?]', '/issues/1', :text => 'Bug #1'
- assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '1'
- end
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'div.issue.hascontextmenu.tooltip.ending',
+ :text => /Cannot print recipes/
+ ) do
+ assert_select 'a.issue[href=?]', '/issues/1', :text => 'Bug #1'
+ assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '1'
end
end
end
@@ -120,24 +116,22 @@ class CalendarsControllerTest < Redmine::ControllerTest
)
assert_response :success
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'div.issue.hascontextmenu.tooltip.starting.ending',
+ :text => /#{subject}/
+ ) do
assert_select(
- 'div.issue.hascontextmenu.tooltip.starting.ending',
- :text => /#{subject}/
- ) do
- assert_select(
- 'a.issue[href=?]', "/issues/#{issue.id}",
- :text => "Bug ##{issue.id}"
- )
- assert_select(
- 'input[name=?][type=?][value=?]',
- 'ids[]',
- 'checkbox',
- issue.id.to_s
- )
- end
+ 'a.issue[href=?]', "/issues/#{issue.id}",
+ :text => "Bug ##{issue.id}"
+ )
+ assert_select(
+ 'input[name=?][type=?][value=?]',
+ 'ids[]',
+ 'checkbox',
+ issue.id.to_s
+ )
end
end
end
@@ -149,14 +143,12 @@ class CalendarsControllerTest < Redmine::ControllerTest
get(:show, :params => {:project_id => 1})
assert_response :success
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
- assert_select(
- 'span.icon.icon-package'
- ) do
- assert_select 'a[href=?]', '/versions/2', :text => '1.0'
- end
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'span.icon.icon-package'
+ ) do
+ assert_select 'a[href=?]', '/versions/2', :text => '1.0'
end
end
end
@@ -179,16 +171,14 @@ class CalendarsControllerTest < Redmine::ControllerTest
get :show
assert_response :success
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
- assert_select(
- 'div.issue.hascontextmenu.tooltip.starting',
- :text => /eCookbook.*Add ingredients categories/m
- ) do
- assert_select 'a.issue[href=?]', '/issues/2', :text => 'Feature request #2'
- assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '2'
- end
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'div.issue.hascontextmenu.tooltip.starting',
+ :text => /eCookbook.*Add ingredients categories/m
+ ) do
+ assert_select 'a.issue[href=?]', '/issues/2', :text => 'Feature request #2'
+ assert_select 'input[name=?][type=?][value=?]', 'ids[]', 'checkbox', '2'
end
end
end
@@ -200,17 +190,15 @@ class CalendarsControllerTest < Redmine::ControllerTest
get :show
assert_response :success
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'span.icon.icon-package'
+ ) do
assert_select(
- 'span.icon.icon-package'
- ) do
- assert_select(
- 'a[href=?]', '/versions/2',
- :text => 'eCookbook - 1.0'
- )
- end
+ 'a[href=?]', '/versions/2',
+ :text => 'eCookbook - 1.0'
+ )
end
end
end
@@ -228,16 +216,16 @@ class CalendarsControllerTest < Redmine::ControllerTest
assert_response :success
end
- assert_select 'tr' do
- assert_select 'td.week-number', :text => '53'
- assert_select 'td.odd', :text => '27'
- assert_select 'td.even', :text => '2'
+ assert_select 'ul' do
+ assert_select 'li.week-number:nth-of-type(2)', :text => /53$/
+ assert_select 'li.odd', :text => /^27/
+ assert_select 'li.even', :text => /^2/
end
- assert_select 'tr' do
- assert_select 'td.week-number', :text => '1'
- assert_select 'td.odd', :text => '3'
- assert_select 'td.even', :text => '9'
+ assert_select 'ul' do
+ assert_select 'li.week-number', :text => /1$/
+ assert_select 'li.odd', :text => /^3/
+ assert_select 'li.even', :text => /^9/
end
with_settings :start_of_week => 1 do
@@ -251,16 +239,16 @@ class CalendarsControllerTest < Redmine::ControllerTest
assert_response :success
end
- assert_select 'tr' do
- assert_select 'td.week-number', :text => '53'
- assert_select 'td.even', :text => '28'
- assert_select 'td.even', :text => '3'
+ assert_select 'ul' do
+ assert_select 'li.week-number:nth-of-type(2)', :text => /53$/
+ assert_select 'li.even', :text => /^28/
+ assert_select 'li.even', :text => /^3/
end
- assert_select 'tr' do
- assert_select 'td.week-number', :text => '1'
- assert_select 'td.even', :text => '4'
- assert_select 'td.even', :text => '10'
+ assert_select 'ul' do
+ assert_select 'li.week-number', :text => /1$/
+ assert_select 'li.even', :text => /^4/
+ assert_select 'li.even', :text => /^10/
end
end
@@ -296,12 +284,12 @@ class CalendarsControllerTest < Redmine::ControllerTest
)
assert_response :success
- assert_select 'tr:nth-child(2)' do
- assert_select 'td.week-number', :text => '49'
+ assert_select 'ul' do
+ assert_select 'li.week-number:nth-of-type(2)', :text => /48$/
# non working days should have "nwday" CSS class
- assert_select 'td.nwday', 2
- assert_select 'td.nwday', :text => '4'
- assert_select 'td.nwday', :text => '10'
+ assert_select 'li.nwday', 10
+ assert_select 'li.nwday', :text => /^4/
+ assert_select 'li.nwday', :text => /^10/
end
end
end
diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb
index c061f67ab..cb3014fda 100644
--- a/test/functional/my_controller_test.rb
+++ b/test/functional/my_controller_test.rb
@@ -444,24 +444,22 @@ class MyControllerTest < Redmine::ControllerTest
assert_select 'form[data-cm-url=?]', '/issues/context_menu'
- assert_select 'table.cal' do
- assert_select 'tr' do
- assert_select 'td' do
+ assert_select 'ul.cal' do
+ assert_select 'li' do
+ assert_select(
+ 'div.issue.hascontextmenu.tooltip.starting.ending',
+ :text => /eCookbook.*#{subject}/m
+ ) do
+ assert_select(
+ 'a.issue[href=?]', "/issues/#{issue.id}",
+ :text => "Bug ##{issue.id}"
+ )
assert_select(
- 'div.issue.hascontextmenu.tooltip.starting.ending',
- :text => /eCookbook.*#{subject}/m
- ) do
- assert_select(
- 'a.issue[href=?]', "/issues/#{issue.id}",
- :text => "Bug ##{issue.id}"
- )
- assert_select(
- 'input[name=?][type=?][value=?]',
- 'ids[]',
- 'checkbox',
- issue.id.to_s
- )
- end
+ 'input[name=?][type=?][value=?]',
+ 'ids[]',
+ 'checkbox',
+ issue.id.to_s
+ )
end
end
end