diff options
-rw-r--r-- | app/controllers/my_controller.rb | 1 | ||||
-rw-r--r-- | app/helpers/calendars_helper.rb | 29 | ||||
-rw-r--r-- | app/views/common/_calendar.html.erb | 73 | ||||
-rw-r--r-- | lib/redmine/helpers/calendar.rb | 17 | ||||
-rw-r--r-- | lib/redmine/i18n.rb | 4 | ||||
-rw-r--r-- | public/stylesheets/application.css | 69 | ||||
-rw-r--r-- | public/stylesheets/responsive.css | 32 | ||||
-rw-r--r-- | test/functional/calendars_controller_test.rb | 164 | ||||
-rw-r--r-- | test/functional/my_controller_test.rb | 32 |
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 |