Skip to content
Browse files

replaced lib/test with code used in lysbon

  • Loading branch information...
1 parent 908d3e5 commit 1c5c1d9f90219727b4c38780bff51ec4d9945824 @rubiii rubiii committed
Showing with 125 additions and 57 deletions.
  1. +84 −46 lib/calendar_helper.rb
  2. +41 −11 test/test_calendar_helper.rb
View
130 lib/calendar_helper.rb
@@ -9,13 +9,15 @@ module CalendarHelper
# calendar (which can then be customized using CSS) for a given month and year.
# However, this may be customized in a variety of ways -- changing the default CSS
# classes, generating the individual day entries yourself, and so on.
- #
+ #
# The following options are required:
# :year # The year number to show the calendar for.
# :month # The month number to show the calendar for.
- #
+ #
# The following are optional, available for customizing the default behaviour:
+ # :table_id => "calendar-2008-08" # The id for the <table> tag.
# :table_class => "calendar" # The class for the <table> tag.
+ # :summary => "Calendar for August 2008" # The summary attribute for the <table> tag. Required for 508 compliance.
# :month_name_class => "monthName" # The class for the name of the month, at the top of the table.
# :other_month_class => "otherMonth" # Not implemented yet.
# :day_name_class => "dayName" # The class is for the names of the weekdays, at the top.
@@ -25,13 +27,13 @@ module CalendarHelper
# or in full (false)
# :first_day_of_week => 0 # Renders calendar starting on Sunday. Use 1 for Monday, and so on.
# :accessible => true # Turns on accessibility mode. This suffixes dates within the
- # # calendar that are outside the range defined in the <caption> with
+ # # calendar that are outside the range defined in the <caption> with
# # <span class="hidden"> MonthName</span>
# # Defaults to false.
- # # You'll need to define an appropriate style in order to make this disappear.
+ # # You'll need to define an appropriate style in order to make this disappear.
# # Choose your own method of hiding content appropriately.
#
- # :show_today => false # Highlights today on the calendar using the CSS class 'today'.
+ # :show_today => false # Highlights today on the calendar using the CSS class 'today'.
# # Defaults to true.
# :previous_month_text => nil # Displayed left of the month name if set
# :next_month_text => nil # Displayed right of the month name if set
@@ -44,7 +46,7 @@ module CalendarHelper
# (this can be used to change the <td>'s class for customization with CSS).
# This block can also return the cell_text only, in which case the <td>'s class defaults to the value given in
# +:day_class+. If the block returns nil, the default options are used.
- #
+ #
# Example usage:
# calendar(:year => 2005, :month => 6) # This generates the simplest possible calendar.
# calendar({:year => 2005, :month => 6, :table_class => "calendar_helper"}) # This generates a calendar, as
@@ -61,19 +63,25 @@ module CalendarHelper
# end
# end
#
- # An additional 'weekend' class is applied to weekend days.
+ # An additional 'weekend' class is applied to weekend days.
#
# For consistency with the themes provided in the calendar_styles generator, use "specialDay" as the CSS class for marked days.
- #
+ #
+ # Accessibility & 508 Compliance:
+ # The table tag has a summary attribute (overridable).
+ # Each th has an id.
+ # Each td has a headers attribute, containing the element id of the appropriate th.
+ #
def calendar(options = {}, &block)
raise(ArgumentError, "No year given") unless options.has_key?(:year)
raise(ArgumentError, "No month given") unless options.has_key?(:month)
block ||= Proc.new {|d| nil}
-
- month_names = (I18n.t("date.month_names").include?("missing")) ? Date::MONTHNAMES.dup : I18n.t("date.month_names")
+
+ month_names = (!defined?(I18n) || I18n.t("date.month_names").include?("missing")) ? Date::MONTHNAMES.dup : I18n.t("date.month_names")
defaults = {
+ :table_id => "calendar-#{options[:year]}-#{"0%d" % options[:month]}",
:table_class => 'calendar',
:month_name_class => 'monthName',
:other_month_class => 'otherMonth',
@@ -86,7 +94,8 @@ def calendar(options = {}, &block)
:previous_month_text => nil,
:next_month_text => nil,
:month_header => true,
- :calendar_title => month_names[options[:month]]
+ :calendar_title => month_names[options[:month]],
+ :summary => "Calendar for #{month_names[options[:month]]} #{options[:year]}"
}
options = defaults.merge options
@@ -95,18 +104,18 @@ def calendar(options = {}, &block)
first_weekday = first_day_of_week(options[:first_day_of_week])
last_weekday = last_day_of_week(options[:first_day_of_week])
-
- day_names = (I18n.t("date.day_names").include?("missing")) ? Date::DAYNAMES.dup : I18n.t("date.day_names")
- abbr_day_names = (I18n.t("date.abbr_day_names").include?("missing")) ? Date::ABBR_DAYNAMES.dup : I18n.t("date.abbr_day_names")
+
+ day_names = (!defined?(I18n) || I18n.t("date.day_names").include?("missing")) ? Date::DAYNAMES.dup : I18n.t("date.day_names").dup
+ abbr_day_names = (!defined?(I18n) || I18n.t("date.abbr_day_names").include?("missing")) ? Date::ABBR_DAYNAMES.dup : I18n.t("date.abbr_day_names").dup
first_weekday.times do
day_names.push(day_names.shift)
abbr_day_names.push(abbr_day_names.shift)
end
# TODO Use some kind of builder instead of straight HTML
- cal = %(<table class="#{options[:table_class]}" border="0" cellspacing="0" cellpadding="0">)
+ cal = %(<table id="#{options[:table_id]}" class="#{options[:table_class]}" border="0" cellspacing="0" cellpadding="0" summary="#{options[:summary]}">)
cal << %(<thead>)
-
+
if (options[:month_header])
cal << %(<tr>)
if options[:previous_month_text] or options[:next_month_text]
@@ -119,56 +128,50 @@ def calendar(options = {}, &block)
cal << %(<th colspan="2">#{options[:next_month_text]}</th>) if options[:next_month_text]
cal << %(</tr>)
end
-
+
cal << %(<tr class="#{options[:day_name_class]}">)
-
+
day_names.each_with_index do |day_name, index|
- if options[:abbrev]
- cal << "<th scope='col'><abbr title='#{day_name}'>#{abbr_day_names[index]}</abbr></th>"
- else
- cal << "<th scope='col'>#{day_name}</th>"
- end
+ cal << %(<th id="#{th_id(day_name, options[:table_id])}" scope='col'>)
+ cal << (options[:abbrev] ? %(<abbr title='#{day_name}'>#{abbr_day_names[index]}</abbr>) : day_name)
+ cal << %(</th>)
end
+
cal << "</tr></thead><tbody><tr>"
+
+ # previous month
beginning_of_week(first, first_weekday).upto(first - 1) do |d|
- cal << %(<td class="#{options[:other_month_class]})
- cal << " weekendDay" if weekend?(d)
- if options[:accessible]
- cal << %(">#{d.day}<span class="hidden"> #{month_names[d.month]}</span></td>)
- else
- cal << %(">#{d.day}</td>)
- end
+ cal << generate_other_month_cell(d, options)
end unless first.wday == first_weekday
+
first.upto(last) do |cur|
cell_text, cell_attrs = block.call(cur)
cell_text ||= cur.mday
cell_attrs ||= {}
+ cell_attrs[:headers] = th_id(cur, options[:table_id])
cell_attrs[:class] ||= options[:day_class]
cell_attrs[:class] += " weekendDay" if [0, 6].include?(cur.wday)
today = (Time.respond_to?(:zone) && !(zone = Time.zone).nil? ? zone.now.to_date : Date.today)
cell_attrs[:class] += " today" if (cur == today) and options[:show_today]
- cell_attrs = cell_attrs.map {|k, v| %(#{k}="#{v}") }.join(" ")
- cal << "<td #{cell_attrs}>#{cell_text}</td>"
+
+ cal << generate_cell(cell_text, cell_attrs)
cal << "</tr><tr>" if cur.wday == last_weekday
end
+
+ # next month
(last + 1).upto(beginning_of_week(last + 7, first_weekday) - 1) do |d|
- cal << %(<td class="#{options[:other_month_class]})
- cal << " weekendDay" if weekend?(d)
- if options[:accessible]
- cal << %(">#{d.day}<span class='hidden'> #{month_names[d.mon]}</span></td>)
- else
- cal << %(">#{d.day}</td>)
- end
+ cal << generate_other_month_cell(d, options)
end unless last.wday == last_weekday
+
cal << "</tr></tbody></table>"
end
-
+
private
-
+
def first_day_of_week(day)
day
end
-
+
def last_day_of_week(day)
if day > 0
day - 1
@@ -176,7 +179,7 @@ def last_day_of_week(day)
6
end
end
-
+
def days_between(first, second)
if first > second
second + (7 - first)
@@ -184,14 +187,49 @@ def days_between(first, second)
second - first
end
end
-
+
def beginning_of_week(date, start = 1)
days_to_beg = days_between(start, date.wday)
date - days_to_beg
end
-
+
+ def generate_cell(cell_text, cell_attrs)
+ cell_attrs = cell_attrs.map {|k, v| %(#{k}="#{v}") }.join(" ")
+ "<td #{cell_attrs}>#{cell_text}</td>"
+ end
+
+ def generate_other_month_cell(date, options)
+ cell_attrs = {}
+ cell_attrs[:headers] = th_id(date, options[:table_id])
+ cell_attrs[:class] = options[:other_month_class]
+ cell_attrs[:class] += " weekendDay" if weekend?(date)
+
+ cell_text = date.day
+ if options[:accessible]
+ cell_text += %(<span class="hidden"> #{month_names[date.month]}</span>)
+ end
+
+ generate_cell(date.day, cell_attrs)
+ end
+
+ # Calculates id for th element.
+ # derived from calendar_id and dow.
+ #
+ # Params:
+ # `day` can be either Date or DOW('Sunday', 'Monday')
+ def th_id(day, calendar_id)
+ return th_id(Date::DAYNAMES[day.wday], calendar_id) if day.is_a?(Date)
+ "#{calendar_id}-#{day[0..2].downcase}"
+ end
+
def weekend?(date)
[0, 6].include?(date.wday)
end
-
+
end
+
+class Railtie < Rails::Railtie
+ ActiveSupport.on_load(:action_view) do
+ include CalendarHelper
+ end
+end if defined? Rails::Railtie
View
52 test/test_calendar_helper.rb
@@ -42,11 +42,11 @@ def test_required_fields
end
def test_default_css_classes
- # :other_month_class is not implemented yet
{ :table_class => "calendar",
:month_name_class => "monthName",
:day_name_class => "dayName",
- :day_class => "day"
+ :day_class => "day",
+ :other_month_class => "otherMonth"
}.each do |key, value|
assert_correct_css_class_for_default value
end
@@ -54,21 +54,19 @@ def test_default_css_classes
def test_custom_css_classes
# Uses the key name as the CSS class name
- # :other_month_class is not implemented yet
- [:table_class, :month_name_class, :day_name_class, :day_class].each do |key|
+ [:table_class, :month_name_class, :day_name_class, :day_class, :other_month_class].each do |key|
assert_correct_css_class_for_key key.to_s, key
end
end
def test_abbrev
- assert_match %r{>Mon<}, calendar_with_defaults(:abbrev => (0..2))
- assert_match %r{>M<}, calendar_with_defaults(:abbrev => (0..0))
- assert_match %r{>Monday<}, calendar_with_defaults(:abbrev => (0..-1))
+ assert_match %r{>Mon<}, calendar_with_defaults()
+ assert_match %r{>Monday<}, calendar_with_defaults(:abbrev => false)
end
def test_block
# Even days are special
- assert_match %r{class="special_day">2<}, calendar(:year => 2006, :month => 8) { |d|
+ assert_match %r{class="special_day"[^>]*>2<}, calendar(:year => 2006, :month => 8) { |d|
if d.mday % 2 == 0
[d.mday, {:class => 'special_day'}]
end
@@ -76,10 +74,10 @@ def test_block
end
def test_first_day_of_week
- assert_match %r{<tr class="dayName">\s*<th scope='col'><abbr title='Sunday'>Sun}, calendar_with_defaults
+ assert_match %r{<tr class="dayName">\s*<th [^>]*scope='col'><abbr title='Sunday'>Sun}, calendar_with_defaults
# testing that if the abbrev and contracted version are the same, there should be no abbreviation.
- assert_match %r{<tr class="dayName">\s*<th scope='col'>Sunday}, calendar_with_defaults(:abbrev => (0..8))
- assert_match %r{<tr class="dayName">\s*<th scope='col'><abbr title='Monday'>Mon}, calendar_with_defaults(:first_day_of_week => 1)
+ assert_match %r{<tr class="dayName">\s*<th [^>]*scope='col'>Sunday}, calendar_with_defaults(:abbrev => false)
+ assert_match %r{<tr class="dayName">\s*<th [^>]*scope='col'><abbr title='Monday'>Mon}, calendar_with_defaults(:first_day_of_week => 1)
end
def test_today_is_in_calendar
@@ -100,6 +98,38 @@ def test_should_have_two_tr_tags_in_the_thead
assert_match %r{<thead><tr>.*</tr><tr.*</tr></thead>}, html
end
+ def test_table_summary_defaults_to_calendar_period
+ html = calendar_with_defaults(:year => 1967, :month => 4)
+ assert_match %r{<table [^>]*summary="Calendar for April 1967"}, html
+ end
+
+ def test_custom_summary_attribute
+ html = calendar_with_defaults(:summary => 'TEST SUMMARY')
+ assert_match %r{<table [^>]*summary="TEST SUMMARY">}, html
+ end
+
+ def test_table_id_defaults_calendar_year_month
+ html = calendar_with_defaults(:year => 1967, :month => 4)
+ assert_match %r{<table [^>]*id="calendar-1967-04"}, html
+ end
+
+ def test_custom_table_id
+ html = calendar_with_defaults(:year => 1967, :month => 4, :table_id => 'test-the-id')
+ assert_match %r{<table [^>]*id="test-the-id"}, html
+ end
+
+ def test_th_id_defaults_calendar_year_month_dow
+ html = calendar_with_defaults(:year => 1967, :month => 4)
+ assert_match %r{<tr class=\"dayName\"><th [^>]*id=\"calendar-1967-04-sun\"}, html
+ end
+
+ def test_each_td_is_associated_with_appriopriate_th
+ html = calendar_with_defaults(:year => 2011, :month => 8)
+ assert_match %r{<td [^>]*headers=\"calendar-2011-08-sun\"[^>]+>31</td>}, html
+ assert_match %r{<td [^>]*headers=\"calendar-2011-08-mon\"[^>]+>1</td>}, html
+ end
+
+
private
def assert_correct_css_class_for_key(css_class, key)

0 comments on commit 1c5c1d9

Please sign in to comment.
Something went wrong with that request. Please try again.