• Publicity: Public Only All

acs-calendar-2-procs.tcl

Library for calendar display widgets

Location:
packages/acs-datetime/tcl/acs-calendar-2-procs.tcl
Created:
2000-11-21
Author:
ron@arsdigita.com
CVS Identification:
$Id: acs-calendar-2-procs.tcl,v 1.46.2.3 2021/12/28 14:49:49 antoniop Exp $

Procedures in this file

Detailed information

dt_hour_diff (public, deprecated)

 dt_hour_diff -start_time start_time -end_time end_time
Deprecated. Invoking this procedure generates a warning.

24-hour times input (23:00,02:00). This gives us the num of hours of difference, taking into account that if something goes until 5:01, it is one more hour long than if it goes until 5:00 DEPRECATED: this is really something one should do leveraging existing tcl capabilities. Plain clock idioms can do the same in a more generic and reliable way.

Switches:
-start_time
(required)
-end_time
(required)
See Also:
  • clock

Partial Call Graph (max 5 caller/called nodes):
%3 dt_widget_day dt_widget_day (public, deprecated) dt_hour_diff dt_hour_diff dt_widget_day->dt_hour_diff ad_log_deprecated ad_log_deprecated (public) dt_hour_diff->ad_log_deprecated

Testcases:
No testcase defined.

dt_midnight_p (public)

 dt_midnight_p time

Check if a time is midnight. This might be replaced by clock idioms in the future, but is currently the way we decide e.g. if an event is an all-day event.

Parameters:
time
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_dt_midnight_p dt_midnight_p (test acs-datetime) dt_midnight_p dt_midnight_p test_dt_midnight_p->dt_midnight_p dt_no_time_p dt_no_time_p (public) dt_no_time_p->dt_midnight_p

Testcases:
dt_midnight_p

dt_no_time_p (public)

 dt_no_time_p -start_time start_time -end_time end_time

This decides whether an item is without a time, which is also our definition of an all-day event.

Switches:
-start_time
(required)
-end_time
(required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_dt_midnight_p dt_midnight_p (test acs-datetime) dt_no_time_p dt_no_time_p test_dt_midnight_p->dt_no_time_p dt_midnight_p dt_midnight_p (public) dt_no_time_p->dt_midnight_p dt_widget_list dt_widget_list (public, deprecated) dt_widget_list->dt_no_time_p

Testcases:
dt_midnight_p

dt_widget_day (public, deprecated)

 dt_widget_day [ -calendar_details calendar_details ] [ -date date ] \
    [ -hour_template hour_template ] [ -start_hour start_hour ] \
    [ -end_hour end_hour ] [ -show_nav show_nav ] \
    [ -prev_nav_template prev_nav_template ] \
    [ -next_nav_template next_nav_template ] \
    [ -master_bgcolor master_bgcolor ] \
    [ -header_bgcolor header_bgcolor ] \
    [ -header_text_color header_text_color ] \
    [ -header_text_size header_text_size ] \
    [ -calendar_width calendar_width ] [ -day_bgcolor day_bgcolor ] \
    [ -today_bgcolor today_bgcolor ] \
    [ -day_text_color day_text_color ] \
    [ -empty_bgcolor empty_bgcolor ] [ -overlap_p overlap_p ]
Deprecated. Invoking this procedure generates a warning.

Returns a calendar for a specific day, with details supplied by hour. Defaults to today. DEPRECATED: this proc uses hardcoded markup and is therefore difficult to style. It is also not localized. Many of the date operations happening here have now good tcl support through the clock api, which would make this code probably faster. Future reimplementations should leverage the templating system more.

Switches:
-calendar_details
(optional)
-date
(optional)
-hour_template
(defaults to "$display_hour") (optional)
-start_hour
(defaults to "0") (optional)
-end_hour
(defaults to "23") (optional)
-show_nav
(defaults to "1") (optional)
-prev_nav_template
(defaults to "<a href="?date=[ns_urlencode $yesterday]"><img border="0" src="[dt_left_arrow]" alt="[_ acs-datetime.back_one_day]"></a>") (optional)
-next_nav_template
(defaults to "<a href="?date=[ns_urlencode $tomorrow]"><img border="0" src="[dt_right_arrow]" alt="[_ acs-datetime.forward_one_day]"></a>") (optional)
-master_bgcolor
(defaults to "black") (optional)
-header_bgcolor
(defaults to "black") (optional)
-header_text_color
(defaults to "white") (optional)
-header_text_size
(defaults to "+2") (optional)
-calendar_width
(defaults to "100%") (optional)
-day_bgcolor
(defaults to "#DDDDDD") (optional)
-today_bgcolor
(defaults to "yellow") (optional)
-day_text_color
(defaults to "white") (optional)
-empty_bgcolor
(defaults to "white") (optional)
-overlap_p
(defaults to "0") (optional)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 _ _ (public) ad_log_deprecated ad_log_deprecated (public) db_1row db_1row (public) dt_hour_diff dt_hour_diff (public, deprecated) dt_sysdate dt_sysdate (public) dt_widget_day dt_widget_day dt_widget_day->_ dt_widget_day->ad_log_deprecated dt_widget_day->db_1row dt_widget_day->dt_hour_diff dt_widget_day->dt_sysdate

Testcases:
No testcase defined.

dt_widget_list (public, deprecated)

 dt_widget_list -calendar_details calendar_details \
    [ -item_template item_template ] [ -start_date start_date ] \
    [ -end_date end_date ] [ -order_by order_by ] \
    [ -url_template url_template ]
Deprecated. Invoking this procedure generates a warning.

create a listing widget for lists (ben) I would like to ask forgiveness from the coding gods for this proc. Right now this is a big hack to make the schedule look a lot like the SloanSpace v1.0 display. Once we have thought this through a bit more, I will generalize this proc. I promise. Please forgive me. DEPRECATED: time is up Ben. This proc uses hardcoded markup and is therefore difficult to style. It is also not fully localized. Future reimplementations should leverage the templating system more.

Switches:
-calendar_details
(required)
-item_template
(defaults to "$item") (optional)
-start_date
(optional)
-end_date
(optional)
-order_by
(optional)
-url_template
(defaults to "?order_by=$order_by") (optional)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 _ _ (public) ad_log_deprecated ad_log_deprecated (public) dt_no_time_p dt_no_time_p (public) lc_time_fmt lc_time_fmt (public) util_AnsiDatetoPrettyDate util_AnsiDatetoPrettyDate (public, deprecated) dt_widget_list dt_widget_list dt_widget_list->_ dt_widget_list->ad_log_deprecated dt_widget_list->dt_no_time_p dt_widget_list->lc_time_fmt dt_widget_list->util_AnsiDatetoPrettyDate

Testcases:
No testcase defined.

dt_widget_week (public, deprecated)

 dt_widget_week [ -calendar_details calendar_details ] [ -date date ] \
    [ -large_calendar_p large_calendar_p ] \
    [ -master_bgcolor master_bgcolor ] \
    [ -header_bgcolor header_bgcolor ] \
    [ -header_text_color header_text_color ] \
    [ -header_text_size header_text_size ] \
    [ -day_template day_template ] \
    [ -day_header_size day_header_size ] \
    [ -day_header_bgcolor day_header_bgcolor ] \
    [ -calendar_width calendar_width ] [ -day_bgcolor day_bgcolor ] \
    [ -today_bgcolor today_bgcolor ] \
    [ -day_text_color day_text_color ] \
    [ -empty_bgcolor empty_bgcolor ] \
    [ -next_week_template next_week_template ] \
    [ -prev_week_template prev_week_template ] \
    [ -prev_next_links_in_title prev_next_links_in_title ] \
    [ -fill_all_days fill_all_days ]
Deprecated. Invoking this procedure generates a warning.

Returns a calendar for a specific week, with details supplied by Julian date. Defaults to this week. To specify details for the individual days (if large_calendar_p is set) put data in an ns_set calendar_details. The key is the Julian date of the day, and the value is a string (possibly with HTML formatting) that represents the details. The variables in the templates are: - day_template: julian,day,date,pretty_date - next_week_template: - prev_week_template: DEPRECATED: this proc uses hardcoded markup and is therefore difficult to style. It is also not localized. Many of the date operations happening here have now good tcl support through the clock api, which would make this code probably faster and certainly portable (Oracle query is missing). Future reimplementations should leverage the templating system more.

Switches:
-calendar_details
(optional)
-date
(optional)
-large_calendar_p
(defaults to "1") (optional)
-master_bgcolor
(optional)
-header_bgcolor
(optional)
-header_text_color
(defaults to "white") (optional)
-header_text_size
(defaults to "+2") (optional)
-day_template
(defaults to "<!--$julian-->$day") (optional)
-day_header_size
(defaults to "2") (optional)
-day_header_bgcolor
(defaults to "#666666") (optional)
-calendar_width
(defaults to "100%") (optional)
-day_bgcolor
(defaults to "#DCDCDC") (optional)
-today_bgcolor
(defaults to "#FFF8DC") (optional)
-day_text_color
(defaults to "white") (optional)
-empty_bgcolor
(defaults to "white") (optional)
-next_week_template
(optional)
-prev_week_template
(optional)
-prev_next_links_in_title
(defaults to "0") (optional)
-fill_all_days
(defaults to "0") (optional)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 ad_log_deprecated ad_log_deprecated (public) db_1row db_1row (public) dt_sysdate dt_sysdate (public) util_AnsiDatetoPrettyDate util_AnsiDatetoPrettyDate (public, deprecated) dt_widget_week dt_widget_week dt_widget_week->ad_log_deprecated dt_widget_week->db_1row dt_widget_week->dt_sysdate dt_widget_week->util_AnsiDatetoPrettyDate

Testcases:
No testcase defined.
[ hide source ] | [ make this the default ]

Content File Source

# /packages/acs-datetime/tcl/acs-calendar-procs.tcl

ad_library {

    Library for calendar display widgets

    @author  ron@arsdigita.com
    @creation-date 2000-11-21
    @cvs-id  $Id: acs-calendar-2-procs.tcl,v 1.46.2.3 2021/12/28 14:49:49 antoniop Exp $
}

d_proc -deprecated dt_widget_week {
    {-calendar_details ""}
    {-date ""}
    {-large_calendar_p 1}
    {-master_bgcolor ""}
    {-header_bgcolor ""}
    {-header_text_color "white"}
    {-header_text_size "+2"}
    {-day_template {<!--$julian-->$day}}
    {-day_header_size 2}
    {-day_header_bgcolor "#666666"}
    {-calendar_width "100%"}
    {-day_bgcolor "#DCDCDC"}
    {-today_bgcolor "#FFF8DC"}
    {-day_text_color "white"}
    {-empty_bgcolor "white"}
    {-next_week_template ""}
    {-prev_week_template ""}
    {-prev_next_links_in_title 0}
    {-fill_all_days 0}
} {
    Returns a calendar for a specific week, with details supplied by
    Julian date. Defaults to this week.

    To specify details for the individual days (if large_calendar_p is
    set) put data in an ns_set calendar_details.  The key is the
    Julian date of the day, and the value is a string (possibly with
    HTML formatting) that represents the details.

    The variables in the templates are:
    - day_template: julian,day,date,pretty_date
    - next_week_template:
    - prev_week_template:

    DEPRECATED: this proc uses hardcoded markup and is therefore
    difficult to style. It is also not localized. Many of the date
    operations happening here have now good tcl support through the
    clock api, which would make this code probably faster and
    certainly portable (Oracle query is missing). Future
    reimplementations should leverage the templating system more.

    @see /doc/acs-templating/
    @see /doc/acs-lang/
    @see clock
} {

    set today_date [dt_sysdate]

    if {$date eq ""} {
        set date $today_date
    }

    set current_date $date

    # Get information for the week
    db_1row select_week_info {}

    # Initialize the ns_set
    if {$calendar_details eq ""} {
        set calendar_details [ns_set create calendar_details]
    }

    # Loop through the days of the week
    set julian $sunday_julian
    set return_html "<table CELLPADDING=0 CELLSPACING=0 BORDER=0 width=95%>\n"

    # Navigation Bar
    append return_html [subst {<tr><td>
    <table cellpadding="3" cellspacing="0" border="0" width="90%" class="table-display">
    <tr class="table-header" bgcolor="lavender">
    <td align="center">
    [subst $prev_week_template]
    <span style="font-family:Arial,Helvetica; size: smaller">
    <b>[util_AnsiDatetoPrettyDate $sunday_date] - [util_AnsiDatetoPrettyDate $saturday_date]</b>
    </span>
    [subst $next_week_template]
    </td>
    </tr>
    </table></td></tr>
    }]

    append return_html [subst {<tr>
    <td>
        <table class="table-display" cellpadding="0" cellspacing="0" border="0" width="90%">}]

    set days_of_week {Sunday Monday Tuesday Wednesday Thursday Friday Saturday}
    foreach day $days_of_week {

        set lower_day [string tolower $day]
        set julian [set ${lower_day}_julian]
        set date [set ${lower_day}_date]
        set pretty_date [util_AnsiDatetoPrettyDate $date]
        set day_html [subst $day_template]

        if {$date == $today_date} {
            set bgcolor $today_bgcolor
        } else {
            set bgcolor $day_bgcolor
        }

        append return_html [subst {<tr><td class="cal-week" bgcolor="$bgcolor">$day_html &nbsp;</td>
        </tr>
        <tr>
        <td class="cal-week-event">
        <table cellpadding="0" cellspacing="0" border="0" width="100%">}]

        # Go through events
        while {1} {
            set index [ns_set find $calendar_details $julian]
            if {$index == -1} {
                break
            }

            append return_html [subst {
                <tr><td class="cal-week-event">
                <span style="font-size: smaller">[ns_set value $calendar_details $index]</span>
                </td></tr>
            }]

            ns_set delete $calendar_details $index
        }

        append return_html "</table></td></tr>"


        append return_html "</td></tr>\n"
        incr julian
    }

    append return_html "</table></td></tr></table>"

    return $return_html
}



d_proc -deprecated dt_widget_day {
    {-calendar_details ""}
    {-date ""}
    {-hour_template {$display_hour}}
    {-start_hour 0}
    {-end_hour 23}
    {-show_nav 1}
    {-prev_nav_template {<a href="?date=[ns_urlencode $yesterday]"><img border="0" src="[dt_left_arrow]" alt="[_ acs-datetime.back_one_day]"></a>}}
    {-next_nav_template {<a href="?date=[ns_urlencode $tomorrow]"><img border="0" src="[dt_right_arrow]" alt="[_ acs-datetime.forward_one_day]"></a>}}
    {-master_bgcolor "black"}
    {-header_bgcolor "black"}
    {-header_text_color "white"}
    {-header_text_size "+2"}
    {-calendar_width "100%"}
    {-day_bgcolor "#DDDDDD"}
    {-today_bgcolor "yellow"}
    {-day_text_color "white"}
    {-empty_bgcolor "white"}
    {-overlap_p 0}
} {
    Returns a calendar for a specific day, with details supplied by
    hour. Defaults to today.

    DEPRECATED: this proc uses hardcoded markup and is therefore
    difficult to style. It is also not localized. Many of the date
    operations happening here have now good tcl support through the
    clock api, which would make this code probably faster. Future
    reimplementations should leverage the templating system more.

    @see /doc/acs-templating/
    @see /doc/acs-lang/
    @see clock
} {

    if {$date eq ""} {
        set date [dt_sysdate]
    }

    set current_date $date

    # Initialize the ns_set
    if {$calendar_details eq ""} {
        set calendar_details [ns_set create calendar_details]
    }

    # Collect some statistics about the events (for overlap)
    for {set hour $start_hour} {$hour <= 23} {incr hour} {
        set n_events($hour) 0
        set n_starting_events($hour) 0
    }

    set calendar_details_2 [ns_set copy $calendar_details]

    for {set hour $start_hour} {$hour <= $end_hour} {incr hour} {
        if {$hour < 10} {
            set index_hour "0$hour"
        } else {
            set index_hour $hour
        }

        # Go through events
        while {1} {
            set index [ns_set find $calendar_details_2 $index_hour]
            if {$index == -1} {
                break
            }

            set item_val [ns_set value $calendar_details_2 $index]
            ns_set delete $calendar_details_2 $index
            # Count the num of events starting at this hour
            set n_starting_events($hour) [expr {$n_starting_events($hour) + 1}]

            # Diff the hours
            set hours_diff [dt_hour_diff -start_time [lindex $item_val 0] -end_time [lindex $item_val 1]]

            # Count the num of events at the hours of operations
            for {set i 0} {$i <= $hours_diff} {incr i} {
                set the_hour [expr {$hour + $i}]
                set n_events($the_hour) [expr {$n_events([expr {$the_hour - $i}]) + 1}]
            }
        }
    }

    # the MAX num of events
    set max_n_events 1
    for {set hour $start_hour} {$hour <= $end_hour} {incr hour} {
        if {$max_n_events < $n_events($hour)} {
            set max_n_events $n_events($hour)
            ns_log debug "BMA-DEBUG-CAL: Setting max_n_events to $max_n_events"
        }
    }

    # Select some basic stuff, sets day_of_the_week, yesterday, tomorrow vars
    db_1row select_day_info {}

    set return_html ""

    if {$show_nav} {
        set prev_nav [subst $prev_nav_template]
        set next_nav [subst $next_nav_template]
        append return_html "<table border=0 cellspacing=0 cellpadding=0 width=$calendar_width><tr class=\"table-header\"><th> $prev_nav &nbsp; &nbsp; $day_of_the_week $next_nav &nbsp; &nbsp; </th></tr>
</table>"
    }

    # Loop through the hours of the day
    append return_html "<table border=0 cellpadding=0 cellspacing=0 width=$calendar_width><tr><td><table cellpadding=1 cellspacing=0 border=0 width=100%>
"

    # The items that have no hour
    set hour ""
    set next_hour ""
    set start_time ""
    set odd_row_p 0
    set display_hour [subst {<img border="0" align="center" src="/resources/acs-subsite/diamond.gif" alt="[_ acs-datetime.All_day]">}]
    append return_html [subst {
        <tr class="odd"><td class="center" align="left" width="60" nowrap><span style="font-size: smaller;">[subst $hour_template]</span></td>
        <td colspan="$max_n_events"><span style="font-size: smaller">}]

    # Go through events
    while {1} {
        set index [ns_set find $calendar_details "X"]
        if {$index == -1} {
            break
        }

        if {$overlap_p} {
            append return_html "[lindex [ns_set value $calendar_details $index] 2]<br>"
        } else {
            append return_html "[ns_set value $calendar_details $index]<br>\n"
        }

        ns_set delete $calendar_details $index
    }

    append return_html "</span>
    </td></tr>"

    for {set hour $start_hour} {$hour <= $end_hour} {incr hour} {

        set next_hour [expr {$hour + 1}]

        if {$hour < 10} {
            set index_hour "0$hour"
        } else {
            set index_hour $hour
        }

        # display stuff
        if {$hour >= 12} {
            set ampm_hour [expr {$hour - 12}]
            set pm 1
        } else {
            set ampm_hour $hour
            set pm 0
        }

        if {$ampm_hour == 0} {
            set ampm_hour 12
        }

        if {$ampm_hour < 10} {
            set display_hour "$ampm_hour"
        } else {
            set display_hour "$ampm_hour"
        }

        append display_hour ":00 "

        if {$pm} {
            append display_hour "pm"
        } else {
            append display_hour "am"
        }

        if { $odd_row_p } {
            set class "odd"
            set odd_row_p 0
        } else {
            set class "even"
            set odd_row_p 1
        }

        set display_hour [subst $hour_template]
        append return_html "<tr class=\"$class\"><td class=\"center\" align=left width=\"60\" \"nowrap\"><nobr><span style=\"font-size: smaller\">$display_hour</span></nobr></td>\n"

        set n_processed_events 0

        # A flag to force completion of the row
        set must_complete_p 0

        # Go through events
        while {1} {
            set index [ns_set find $calendar_details $index_hour]
            if {$index == -1} {
                break
            }

            incr n_processed_events

            if {$overlap_p} {
                set one_item_val [ns_set value $calendar_details $index]

                set hour_diff [dt_hour_diff -start_time [lindex $one_item_val 0] -end_time [lindex $one_item_val 1]]

                set start_time $hour

                # Calculate the colspan
                if {$n_processed_events == $n_starting_events($hour)} {
                    # This is the last one, make it as wide as possible
                    if {$hour_diff > 0} {
                        set colspan 1
                        set must_complete_p 1
                    } else {
                        # HACK
                        set colspan 1
                        set must_complete_p 1
                        #set colspan [expr {$max_n_events - $n_events($hour) + 1}]
                    }
                } {
                    # Just make it one
                    set colspan 1
                }

                append return_html "<td valign=top rowspan=[expr {$hour_diff + 1}] colspan=$colspan><span style=\"font-size: smaller\">[lindex $one_item_val 2]</span></td>"
            } else {
                append return_html "[ns_set value $calendar_details $index]<br>\n"
            }

            ns_set delete $calendar_details $index
        }

        if {$n_processed_events == 0 || ($n_events($hour) < $max_n_events && $must_complete_p)} {
            if {$n_events($hour) == 0 || $n_events($hour) == $n_processed_events} {
                append return_html "<td colspan=\"[expr {$max_n_events - $n_events($hour)}]\" class=\"$class\">&nbsp;</td>"
            } else {
                for {set i 0} {$i < $max_n_events - $n_events($hour)} {incr i} {
                    append return_html "<td colspan=\"1\" class=$class>&nbsp;</td>"
                }
            }
        }

        append return_html "</tr>\n"
    }

    append return_html "</table>
</td></tr>
</table>"

    return $return_html
}



d_proc -deprecated dt_widget_list {
    {-calendar_details:required}
    {-item_template {$item}}
    {-start_date ""}
    {-end_date ""}
    {-order_by ""}
    {-url_template {?order_by=$order_by}}
} {
    create a listing widget for lists

    (ben) I would like to ask forgiveness from the coding gods for this proc.
    Right now this is a big hack to make the schedule look a lot like the SloanSpace v1.0
    display. Once we have thought this through a bit more, I will generalize this proc. I promise.
    Please forgive me.

    DEPRECATED: time is up Ben. This proc uses hardcoded markup and is
    therefore difficult to style. It is also not fully
    localized. Future reimplementations should leverage the templating
    system more.

    @see /doc/acs-templating/
    @see /doc/acs-lang/
} {
    # Check for zero size
    if {[ns_set size $calendar_details] == 0} {
        return "<i>No Items</i>"
    }

    # The title
    if {$start_date eq "" && $end_date eq ""} {
        #This used to be All Items but that was just taking up space and not adding value so now we assume All Items and only give a title if its something else. - Caroline@meekshome.com
        set title ""
    }

    if {$start_date eq "" && $end_date ne ""} {
        set $pretty_end_date [lc_time_fmt $end_date "%x"]
        set title "[_ acs-datetime.Items_until]"
    }

    if {$start_date ne "" && $end_date eq ""} {
        set title "Items starting [util_AnsiDatetoPrettyDate $start_date]"
    }

    if {$start_date ne "" && $end_date ne ""} {
        set title "Items from [util_AnsiDatetoPrettyDate $start_date] to [util_AnsiDatetoPrettyDate $end_date]"
    }

    set return_html "<b>$title</b><p>"

    # Prepare the templates
    set real_order_by $order_by
    set order_by "item_type"
    set item_type_url [subst $url_template]
    set order_by "start_date"
    set start_date_url [subst $url_template]

    # Create the header
    append return_html [subst {
        <table class="table-display" border="0" cellspacing="0" cellpadding="2">
        <tr class="table-header">
        <th>Day of Week</th>
        <th><a href="[ns_quotehtml $start_date_url]">Date</a></th>
        <th>Start Time</th>
        <th>End Time</th>
    }]

    if {$real_order_by ne "item_type"} {
        append return_html [subst {<th><a href="[ns_quotehtml $item_type_url]">Type</a></th>}]
    }


    append return_html "<th>Title</th></tr>\n"

    # initialize the item_type so we can do intermediate titles
    set old_item_type ""

    set flip 0

    # Loop through the events, and add them
    foreach item [ns_set values $calendar_details] {
        lassign $item date start_time end_time weekday item_type item_details

        # Adjust the display of no-time items
        if {[dt_no_time_p -start_time $start_time -end_time $end_time]} {
            set start_time "--"
            set end_time "--"
        }

        # Do we need a title?
        if {$real_order_by eq "item_type" && $item_type != $old_item_type} {
            if {$item_type eq ""} {
                set item_type_for_title "(No Item Type)"
            } else {
                set item_type_for_title $item_type
            }
            append return_html [subst {<tr class="table-title"><td colspan="5"><b>$item_type_for_title</b></td></tr>}]
            set flip 0
        }

        set old_item_type $item_type

        if {$flip % 2 == 0} {
            set z_class odd
        } else {
            set z_class even
        }

        append return_html "
        <tr class=$z_class><td>$weekday</td><td>$date</td><td>$start_time</td><td>$end_time</td>"

        if {$real_order_by ne "item_type"} {
            append return_html "<td>$item_type</td>"
        }

        append return_html "<td>$item_details</td></tr>\n"
        incr flip
    }

    append return_html "</table>
<!-- End of dt_widget_list --->"

    return $return_html
}


#
# Additional Utility Procs
#

d_proc -public dt_midnight_p {
    time
} {
    Check if a time is midnight.

    This might be replaced by clock idioms in the future, but is
    currently the way we decide e.g. if an event is an all-day event.

    @see dt_no_time_p
} {
    if {$time eq "00:00" || $time eq ""} {
        return 1
    }

    if {[regexp {00:00 *[aA][mM]} $time the_match]} {
        return 1
    }

    if {[regexp {12:00 *[aA][mM]} $time the_match]} {
        return 1
    }

    if {[regexp {[0-9]+-[0-9]+[0-9]+ (0?)0:0(0?)} $time the_match]} {
        return 1
    }

    if {[regexp {[0-9]+-[0-9]+ (0?)0:0(0?)} $time the_match]} {
        return 1
    }
    return 0
}

d_proc -public dt_no_time_p {
    {-start_time:required}
    {-end_time:required}
} {
    This decides whether an item is without a time, which is also our
    definition of an all-day event.
} {
    # Compare times and make sure it's midnight on both
    if {[dt_midnight_p $start_time] && [dt_midnight_p $end_time]} {
        return 1
    } else {
        return 0
    }
}

d_proc -deprecated dt_hour_diff {
    {-start_time:required}
    {-end_time:required}
} {
    24-hour times input (23:00,02:00).
    This gives us the num of hours of difference,
    taking into account that if something goes until 5:01, it is one
    more hour long than if it goes until 5:00

    DEPRECATED: this is really something one should do leveraging
    existing tcl capabilities. Plain clock idioms can do the same in a
    more generic and reliable way.

    @see clock
} {
    set start_hour [string trimleft [string range $start_time 0 1] 0]
    set end_hour [string trimleft [string range $end_time 0 1] 0]
    set end_minutes [string range $end_time 3 4]

    # Special case when the hour is exact
    if {$end_minutes eq "00" } {
        return [expr {$end_hour - $start_hour - 1}]
    } else {
        return [expr {$end_hour - $start_hour}]
    }
}

# Local variables:
#    mode: tcl
#    tcl-indent-level: 4
#    indent-tabs-mode: nil
# End: