# CalendarHelper allows you to draw a databound calendar with fine-grained CSS formatting
# Copyright (C) 2005 Jeremy Voorhis, Shachaf Ben-Kiki
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
module CalendarHelper
# Returns an HTML calendar. In its simplest form, this method generates a plain
# 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_class => "calendar" # The class for the
tag.
# :month_name_class => "monthName" # The class for the name of the month, at the top of the table.
# :other_month_class => "otherMonthClass" # Not implemented yet.
# :day_name_class => "dayName" # The class is for the names of the weekdays, at the top.
# :day_class => "day" # The class for the individual day number cells.
# This may or may not be used if you specify a block (see below).
# :abbrev => (0..2) # This option specifies how the day names should be abbreviated.
# Use (0..2) for the first three letters, (0..0) for the first, and
# (0..-1) for the entire name.
#
# For more customization, you can pass a code block to this method, that will get one argument, a Date object,
# and return a values for the individual table cells. The block can return an array, [cell_text, cell_attrs],
# cell_text being the text that is displayed and cell_attrs a hash containing the attributes for the tag
# (this can be used to change the | 's class for customization with CSS).
# This block can also return the cell_text only, in which case the | '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
# # before, but the 's class
# # is set to "calendar_helper".
# calendar(:year => 2005, :month => 6, :abbrev => (0..-1)) # This generates a simple calendar but shows the
# # entire day name ("Sunday", "Monday", etc.) instead
# # of only the first three letters.
# calendar(:year => 2005, :month => 5) do |d| # This generates a simple calendar, but gives special days
# if listOfSpecialDays.include?(d) # (days that are in the array listOfSpecialDays) one CSS class,
# [d.mday, {:class => "specialDay"}] # "specialDay", and gives the rest of the days another CSS class,
# else # "normalDay". You can also use this highlight today differently
# [d.mday, {:class => "normalDay"}] # from the rest of the days, etc.
# end
def calendar(options = {}, &block)
raise ArgumentError, "No year given" unless defined? options[:year]
raise ArgumentError, "No month given" unless defined? options[:month]
block ||= Proc.new {|d| nil}
options[:table_class ] ||= "calendar"
options[:month_name_class ] ||= "monthName"
options[:other_month_class ] ||= "otherMonth"
options[:day_name_class ] ||= "dayName"
options[:day_class ] ||= "day"
options[:abbrev ] ||= (0..2)
first = Date.civil(options[:year], options[:month], 1)
last = Date.civil(options[:year], options[:month], -1)
cal = <
#{Date::MONTHNAMES[options[:month]]} |
EOF
Date::DAYNAMES.each {|d| cal << " #{d[options[:abbrev]]} | "}
cal << "
"
0.upto(first.wday - 1) {|d| cal << " | "} unless first.wday == 0
first.upto(last) do |cur|
cell_text, cell_attrs = block.call(cur)
cell_text ||= cur.mday
cell_attrs ||= {:class => options[:day_class]}
cell_attrs = cell_attrs.map {|k, v| "#{k}='#{v}'"}.join(' ')
cal << " #{cell_text} | "
cal << " \n " if cur.wday == 6
end
last.wday.upto(5) {|d| cal << " | "} unless last.wday == 6
cal << " \n \n "
end
end
|