#!/usr/bin/perl
# before anything else, the script needs to find out its own name
#
# some servers (notably IIS on windows) don't set the cwd to the script's
# directory before executing it. So we get that information
# from $0 (the full name & path of the script).
BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_}
$name = $0;
$name =~ s/.+\/?.+\///; # for unix
$name =~ s/.+\\.+\\//; # for windows
$path = $0;
$path =~ s/(.+\/).+/$1/g; # for unix
$path =~ s/(.+\\).+/$1/g; # for windows
if ($path ne "")
{
chdir $path;
push @INC,$path;
}
# finished discovering name
# some global variables (more further down)
local $plans_version = "6.0.2"; # version
local $debug_info;
local $perl_version = (sprintf ("%vd",$^V));
local $data_storage_mode;
local $fatal_error = 0; # fatal errors cause plans to abort and print an error message to the browser
local $error_info = "";
local $html_output;
local $event_details_template;
local %calendars;
local %current_calendar;
local %latest_calendar;
local %latest_new_calendar;
local $max_cal_id = 0;
local $max_new_cal_id = 0;
local $max_series_id = 0;
local %events;
local %current_event;
local %latest_event;
local $max_event_id = 0;
local %text;
local $max_remote_event_id = 0;
local $default_template_path = "";
local $theme_url = "";
local $choose_themes = "";
local $graphics_url = "";
local $icons_url = "";
local $input_cal_id_valid = 0;
local $right_click_menus_enabled = 0;
local %cal_options;
local $rightnow;
local @months;
local @months_abv;
local @day_names;
local $loaded_all_events; # flag used to avoid calling load_events("all") twice
# not needed for calendars (we always load all calendars)
# check for required modules.
my $module_found=0;
foreach $temp_path (@INC)
{
if (-e "$temp_path/plans_config.pl")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "Unable to locate plans_config.pl! It should be in the same directory as plans.cgi!\n";
}
else {require "plans_config.pl";}
$module_found=0;
foreach $temp_path (@INC)
{
if (-e "$temp_path/CGI")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "unable to locate required module CGI!\n";
}
else
{use CGI;}
$module_found=0;
foreach $temp_path (@INC)
{
if (-e "$temp_path/CGI/Carp.pm")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "unable to locate required module CGI::Carp!\n";
}
else
{use CGI::Carp qw/fatalsToBrowser/;}
$module_found=0;
foreach $temp_path (@INC)
{
if (-e "$temp_path/Time")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "unable to locate required module Time.pm!\n";
}
else
{use Time::Local;}
$module_found=0;
foreach $temp_path (@INC)
{
if (-e "$temp_path/IO.pm")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "unable to locate required module IO.pm!\n";
}
else
{use IO::Socket;}
if ($fatal_error == 1) # print error and bail out
{
&fatal_error();
}
$module_found=0;
foreach $temp_path (@INC)
{
if (-r "$temp_path/plans_lib.pl")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "Unable to locate plans_lib.pl! It should be in the same directory as plans.cgi!\n";
}
else {require "plans_lib.pl";}
# get the language file, if one is defined
if (defined $language_file)
{
$module_found=0;
foreach $temp_path (@INC)
{
if (-r "$temp_path/$language_file")
{$module_found=1;}
}
if ($module_found == 0)
{
$fatal_error=1;
$error_info .= "Unable to locate language file $language_file! It should be in the same directory as plans.cgi!\n";
}
else {require $language_file;}
}
else
{
$fatal_error=1;
$error_info .= "No language file defined in plans.config!\n";
}
# check for perl version
my $temp = substr($perl_version,0,3);
if ($temp < 5.6) {
$fatal_error=1;
$error_info .= "Your version of perl ($perl_version) is too old! Plans requires perl version 5.6 or better.\n";
}
if ($fatal_error == 1) # print error and bail out
{
&fatal_error();
}
# init cgi stuff
$q = new CGI;
$script_url = $q->url(-path_info>=1);
$script_url =~ /(.*)\//; # remove trailing / and all text after
$script_url = $1; # remove trailing / and all text after
# check if data files or tables are present
&check_data();
# fatal error? Print error and bail out
if ($fatal_error == 1)
{&fatal_error();}
if ($choose_themes)
{
$theme_url=$q->param('theme_url');
$theme_url=$theme_url;
}
if ($theme_url eq "")
{$theme_url = "$script_url/theme";}
$graphics_url ="$theme_url/graphics"; # where misc. graphics are
$icons_url = "$theme_url/icons"; # where icons are
$css_path = "$theme_url/plans.css"; # css file
# globals for http parameters
my $active_tab = $q->param('active_tab');
my $add_edit_cal_action = $q->param('add_edit_cal_action');
local $current_cal_id = $q->param('cal_id');
$current_cal_id = 0 if ($current_cal_id eq "" || $current_cal_id =~ /\D/);
my $add_edit_event = $q->param('add_edit_event');
local $current_event_id = $q->param('evt_id');
local $cal_num_months = $q->param('cal_num_months');
local $cal_start_month = $q->param('cal_start_month');
local $cal_start_year = $q->param('cal_start_year');
my $special_action = $q->param('special_action');
local $cal_or_list = $q->param('cal_or_list');
# other globals
my $event_start_date;
my $event_start_timestamp;
my $event_days;
my $start_mday;
my $start_mon;
my $start_year;
my @timestamp_array;
my $recur_end_timestamp;
# load calendar data
&load_calendars();
foreach $cal_id (keys %calendars)
{
if ($cal_id eq $current_cal_id && $cal_id ne "")
{$input_cal_id_valid = 1;}
}
if (!$input_cal_id_valid)
{
$current_cal_id=0;
#$q->param(-name=>'cal_id',-values=>[0]);
}
# make all calendars selectable by default
foreach $cal_id (keys %calendars)
{$default_cal{selectable_calendars}{$cal_id} = 1;}
%current_calendar = %{$calendars{$current_cal_id}};
# time-related globals
$rightnow = time() + 3600 * $current_calendar{gmtime_diff};
@rightnow_array = gmtime $rightnow;
$rightnow_year = $rightnow_array[5]+1900;
$rightnow_month = $rightnow_array[4];
$rightnow_mday = $rightnow_array[3];
$next_year = $rightnow_year+1;
$rightnow_description = formatted_time($rightnow, "hh:mm:ss mn md yy");
@weekday_sequence = @day_names;
# custom stylesheet?
if ($current_calendar{custom_stylesheet} ne "")
{
$css_path = "http://$current_calendar{custom_stylesheet}";
}
# if this is a custom calendar request, shoehorn the request parameters in
if ($q->param('custom_calendar') == 1)
{
$current_cal_id = $q->param('custom_calendar_calendar');
@custom_calendar_backgound_calendars = $q->param('custom_calendar_background_calendars');
foreach $local_background_calendar (keys %{$calendars{$current_cal_id}{local_background_calendars}})
{delete $calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar};}
foreach $local_background_calendar (@custom_calendar_backgound_calendars)
{$calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar} = 1;}
%current_calendar = %{$calendars{$current_cal_id}};
}
# make sure we can select the current calendar
#$current_calendar{selectable_calendars}{$current_cal_id} = 1;
# set info window height & width
my ($info_window_width, $info_window_height) = split("x", $current_calendar{info_window_size});
# rotate weekday_sequence by the offset defined in the week start day.
for ($l1=0;$l1 < $current_calendar{week_start_day};$l1++)
{push @weekday_sequence, (shift @weekday_sequence);}
# load background_colors
my @temp_lines = split ("\n", $event_background_colors);
foreach $temp_line (@temp_lines)
{
if ($temp_line !~ /\w/) # skip any blank lines
{next;}
$temp_line =~ s/^\s+//;
my ($hex_color, $hex_color_title) = split (/,*\s+/, $temp_line, 2);
if ($hex_color_title eq "")
{$hex_color_title = " ";}
push @event_bgcolors, {color => $hex_color, title => $hex_color_title};
}
my $template_html;
#load template
my $custom_template_file_found=1;
my $local_template_file = 0; # tells whether the template was loaded via a filesystem open or through a http request.
if ($current_calendar{custom_template} ne "") # custom template
{
$template_html = &get_remote_file("$current_calendar{custom_template}");
if ($template_html !~ /###/)
{
$custom_template_file_found=0;
$lang{custom_template_fail} =~ s/###template###/$current_calendar{custom_template}/;
$debug_info .= "$lang{custom_template_fail}\n";
}
}
if ($current_calendar{custom_template} eq "" || $custom_template_file_found ==0)
{
if (!(-e "$default_template_path"))
{
$fatal_error=1;
$lang{default_template_fail} =~ s/###template###/$default_template_path/;
$debug_info .= "$lang{default_template_fail}\n";
&fatal_error();
}
else
{
open (FH, "$default_template_path") || ($debug_info .=" Unable to open default template file $default_template_path for reading ");
flock FH,2;
@template_lines=;
close FH;
$template_html = join "", @template_lines;
$local_template_file = 1;
}
}
# separate the main calendar template and the event details template
$event_details_template = $template_html;
$template_html =~ s/<\/html>.+/<\/html>/s;
$template_html =~ s/.+<\/event_details>//s; # needed in case the event details aren't at the bottom of the html. It happens.
if ($event_details_template =~ // && $event_details_template =~ /<\/event_details>/)
{
$event_details_template =~ s/.*//s;
$event_details_template =~ s/<\/event_details>.+//s;
}
else
{
$debug_info .= "Warning! No event details template found. (The template file doesn't contain <event_details>...</event_details>\n";
$event_details_template = "";
}
# ssi-style includes in the template
if ($local_template_file)
{
my $new_html = $template_html;
$template_html =~ s/###include\s+(.+)###/&load_file($1)/ge;
#while ($new_html =~ s/###include\s+(.+)###//g)
if(0)
{
my $include_file=$1;
if (-e $include_file)
{
open (FH, "$include_file") || ($debug_info .=" unable to open include file $include_file for reading ");
flock FH,2;
my @include_lines=;
close FH;
$include_html = join "", @include_lines;
}
$template_html =~ s/###include\s+(.+)###/$include_html/;
}
}
sub load_file()
{
my ($file)=@_;
if (-e $file)
{
open (FH, "$file") || (return "unable to open include file $file for reading");
flock FH,2;
my @lines=;
close FH;
$text = join "", @lines;
return $text;
}
else
{
return "file $file does not exist";
}
}
if($choose_themes)
{
my $theme_file="choose_theme.html";
my $theme_html="";
if (-e $theme_file)
{
open (FH, "$theme_file") || ($debug_info .=" unable to open theme file $theme_file for reading ");
flock FH,2;
my @theme_lines=;
close FH;
$theme_html = join "", @theme_lines;
}
$template_html =~ s/###choose theme###/$theme_html/;
}
else
{
$template_html =~ s/###choose theme###//;
}
#evaluate browser type and version
$_ = $ENV{HTTP_USER_AGENT};
if (/Mozilla/) {
if (/Opera.([0-9\.]+)/) { $browser_type = 'Opera'; $browser_version=$1;}
elsif (/MSIE.([0-9.]+)/) { $browser_type = 'IE'; $browser_version = $1;}
elsif (/Mozilla\/([0-9\.]+)/) {$browser_type = 'Mozilla'; $browser_version=$1;
if (($browser_version<5) || (/Netscape/)) {$browser_type = "Netscape";} }
if (/\)[^0-9.]+[0-9]*[\/\ ]([0-9.]+)/) {$browser_version=$1;}
} elsif (/(\w+)\/([0-9\.]+)/) {$browser_type = $1; $browser_version = $2}
#evaluate, transform, tweak, adjust, modify input values
#$debug_info .= "browser type: $browser_type ";
#if the input is greater than the number of tabs, things look goofy
if ($q->param('active_tab') >= scalar @tab_text || $q->param('active_tab') eq "")
{
$active_tab = 0;
}
#if no month is selected, use the current month
if ($cal_start_month eq "")
{
$cal_start_month = $rightnow_month;
#$cal_start_month = 2;
}
#if the input year is out of range use the current year
if (($cal_start_year+0) < 1902 || ($cal_start_year+0)> 2037)
{
$cal_start_year = $rightnow_year;
}
if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months})
{
$cal_num_months = "$current_calendar{default_number_of_months}";
}
if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months})
{
$cal_num_months = 1;
}
#calculate calendar end month and year
$cal_end_month = $cal_start_month;
$cal_end_year = $cal_start_year;
for ($l1=1;$l1<$cal_num_months;$l1++)
{
$cal_end_month++;
if ($cal_end_month == 12)
{
$cal_end_month=0;
$cal_end_year++;
}
}
#check to make sure num_months+cal_start_date doesn't go out of bounds
if ($cal_end_year < 1902 || $cal_end_year> 2037)
{
$cal_end_year = $cal_start_year;
$cal_end_month = $cal_start_month;
$cal_num_months = 1;
}
# time window for loading events
my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year) - 2592000;
my $cal_end_timestamp = timegm(0,0,0,1,$cal_end_month,$cal_end_year) + 5184000;
if ($q->param('cal_start_timestamp') ne "" && $q->param('cal_start_timestamp') !~ /\D/)
{$cal_start_timestamp = $q->param('cal_start_timestamp');}
if ($q->param('cal_end_timestamp') ne "" && $q->param('cal_end_timestamp') !~ /\D/)
{$cal_end_timestamp = $q->param('cal_end_timestamp');}
#$debug_info .="start: $cal_start_timestamp\nend: $cal_end_timestamp\nrightnow: $rightnow\n";
# load event data, for main calendar and its background calendars
my @temp_calendars = ($current_cal_id);
foreach $local_background_calendar (keys %{$current_calendar{local_background_calendars}})
{push @temp_calendars, $local_background_calendar;}
&load_events($cal_start_timestamp, $cal_end_timestamp, \@temp_calendars);
if ($current_event_id ne "")
{
&load_event($current_event_id);
%current_event = %{$events{$current_event_id}};
}
# load events from remote background calendars
if (scalar keys %{$current_calendar{remote_background_calendars}} > 0)
{
$remote_calendars_status="";
my $temp = scalar keys %{$current_calendar{remote_background_calendars}};
foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}})
{
# pull in remote calendar name
my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url};
$remote_calendar_complete_url = $remote_calendar_url;
#$debug_info .= "remote calendar: $remote_calendar_complete_url\n";
$remote_calendar_complete_url .= "?remote_calendar_request=1&cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}&cal_start_year=$cal_start_year&cal_start_month=$cal_start_month&num_months=$cal_num_months";
#$debug_info .= "remote calendar url: $remote_calendar_complete_url\n";
my $xml_results = &get_remote_file($remote_calendar_complete_url);
if ($xml_results =~ //)
{
$xml_results =~ s/</g;
$xml_results =~ s/>/>/g;
$debug_info .= "Error fetching remote calendar: $xml_results\n";
}
else
{
my %remote_calendars = %{&xml2hash($xml_results)};
my $remote_cal_title=$remote_calendars{'xml'}{calendar}{title};
my $temp=$xml_results;
$temp=~ s/>/>/g;
$temp=~ s/</g;
#$debug_info .= "xml results: $temp\n";
&load_remote_events($xml_results, $current_calendar{remote_background_calendars}{$remote_calendar_id});
}
}
}
#calculate next and previous start months & years
$previous_cal_start_month=$cal_start_month-$cal_num_months;
$previous_cal_start_year=$cal_start_year;
if ($previous_cal_start_month < 0)
{
$previous_cal_start_month +=12;
$previous_cal_start_year--;
}
if ($cal_num_months > 1)
{
$prev_string = $lang{previous_months};
$prev_string =~ s/###num###/$cal_num_months/;
}
else
{
$prev_string = $lang{previous_month};
}
$next_cal_start_month=$cal_start_month+$cal_num_months;
$next_cal_start_year=$cal_start_year;
if ($next_cal_start_month > 11)
{
$next_cal_start_month -= 12;
$next_cal_start_year++;
}
if ($cal_num_months > 1)
{
$next_string = $lang{next_months};
$next_string =~ s/###num###/$cal_num_months/;
}
else
{
$next_string = $lang{next_month};
}
$consistent_parameter_string="";
&make_consistent ("cal_id");
&make_consistent ("cal_start_month");
&make_consistent ("cal_start_year");
&make_consistent ("cal_num_months");
&make_consistent ("cal_or_list");
&make_consistent ("theme_url");
if ($q->param('diagnostic_mode') eq "1")
{
&diagnostic_mode();
exit(0);
}
if ($q->param('detect_remote_calendars') eq "1")
{
&detect_remote_calendars();
exit(0);
}
if ($q->param('remote_calendar_request') eq "1")
{
&remote_calendar_request();
exit(0);
}
if ($q->param('export_calendar') eq "1")
{
if ($q->param('export_type') eq "ascii_text")
{
&ascii_text_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
exit(0);
}
elsif ($q->param('export_type') eq "csv_file")
{
&csv_file($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
exit(0);
}
elsif ($q->param('export_type') eq "vcalendar")
{
&vcalendar_export_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
exit(0);
}
}
if ($q->param('export_event') eq "1")
{
if ($q->param('export_type') eq "ascii_text")
{
&ascii_text_event();
exit(0);
}
elsif ($q->param('export_type') eq "icalendar")
{
&icalendar_export_event();
exit(0);
}
elsif ($q->param('export_type') eq "vcalendar")
{
&vcalendar_export_event();
exit(0);
}
}
elsif ($q->param('view_event') eq "1")
{
&view_event();
exit(0);
}
elsif ($q->param('email_reminder') eq "1")
{
&email_reminder_prompt();
exit(0);
}
elsif ($q->param('email_reminder_confirm') eq "1")
{
&email_reminder_confirm();
exit(0);
}
elsif ($special_action eq "preview_event")
{
&preview_event();
exit(0);
}
elsif ($special_action eq "preview_date")
{
&preview_date();
exit(0);
}
$html_output .=<
p1
chomp $insert_text;
$html_output =~ s/###javascript stuff###/$insert_text/;
#default page
&display_default();
exit(0);
sub display_default
{
chomp $insert_text;
$html_output =~ s/###css file###/$css_path/g;
# tab menu stuff
$menu_tabs[0] = {status => "inactive",
html => "$tab_text[0]"};
$menu_tabs[1] = {status => "inactive",
html => "$tab_text[1]"};
$menu_tabs[2] = {status => "inactive",
html => "$tab_text[2]"};
$menu_tabs[$active_tab]{status} ="active";
$menu_tabs[2]{html} = "$tab_text[2]";
$insert_text =<
p1
# this kludge sucks!
if ($browser_type eq "IE")
{$tab_vert_offset=4;}
else
{$tab_vert_offset=0;}
#lay out the actual menu tabs
for ($l1=0;$l1 $$menu_tab{html}
p1
$noinsert_text .=<$$menu_tab{html}
p1
}
$insert_text .=<
p1
chomp $insert_text;
if ($q->param('custom_calendar') == 1)
{
$html_output =~ s/###tab menu stuff###//;
}
else
{
$html_output =~ s/###tab menu stuff###/$insert_text/;
}
$insert_text ="";
#invisible html for context menu
$insert_text .=<
p1
#main box stuff
$insert_text .=<
p1
if ($q->param('custom_calendar') == 1)
{
$html_output =~ s/###calendar controls###//g;
}
else
{
$html_output =~ s/###calendar controls###/$cal_controls_text/g;
}
$insert_text .= &do_calendar_list_view();
#select event range
$cal_month_start_date = timegm(0,0,0,1,$cal_start_month,$cal_start_year);
@cal_month_start_date_array = gmtime $cal_month_start_date;
$events_start_timestamp = $cal_month_start_date - 604800; # +7 day margin
$events_end_timestamp = &find_end_of_month($cal_end_month, $cal_end_year) + 604800; # +7 day margin
#now that we have selected the appropriate events, we can
#generate the corresponding javascript and calendar view
#and insert/add it to the html output.
$common_javascript = &common_javascript();
$page_javascript = &calendar_view_javascript($events_start_timestamp, $events_end_timestamp);
#display browser-appropriate javascript
if ($browser_type eq "IE")
{$browser_javascript = &IE_javascript();}
else
{$browser_javascript = &NS6_javascript();}
#replace javascript placeholders with actual html/javascript code
$html_output =~ s/###common javascript###/$common_javascript/;
$html_output =~ s/###page-specific javascript###/$page_javascript/;
$html_output =~ s/###browser-specific javascript###/$browser_javascript/;
my $temp1 .=<$prev_string
p1
my $temp2 .=<$next_string
p1
$html_output =~ s/###previous month link###/$temp1/g;
$html_output =~ s/###next month link###/$temp2/g;
}
elsif ($active_tab eq "1") #the second tab is the add/edit events view
{
$html_output =~ s/###calendar controls###//;
$insert_text .=<
p1
$insert_text .= &add_edit_events();
$insert_text .=<
p1
#generate javascript for add/edit events page
$common_javascript = &common_javascript();
$page_javascript = &add_edit_events_javascript();
#display browser-appropriate javascript
if ($browser_type eq "IE")
{$browser_javascript = &IE_javascript();}
else
{$browser_javascript = &NS6_javascript();}
#replace javascript placeholders with actual html/javascript code
$html_output =~ s/###common javascript###/$common_javascript/;
$html_output =~ s/###page-specific javascript###/$page_javascript/;
$html_output =~ s/###browser-specific javascript###/$browser_javascript/;
# sneak in the color select javascript before all other javascript.
my $temp =<
p1
$html_output =~ s/(
p1
$html_output =~ s/(
p1
}
else
{
$javascript_info .=<
p1
}
$javascript_info =~ s/\//\\\//g;
$javascript_info =~ s/\n/\\n/g;
$javascript_info =~ s/"/\\"/g;
$return_string .=<');
doc.write('');
doc.write('$lang{event_details}<\\/title>');
doc.write('');
doc.write('<\\/head>');
doc.write('');
doc.write('$javascript_info');
doc.write('');
doc.write(detail_string);
doc.write('<\\/body><\\/html>');
doc.close();
p1
}
else
{
$return_string .=<
p1
}
else
{
$javascript_info .=<
p1
}
$javascript_info =~ s/\n/\\n/g;
$javascript_info =~ s/"/\\"/g;
$javascript_info =~ s/\//\\\//g;
$return_string.=<');
doc.write('$lang{help_box_title}<\\/title>');
doc.write('');
doc.write('$javascript_info');
doc.write('');
doc.write(help_text);
doc.write('<\\/body><\\/html>');
doc.close();
info_window.focus();
}
function update_bg_color_select_box() {
// did the user just select custom?
if (document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].text == "custom")
{
document.getElementById("color_select_icon0").style.visibility = "visible";
}
else
{
document.getElementById("color_select_icon0").style.visibility = "hidden";
}
// take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked. Removing focus makes this go away)
document.add_event_form.dummy.style.display='inline';
document.add_event_form.dummy.focus();
document.add_event_form.dummy.style.display='none';
if (!document.add_event_form.evt_bgcolor)
return;
document.add_event_form.evt_bgcolor.style.background = document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value
//document.add_event_form.evt_title.focus();
}
function update_preview_icon() {
var icon_preview_area = document.getElementById("icon_preview")
icon_name = document.add_event_form.evt_icon.options[document.add_event_form.evt_icon.selectedIndex].value
icon_preview_area.innerHTML = ""
if (!document.add_event_form.unit_number)
return;
var unit_number_preview_area = document.getElementById("unit_number_preview")
// remove non-numeric text from the string
var unit_number = document.add_event_form.unit_number.value;
unit_number = unit_number.replace(/[^0-9]/g, "");
// this next part might be really clever or really stupid (using a regex for something like this).
// regardless, it's only one line, and that's nice.
var unit_number_graphic_string = unit_number.replace(/([0-9])/g, "");
unit_number_preview_area.innerHTML = unit_number_graphic_string;
document.add_event_form.unit_number.value = unit_number;
// it would be nice if we could do things with the DOM model, as opposed to innerHTML, but
// that would be crazy cumbersome. The following is a non-working stab at it. Maybe useful someday.
//preview_area.nodeValue = "unit num";
//preview_area.appendChild(document.createTextNode("unit "));
}
function all_day_event_toggle(value)
{
var el0 = document.getElementById("all_day_event_toggle0");
el0.style.display="";
if (value)
el0.style.display="none";
}
function tab_show(tab_num)
{
if (tab_num == null) return;
var elList, i;
i=0;
// update all tabs.
while (document.getElementById("tab"+i) && i<100)
{
if (i == tab_num)
{
// If the tab is the new active tab, activate it.
document.getElementById("tab"+i).className += " active";
document.getElementById("tab_area"+i).style.display=""
document.getElementById("tab"+i).blur();
}
else
{
// Otherwise, make sure the tab is deactivated.
removename (document.getElementById("tab"+i),"active");
document.getElementById("tab_area"+i).style.display="none"
}
i++;
}
}
function preview_event() {
info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,width=300,height=200");
doc = info_window.document;
doc.open('text/html');
doc.write('');
doc.write('$lang{event_preview_title}<\\/title>');
doc.write('');
doc.write('$lang{generating_preview}<\\/font>');
doc.write('<\\/body><\\/html>');
doc.close();
document.add_event_form.special_action.value = "preview_event";
document.add_event_form.target = "info_window";
document.add_event_form.submit();
document.add_event_form.special_action.value = "";
document.add_event_form.target = "";
info_window.focus();
}
function recur_toggle() {
if (document.add_event_form.recurring_event.checked)
{
document.add_event_form.recurrence_type[0].disabled=false;
document.add_event_form.recurrence_type[1].disabled=false;
document.add_event_form.recurrence_type[2].disabled=false;
document.add_event_form.recurrence_type[3].disabled=false;
document.add_event_form.weekday_of_month_type.disabled=false;
document.add_event_form.custom_months.disabled=false;
document.add_event_form.year_fit_type[0].disabled=false;
document.add_event_form.year_fit_type[1].disabled=false;
document.add_event_form.custom_months.disabled=false;
if (!document.add_event_form.recurrence_type[1].checked)
document.add_event_form.weekday_of_month_type.disabled=true;
if (document.add_event_form.year_fit_type[0].checked)
document.add_event_form.custom_months.disabled=true;
document.add_event_form.recur_end_date.disabled=false;
}
else
{
document.add_event_form.recurrence_type[0].disabled=true;
document.add_event_form.recurrence_type[1].disabled=true;
document.add_event_form.recurrence_type[2].disabled=true;
document.add_event_form.recurrence_type[3].disabled=true;
setTimeout("document.add_event_form.every_x_days.disabled=true",100);
setTimeout("document.add_event_form.every_x_weeks.disabled=true",100);
setTimeout("document.add_event_form.weekday_of_month_type.disabled=true",100);
setTimeout("document.add_event_form.custom_months.disabled=true",100);
document.add_event_form.year_fit_type[0].disabled=true;
document.add_event_form.year_fit_type[1].disabled=true;
document.add_event_form.custom_months.disabled=true;
document.add_event_form.recur_end_date.disabled=true;
}
recurrence_type_update();
//alert(document.add_event_form.recurring_event.checked);
}
function recurrence_type_update(last)
{
document.add_event_form.weekday_of_month_type.disabled=true;
document.add_event_form.every_x_days.disabled=true;
document.add_event_form.every_x_weeks.disabled=true;
if (document.add_event_form.recurrence_type[1].checked && !document.add_event_form.recurrence_type[1].disabled)
{
document.add_event_form.weekday_of_month_type.disabled=false;
}
if (document.add_event_form.recurrence_type[2].checked && !document.add_event_form.recurrence_type[2].disabled)
{
document.add_event_form.every_x_days.disabled=false;
}
if (document.add_event_form.recurrence_type[3].checked && !document.add_event_form.recurrence_type[3].disabled)
{
document.add_event_form.every_x_weeks.disabled=false;
}
if (!last) setTimeout("recurrence_type_update(true)",100);
}
function recur_edit_toggle()
{
if (document.add_event_form.all_in_series.checked)
{
document.add_event_form.add_event_button.value="$lang{recurring_event_update_all1}";
document.add_event_form.del_event_button.value="$lang{recurring_event_delete_all1}";
}
else
{
document.add_event_form.add_event_button.value="$lang{update_event}";
document.add_event_form.del_event_button.value="$lang{delete_event1}";
}
}
function preview_dates() {
var i = 0;
var j = 0;
var info_window_x = window_x()-$info_window_width;
var info_window_y = window_y();
var evt_start_date = document.add_event_form.evt_start_date.value;
var evt_days = document.add_event_form.evt_days.value;
var recurring_event = "";
var every_x_days;
var every_x_weeks;
var recur_end_date;
var recurrence_type = "";
var year_fit_type = "";
var weekday_of_month_type = "";
if (document.add_event_form.recur_end_date)
{
every_x_days = document.add_event_form.every_x_days.value;
every_x_weeks = document.add_event_form.every_x_weeks.value;
recur_end_date = document.add_event_form.recur_end_date.value;
if (document.add_event_form.recurring_event.checked)
recurring_event = document.add_event_form.recurring_event.value;
for (i=0; i -1)
weekday_of_month_type = document.add_event_form.weekday_of_month_type.options[document.add_event_form.weekday_of_month_type.selectedIndex].value
var selects = new Array();
var custom_months = "";
if (document.add_event_form.custom_months.selectedIndex > -1)
for (j=0, i=document.add_event_form.custom_months.selectedIndex; i');
doc.write('');
doc.write('$lang{event_preview_computing}<\\/title>');
doc.write('');
doc.write('<\\/head>');
doc.write('');
doc.write('$lang{event_preview_computing}');
doc.write('<\\/body><\\/html>');
doc.close();
info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height");
info_window.focus();
}
p1
$help_text=<
$lang{help_evt_calendar1}
p1
}
#calculate where to start the calendar (first sunday)
#first, calculate what day of the week this month begins on
#format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
my $cal_month_start_date = timegm(0,0,0,1, $current_month, $current_year);
my @cal_month_start_date_array = gmtime $cal_month_start_date;
my $cal_start_day_offset = $cal_month_start_date_array[6] - $current_calendar{week_start_day};
if ($cal_start_day_offset < 0)
{
$cal_start_day_offset += 7;
}
my $cal_start_date = $cal_month_start_date - (86400 * $cal_start_day_offset);
my @cal_start_date_array = gmtime $cal_start_date;
my $cal_end_date = $cal_start_date + 86400*37;
my $next_month = $current_month+1;
if ($next_month == 12)
{ $next_month=0;}
#cal_date keeps track of the date (in timestamp format)
#as the calendar loop iterates through each day on the calendar page
my $cal_date = $cal_start_date;
my @cal_date_array = gmtime $cal_date;
my %max_day_events;
my %week_max_slots;
#make a first pass through the month, assemble event week events structure:
#week_events{week_index}{id} ={}
#this hash has 4 keys--start_weekday, start_day, length and slot_order (slot_order will be calculated in the second pass)
for ($l1=0;$cal_date_array[4] != $next_month;$l1++) #each calendar has 5 or 6 weeks
{
$week_start_timestamp = $cal_date;
$week_end_timestamp = $week_start_timestamp + 604800;
$max_day_events{$l1} = 0;
@cal_date_array = gmtime $cal_date;
foreach $event_id (keys %events)
{
my %event = %{$events{$event_id}};
#$debug_info .= "checking event $event_id ($event{start}, $event{end})\n";
#$debug_info .= "checking event $event_id ($event{start} - $event{end}) against week $l1 ($week_start_timestamp - $week_end_timestamp)\n";
if (time_overlap($event{start}, $event{end}, $week_start_timestamp, $week_end_timestamp))
{
#$debug_info .= "event $event_id\n";
#$debug_info .= "event $event_id ($event{days} days) in week $l1\n";
#$debug_info .= "check passed!\n";
@event_date_array = gmtime $event{start};
$event_start_weekday = $event_date_array[6] - $current_calendar{week_start_day};
my $days_before_week_start = 0;
my $days_after_week_end = 0;
# the event might fall completely within the week boundary, or it
# might overlap event begins or ends outside the week boundaries
# (there are four possible cases):
#the event both starts and ends outside this week
if ($event{start} < $week_start_timestamp && $event{end} > $week_end_timestamp)
{
$week_events{$l1}{$event{id}}{start_weekday} = 0;
$week_events{$l1}{$event{id}}{length} = 7;
}
#the event starts before this week and ends within it
elsif ($event{start} < $week_start_timestamp)
{
$days_before_week_start = int(($week_start_timestamp - $event{start})/86400);
$week_events{$l1}{$event{id}}{start_weekday} = 0;
$week_events{$l1}{$event{id}}{length} = $event{days} - $days_before_week_start;
}
#the event starts within this week and ends after it
elsif ($event{end} > $week_end_timestamp)
{
$days_after_week_end = int(($event{end} - $week_end_timestamp)/86400);
$week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
$week_events{$l1}{$event{id}}{length} = $event{days} - $days_after_week_end - 1; # <-- the -1 is necessary
}
#the event begins and ends within the week
else
{
$week_events{$l1}{$event{id}}{length} = $event{days};
$week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
}
if ($week_events{$l1}{$event{id}}{start_weekday} < 0)
{
$week_events{$l1}{$event{id}}{start_weekday} += 7;
}
elsif ($week_events{$l1}{$event{id}}{start_weekday} > 6)
{
$week_events{$l1}{$event{id}}{start_weekday} -= 7;
}
}
}
$temp_debug_info = "";
$cal_date += 604800;
# each day has at least two slots (the date, and a blank box beneath it)
for ($l2=0;$l2<7;$l2++)
{
$week_slots{$l1}{$l2}{0}{width}=1;
$week_slots{$l1}{$l2}{0}{depth}=1;
$week_slots{$l1}{$l2}{1}{width}=1;
$week_slots{$l1}{$l2}{1}{depth}=1;
}
#order the week_events
#fill in the %slots data structure:
# $week_slots{week_index}{day_index}{slot_index}
# $width = colspan
# $depth = rowspan
# $spacer = 1 if spacer slot.
# @ids = event ids
# hey man, that's a sharp-lookin' sort you got there.
foreach $week_event_id (sort {
if ($week_events{$l1}{$b}{length} == $week_events{$l1}{$a}{length})
{
if ($events{$b}{all_day_event} eq "1")
{return 1;}
else
{return $events{$a}{start} <=> $events{$b}{start};}
}
else
{return $week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length};}
} keys %{$week_events{$l1}})
{
#$debug_info .= "length: $week_events{$l1}{$week_event_id}{length} start: $events{$week_event_id}{start}\n";
$empty_slot = 0;
#starting at 1 leaves a row of empty slots (row 0), where the calendar dates will go.
for ($l4=1; $empty_slot != 1; $l4++)
{
$empty_slot = 1;
#check each day of the week_event, to make sure the slot is empty
for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++)
{
$day_index=$l2+$week_events{$l1}{$week_event_id}{start_weekday};
if (scalar @{$week_slots{$l1}{$day_index}{$l4}{ids}} > 0)
{
$empty_slot = 0;
}
}
$slot_index=$l4;
}
$temp_debug_info .= " event: $week_event start weekday $week_events{$l1}{$week_event_id}{start_weekday} slot: $slot_index ";
#fill up $week_slots with the new event (extend horizontally)
for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++)
{
#$slots_in_row{$l1}{$slot_index}++;
$day_index = $l2+$week_events{$l1}{$week_event_id}{start_weekday};
push @{$week_slots{$l1}{$day_index}{$slot_index}{ids}}, $week_event_id;
if ($l2==0) # first slot gets the width
{$week_slots{$l1}{$day_index}{$slot_index}{width} = $week_events{$l1}{$week_event_id}{length};}
else # other slots get 0 for length (they get absorbed later)
{$week_slots{$l1}{$day_index}{$slot_index}{width} = 0;}
$week_slots{$l1}{$day_index}{$slot_index}{depth} = 1;
}
#keep track of the maximum number of slots each week has
if ($slot_index > $week_max_slots{$l1})
{
$week_max_slots{$l1} = $slot_index;
$max_day_events{$l1} = $slot_index;
}
}
# give all blank slots width and depth of 1
for ($l2=0;$l2<7;$l2++)
{
for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) # for each slot
{
if ($week_slots{$l1}{$l2}{$l3}{depth} eq "" || $week_slots{$l1}{$l2}{$l3}{width} eq "")
{
$week_slots{$l1}{$l2}{$l3}{width}=1;
$week_slots{$l1}{$l2}{$l3}{depth}=1;
}
}
}
#$debug_info .= "week $l1 day 0, slot 2: ".$week_slots{$l1}{0}{2}{ids}[0]."\n";
my $total_spacers=0;
# insert spacer slots below multi-day events.
for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) # for each slot
{
my $inserted_spacers=0;
for ($l2=0;$l2<7;$l2++)
{
#if ($l3 != 3) {next};
if ($week_slots{$l1}{$l2}{$l3}{width} > 1) #multi-day event, add spacers beneath
{
# create spacer row
if ($inserted_spacers == 0)
{
# move everything else down and increment the number of rows
$week_max_slots{$l1}++;
for ($l4=0;$l4<7;$l4++) # insert blank slots
{
for ($l5=$week_max_slots{$l1};$l5>$l3+1;$l5--) # count backwards
{
$week_slots{$l1}{$l4}{$l5} = &deep_copy($week_slots{$l1}{$l4}{$l5-1});
}
$week_slots{$l1}{$l4}{$l3+1}{width}=1;
$week_slots{$l1}{$l4}{$l3+1}{depth}=1;
$week_slots{$l1}{$l4}{$l3+1}{spacer}=0;
$week_slots{$l1}{$l4}{$l3+1}{ids}=();
}
$inserted_spacers=1
}
# insert spacers into previously created row.
for ($l4=$l2;$l4<$l2+$week_slots{$l1}{$l2}{$l3}{width};$l4++)
{
$week_slots{$l1}{$l4}{$l3+1}{spacer}=1;
#$debug_info .= "inserted spacer into row: ".($l3+1).", column $l4, event ".($week_slots{$l1}{$l4}{$l3}{ids}[0])."\n";
$total_spacers++;
}
#$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";
}
}
}
#$debug_info .= "$total_spacers spacers inserted for week $l1.\n";
#$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";
#$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
# calculate slots in each row:
#for ($l2=0;$l2<7;needed for pre-5.8.3 way of calculating trim.
{
for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot
{
if ((scalar @{$week_slots{$l1}{$l2}{$l3}{ids}}) > 0 )
{
$slots_in_row{$l1}{$l3} += $week_slots{$l1}{$l2}{$l3}{width};
#$debug_info .= "event in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
}
if ($week_slots{$l1}{$l2}{$l3}{spacer} == 1)
{
$slots_in_row{$l1}{$l3}++;
#$debug_info .= "spacer in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
}
}
}
#$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
#$slots_in_row{$l1}{$slot_index}++;
# extend event slots vertically.
for ($l2=0;$l2<7;$l2++) # for each day of the week
{
for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot
{
if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0 && $week_slots{$l1}{$l2}{$l3}{width} > 0) # if this slot begins an event
{
my $start_slot = $l3+1;
for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++)
{
#$debug_info .= "checking slot $l4 below event slot ($l2, $l3)\n";
#if ($week_slots{$l1}{$l2}{$l4}{width} == 0)
# {next;}
if (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}} > 0 && $week_slots{$l1}{$l2}{$l4}{width} eq $week_slots{$l1}{$l2}{$l3}{width}) # another event below this one, with the same width.
{
#if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2")
# {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";}
#$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";
#$debug_info .= "same-width event slot below week $l1, slot ($l2, $l3)\n";
$week_slots{$l1}{$l2}{$l4}{width}=0;
$week_slots{$l1}{$l2}{$l4}{depth}=0;
$week_slots{$l1}{$l2}{$l3}{depth}++;
push @{$week_slots{$l1}{$l2}{$l3}{ids}}, @{$week_slots{$l1}{$l2}{$l4}{ids}};
#$slots_in_row{$l1}{$l4}--;
}
elsif ($week_slots{$l1}{$l2}{$l3}{width} == 1 && (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}) == 0 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0) # blank slot below 1-slot wide event slot
{
#if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2")
# {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";}
#$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";
#$debug_info .= "week $l1 slot ($l2, $l4) # ids:".scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}."\n";
#$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n";
$week_slots{$l1}{$l2}{$l4}{width}=0;
$week_slots{$l1}{$l2}{$l4}{depth}=0;
$week_slots{$l1}{$l2}{$l3}{depth}++;
#$debug_info .= "week $l1, slot ($l2, $l3) depth: $week_slots{$l1}{$l2}{$l3}{depth} \n";
}
else
{
#$debug_info .= "week $l1 slot ($l2, $l4) occupied. Finished attempting to extend slot $l3\n";
last;
}
}
}
}
}
#$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
# extend blank slots vertically into other blank slots.
for ($l2=0;$l2<7;$l2++) # for each day of the week
{
for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot
{
if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0)
{next;}
if ($week_slots{$l1}{$l2}{$l3}{width} > 0 && $week_slots{$l1}{$l2}{$l3}{spacer} == 0) # if it's blank (but not a spacer)
{
my $start_slot = $l3+1;
for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++)
{
if ($week_slots{$l1}{$l2}{$l4}{width} == 1 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0)
{
#$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n";
$week_slots{$l1}{$l2}{$l4}{width}=0;
$week_slots{$l1}{$l2}{$l4}{depth}=0;
$week_slots{$l1}{$l2}{$l3}{depth}++;
}
else
{last;}
}
}
}
}
#$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
#$debug_info .= "week $l1 slot (4, 1) depth: $week_slots{$l1}{4}{1}{depth}\n";
#$debug_info .= "week $l1 slot (0, 1) width: $week_slots{$l1}{0}{1}{width}\n";
# yet another pass. trim vertical depth and re-calculate max_slots
# calculate trim
my $trim = 0;
#$debug_info .= " week $l1 max slots: $week_max_slots{$l1}\n";
my $max_week_needed_slots=0;
my %max_day_needed_slots;
for ($l2=0;$l2<7;$l2++) # for each day of the week
{
my $found_single_day_event=0;
for ($l3=1;$l3<=$week_max_slots{$l1};$l3++)
{
if ($week_slots{$l1}{$l2}{$l3}{width} > 1) # if multi-day, or a spacer
{
#$debug_info .= "week $l1, found multi-day event (day $l2, width $week_slots{$l1}{$l2}{$l3}{width})\n";
for ($l4=0;$l4<$week_slots{$l1}{$l2}{$l3}{width};$l4++)
{
#$debug_info .= "week $l1, adding needed slot to day ".($l2+$l4)."\n";
$max_day_needed_slots{$l2+$l4}++;
}
}
elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0)
{
$max_day_needed_slots{$l2}++;
#$debug_info .= "week $l1, found spacer (day $l2)\n";
}
elsif (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) # single-day event
{
$found_single_day_event=1;
#$debug_info .= "week $l1, found single day event (day $l2)\n";
}
}
$max_day_needed_slots{$l2} += $found_single_day_event;
}
#$debug_info .= "week $l1, max_day_needed_slots: $max_day_needed_slots{0} $max_day_needed_slots{1} $max_day_needed_slots{2} $max_day_needed_slots{3} $max_day_needed_slots{4} $max_day_needed_slots{5} $max_day_needed_slots{6} $max_day_needed_slots{7}\n";
$max_week_needed_slots = max(values %max_day_needed_slots);
#if ($max_day_needed_slots >$max_week_needed_slots)
# {$max_week_needed_slots = $max_day_needed_slots;}
#$debug_info .= "max needed slots for week $l1, $max_week_needed_slots\n";
my $trim = $week_max_slots{$l1} - $max_week_needed_slots;
# apply trim
#$debug_info .= "trim for week $l1, $trim\n";
for ($l2=0;$l2<7;$l2++) # for each day of the week
{
for ($l3=$week_max_slots{$l1};$l3>0;$l3--) # for each slot, counting backwards (upwards)
{
if ($week_slots{$l1}{$l2}{$l3}{depth} > 0) # blank or non-blank, with depth > 0
{
#$debug_info .= "trimming week $l1, slot ($l2, $l3) by $trim\n";
$week_slots{$l1}{$l2}{$l3}{depth} = $week_slots{$l1}{$l2}{$l3}{depth} - $trim;
last;
}
}
}
$week_max_slots{$l1} = $week_max_slots{$l1} - $trim;
} # repeat for next week
# print day names
$return_text .=<
$weekday_sequence[0]
$weekday_sequence[1]
$weekday_sequence[2]
$weekday_sequence[3]
$weekday_sequence[4]
$weekday_sequence[5]
$weekday_sequence[6]
p1
#cal_date keeps track of the date (in timestamp format)
#as the calendar loop iterates through each day on the calendar page
$cal_date = $cal_start_date;
@cal_date_array = gmtime $cal_date;
#locked and loaded, data structures assembled--now it's time to kick it, calendar-style.
for ($l1=0;$cal_date_array[4] != $next_month; $l1++) #each calendar has 5 or 6 weeks
{
my $last_week=0;
my $timestamp_next_week = $cal_date+604800;
my @timestamp_next_week_array = gmtime $timestamp_next_week;
if ($timestamp_next_week_array[4] == $next_month)
{
$last_week = 1;
}
my $week_date_index = $cal_date;
# draw the table!
for ($l3=0;$l3<$week_max_slots{$l1}+1;$l3++)
{
$return_text .="
";
$week_date_index = $cal_date;
for ($l2=0;$l2<7;$l2++) # 7 days / week
{
@cal_date_array = gmtime $week_date_index;
my $td_class = "day ".lc($day_names[$l2]);
if ($cal_date_array[4] == $rightnow_month &&
$cal_date_array[3] == $rightnow_mday &&
$cal_date_array[5]+1900 == $rightnow_year)
{$td_class .= " today";}
#display date numbers differently, depending on whether they are
#in the current month or not
if ($cal_date_array[4] != $current_month)
{$td_class .= " other_month";}
#if ($l2 == $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} && $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} ne "")
if ($l3 == 0) #if it's the top blank slot, put the date in there.
{
$td_style="border-bottom-width:0px;";
#display the cell differently if it is today.
if ($cal_date_array[4] == $rightnow_month &&
$cal_date_array[3] == $rightnow_mday &&
$cal_date_array[5]+1900 == $rightnow_year)
{
# offset the date number a few pixels
# (so it will be in the center of the red circle)
# offset a bit more for a double-digit day number.
# small touches are the difference between good and great :)
my $date_div_style = "";
if ($rightnow_mday > 10)
{$date_div_style = "text-indent: 11px;";}
$return_text .=<
$cal_date_array[3]
p1
}
else
{
$return_text .=<
$cal_date_array[3]
p1
}
}
elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0) # spacer slot
{
my $spacer_class = "spacer";
if ($l3 == $week_max_slots{$l1}-1)
{
$spacer_class .= " bottom";
}
$return_text .=<
p1
}
elsif ($week_slots{$l1}{$l2}{$l3}{width} != 0) # slot containing events
{
$num_cols = $week_slots{$l1}{$l2}{$l3}{width};
$num_rows = $week_slots{$l1}{$l2}{$l3}{depth};
if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0)
{
$td_style="border-top-width:0px;border-bottom-width:0px;";
#($l2,$l3) $num_cols\lx$num_rows
$return_text .=<
p1
foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}})
{
my $event_bgcolor = $events{$event_id}{bgcolor};
my $event_box_class = "event_box";
if ($events{$event_id}{cal_id} != $current_calendar{id})
{
$event_box_class .= " background";
if ($current_calendar{background_events_display_style} eq "single_color")
{$event_bgcolor = $current_calendar{background_events_color};}
elsif ($current_calendar{background_events_display_style} eq "faded")
{
# create "faded" look for background event
my $faded_color = $events{$event_id}{bgcolor};
#convert rgb values from hex (00-FF) to decimal integer (0-255)
my $r = hex substr $faded_color,1,2;
my $g = hex substr $faded_color,3,2;
my $b = hex substr $faded_color,5,2;
#convert integer rgb values to hsv
my @hsv_array = &rgb2hsv($r,$g,$b);
#convert s and v from percentages to decimal
$hsv_array[1] = $hsv_array[1]/100;
$hsv_array[2] = $hsv_array[2]/100;
#"fade" the color (decrease saturation)
$hsv_array[1] = $hsv_array[1]/$current_calendar{background_events_fade_factor};
my @new_rgb_array = &hsv2rgb($hsv_array[0],$hsv_array[1],$hsv_array[2]);
#convert back to hex
$r = (sprintf ("%1.1X",$new_rgb_array[0]));
$g = (sprintf ("%1.1X",$new_rgb_array[1]));
$b = (sprintf ("%1.1X",$new_rgb_array[2]));
#$debug_info .= "
\n";
$event_bgcolor = "#$r$g$b";
}
}
# handle icon
my $icon_text = "";
my $unit_icon_text = "";
if ($events{$event_id}{unit_number} ne "")
{
$unit_icon_text = $events{$event_id}{unit_number};
$unit_icon_text =~ s/(\d)//g;
}
if ($events{$event_id}{icon} ne "blank")
{
$icon_text = <
p1
}
$icon_text = "$unit_icon_text$icon_text";
# context menu stuff
my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$events{$event_id}{series_id}');\"";
if ($event_id =~ /\D/)
{$event_context_menu_text=""}
if ($week_slots{$l1}{$l2}{$l3}{width} == 1)
{
my $event_time = "";
if ($events{$event_id}{all_day_event} ne "1")
{
$event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm");
# if both times are am or pm, remove the first one (it's redundant!)
$event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/;
$event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/;
$event_time = "$event_time";
}
$return_text .=<
$unit_icon_text$event_time $events{$event_id}{title}
p1
p1
}
else
{
# handle the case where an event stretches across two days not because it's >24 hours
# but because it crosses midnight.
my $temp="";
my $event_time = "";
if ($events{$event_id}{all_day_event} ne "1")
{
#my $offset = int(100*($events{$event_id}{start} - $week_date_index)/(86400*$week_slots{$l1}{$l2}{$l3}{width}));
#my $width = int(100*($events{$event_id}{end} - $events{$event_id}{start})/(86400*$week_slots{$l1}{$l2}{$l3}{width}));
my $offset = 25;
my $width = 50;
$temp = "width:$width%;position:relative;left:$offset%;";
$event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm");
# if both times are am or pm, remove the first one (it's redundant!)
$event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/;
$event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/;
$event_time = "$event_time";
}
$return_text .=<
$unit_icon_text$event_time $events{$event_id}{title}
p1
p1
}
} # next event id
$return_text .=<
p1
}
elsif ($week_slots{$l1}{$l2}{$l3}{ids} eq "" && $week_slots{$l1}{$l2}{$l3}{width} > 0) # blank slot
{
$td_style="border-top-width:0px;border-bottom-width:0px;";
#($l2,$l3) blank $num_cols\lx$num_rows
$return_text .=<
p1
}
}
$week_date_index += 86400;
} # next day
#right border
$return_text .=<
p1
} # event slot index
# this little trick is the cat's pajamas. It's another row of
# table cells that cause each calendar day to come down a little
# bit below the lowest event. It makes the calendar
# look sharp.
# Also, if the week has a small number of
# events, we expand the height of the bottom cell.
# This makes all the calendar cells look square,
# which is the bee's knees.
my $bottom_height_style = "";
if ($max_day_events{$l1} < 2)
{
my $height = (4-$max_day_events{$l1}) . "em"; # this algorithm was developed by guess & check
#my $height = "100px"; # this algorithm was developed by guess & check
$bottom_height_style = "line-height:$height;";
}
$return_text .=<
p1
$week_date_index = $cal_date;
for ($l2=0;$l2<7;$l2++) #each week has 7 days(!)
{
my $td_class = "";
@cal_date_array = gmtime $week_date_index;
$td_class .= "day ".lc($day_names[$l2])." cell_bottom";
if ($cal_date_array[4] != $current_month)
{
$td_class .= " other_month";
}
if ($cal_date_array[4] == $rightnow_month &&
$cal_date_array[3] == $rightnow_mday &&
$cal_date_array[5]+1900 == $rightnow_year)
{$td_class .= " today";}
$return_text .=<
p1
$week_date_index+=86400;
}
$return_text .=<
p1
$cal_date+=604800;
}
$return_text .=<
p1
#increment to the next month--the method used
#here is the most painless way of making
#this work the right way in all cases.
$current_month++;
if ($current_month == 12)
{
$current_month=0;
$current_year++;
}
}
return $return_text;
} #********************end generate_calendar subroutine**********************
sub generate_list
{
my $return_text = "";
($start_month, $start_year, $end_month, $end_year) = @_;
#calculate where to start and end the list
#format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
#loop through all the events. Create an array of events which fall
#within the current list view dates.
foreach $event_id (keys %events)
{
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
{
if ($events{$event_id}{cal_id} eq $current_cal_id)
{push @selected_cal_events, $event_id;}
else
{push @list_events, $event_id;}
}
}
# take the results of the previous sort and create a
# funky data structure (broken down according to the calendars currently
# selected)
# create hash to hold that data structure
# each element of this hash will be an array.
$shared_cal_events={}; #empty hash
#fill up that hash
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
{
foreach $event_id (@list_events)
{
if ($events{$event_id}{cal_id} eq $background_cal_id)
{push @{$shared_cal_events{$background_cal_id}}, $event_id;}
}
}
# initialize loop variables
$current_month = $start_month;
$current_year = $start_year;
$return_text .=<
p1
if ($cal_num_months> 1)
{
$return_text .=<
$calendars{$current_cal_id}{title}
p1
#display events for selected calendar
foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events)
{
%event = %{$events{$event_id}};
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
@event_start_timestamp_array = gmtime $event{start};
if ($event{days} == 1)
{ #single-day event
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
}
else #multi-day event
{
@event_end_timestamp_array = gmtime $event{end};
if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4])
{
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]";
}
else
{
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]";
}
}
my $icon_text="";
my $unit_icon_text="";
if ($event{unit_number} ne "")
{
$icon_text = $event{unit_number};
$icon_text =~ s/(\d)//g;
}
if ($event{icon} eq "blank")
{
$icon_text .= "$unit_icon_text";
}
else
{
$icon_text .= "$unit_icon_text";
}
my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$events{$event_id}{series_id}');\"";
if ($event_id =~ /\D/)
{$event_context_menu_text=""}
# event time
my $event_time = "";
if ($events{$event_id}{all_day_event} ne "1")
{
$event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm");
# if both times are am or pm, remove the first one (it's redundant!)
$event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/;
$event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/;
$event_time = "$event_time";
}
$return_text .=< $date_string $icon_text $event_time $event{title}
p1
}
}
if ($current_calendar{list_background_calendars_together} ne "yes")
{
$return_text .=<
p1
}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
{
if ($current_calendar{list_background_calendars_together} eq "no")
{
$return_text .=<
$calendars{$background_cal_id}{title}
p1
}
#list events for that calendar
foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
{
%event = %{$events{$event_id}};
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
@event_start_timestamp_array = gmtime $event{start};
#if the event headline is longer than 30 characters,
#split it into another line after the second word.
if ($event{days} == 1)
{ #single-day event
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
}
else #multi-day event
{
@event_end_timestamp_array = gmtime $event{end};
if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4])
{
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]";
}
else
{
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]";
}
}
my $icon_text="";
if ($event{unit_number} ne "")
{
$icon_text = $event{unit_number};
$icon_text =~ s/(\d)//g;
}
if ($event{icon} eq "blank")
{
$icon_text .= "$unit_icon_text";
}
else
{
$icon_text .= "$unit_icon_text";
}
my $date_style="line-height:120%;";
if ($icon_text eq "")
{$date_style="";}
my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$events{$event_id}{series_id}');\"";
if ($event_id =~ /\D/)
{$event_context_menu_text=""}
$return_text .=< $date_string $icon_text $event{title}
p1
}
}
if ($current_calendar{list_background_calendars_together} ne "yes")
{
$return_text .=<
p1
}
}
if ($current_calendar{list_background_calendars_together} eq "yes")
{
$return_text .=<
p1
}
$return_text .=<
p1
#increment to the next month--the method used
#here is the most painless way of making
#this work the right way in all cases.
$current_month +=1;
if ($current_month == 12)
{
$current_month=0;
$current_year++;
}
}
$return_text .=<
p1
}
else
{
$javascript_info .=<
p1
}
$javascript_info =~ s/\n/\\n/g;
$javascript_info =~ s/"/\\"/g;
$javascript_info =~ s/\//\\\//g;
$return_string .=<');
doc.write('$lang{calendar_details}<\\/title>');
doc.write('');
doc.write('');
doc.write('$javascript_info');
doc.write('');
doc.write(cal_details[cal_id].text);
doc.write('<\\/body><\\/html>');
doc.close();
info_window.focus();
}
function do_on_load() {
}
p1
return $return_string;
} #********************end cal_view_inf0_javascript subroutine**********************
sub generate_cal_details()
{
my ($calendar_ref) = @_;
my %calendar = %{$calendar_ref};
my $return_text = <
$calendar{title}
$calendar{details}
p1
$writable{calendar_file} and $return_text .= <$lang{calendar_add_edit}
p1
$return_text .= <
$lang{calendar_direct_link} $script_url/$name?cal_id=$calendar{id}
p1
return $return_text;
}
sub generate_cal_details_javascript()
{
my $return_string ="";
my $cal_detail_text = "";
foreach $cal_id (sort {$a <=> $b} keys %calendars)
{
$cal_detail_text = &generate_cal_details($calendars{$cal_id});
$cal_detail_text =~ s/\n/\\n/g;
#$cal_detail_text =~ s/\n/adsf/g;
$cal_detail_text =~ s/"/\\"/g;
$cal_detail_text =~ s/\//\\\//g;
$cal_defs .=< $events{$b}{start}} @selected_cal_events)
{
my %event = %{$events{$event_id}};
if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
@event_end_timestamp_array = gmtime $event{end};
my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
my $csv_description = $event{details};
$csv_description =~ s/"/""/g;
$csv_description =~ s/\n/\\n/g;
if ($event{days} != 1)
{
@event_end_timestamp_array = gmtime $event{end};
$csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
}
$html_output .=< $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
{
my %event = %{$events{$event_id}};
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
@event_end_timestamp_array = gmtime $event{end};
my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
my $csv_description = $event{details};
$csv_description =~ s/"/""/g;
$csv_description =~ s/\n/\\n/g;
$csv_description =~ s/"/""/g;
$csv_description =~ s/\n/\\n/g;
if ($event{days} != 1)
{
@event_end_timestamp_array = gmtime $event{end};
$csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
}
$html_output .=< $events{$b}{start}} @selected_cal_events)
{
my %event = %{$events{$event_id}};
if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
my $csv_end_date = $csv_start_date;
my $csv_description = $event{details};
$csv_description =~ s/"/""/g;
$csv_description =~ s/\n/\\n/g;
if ($event{days} != 1)
{
@event_end_timestamp_array = gmtime $event{end};
$csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
}
$html_output .= &event2vcal(\%event)."\n";
}
}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
{
#list events for that calendar
foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
{
my %event = %{$events{$event_id}};
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
my $csv_end_date = $csv_start_date;
my $csv_description = $event{details};
$csv_description =~ s/"/""/g;
$csv_description =~ s/\n/\\n/g;
if ($event{days} != 1)
{
@event_end_timestamp_array = gmtime $event{end};
$csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
}
$html_output .= &event2vcal(\%event)."\n";
}
}
}
#increment to the next month--the method used
#here is the most painless way of making
#this work the right way in all cases.
$current_month +=1;
if ($current_month == 12)
{
$current_month=0;
$current_year++;
}
}
$html_output .= $debug_info;
print $html_output;
}
sub ascii_text_cal
{
($start_month, $start_year, $end_month, $end_year) = @_;
#calculate where to start and end the list
#format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
#@cal_month_start_date_array = gmtime $cal_month_start_date;
#loop through all the events. Create an array of events which fall
#within the current calendar view dates.
foreach $event_id (keys %events)
{
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp))
{
if ($events{$event_id}{cal_id} eq $current_cal_id)
{push @selected_cal_events, $event_id;}
else
{push @list_events, $event_id;}
}
}
#take the results of the previous sort and arrange them into a
#funky data structure (broken down according to the calendars currently
#selected)
#create hash to hold that data structure
#each element of this hash will be an array.
$shared_cal_events={}; #empty hash
#fill up that hash
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
{
foreach $event_id (@list_events)
{
if ($events{$event_id}{cal_id} eq $background_cal_id)
{push @{$shared_cal_events{$background_cal_id}}, $event_id;}
}
}
$html_output =< $events{$b}{start}} @selected_cal_events)
{
%event = %{$events{$event_id}};
if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
@event_start_timestamp_array = gmtime $event{start};
my $event_time = "";
if ($event{days} == 1)
{ #single-day event
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
if ($event{all_day_event} ne "1")
{
$event_time = &formatted_time($event{start},"hh:mm ampm")." - ".&formatted_time($event{end},"hh:mm ampm");
# if both times are am or pm, remove the first one (it's redundant!)
$event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/;
$event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/;
$event_time = " ($event_time)";
}
}
else #multi-day event
{
$date_string = &nice_date_range_format($event{start}, $event{end}, "-");
}
my $event_details = $event{details};
$event_details =~ s/\n\s+/\n/g;
$event_details =~ s/\n{2,}/\n/g;
chomp $event_details;
#indent each line of the details
$event_details =~ s/\n/\n /g;
$html_output .=" $date_string$event_time: $event{title}\n";
if ($event_details ne "")
{
$html_output .= " $event_details\n\n";
}
}
}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}})
{
$html_output .=< $events{$b}{start}} @{$shared_cal_events{$background_cal_id}})
{
my %event = %{$events{$event_id}};
if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp))
{
@event_start_timestamp_array = gmtime $event{start};
my $event_time = "";
if ($event{days} == 1)
{ #single-day event
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
if ($event{all_day_event} ne "1")
{
$event_time = &formatted_time($event{start},"hh:mm ampm")." - ".&formatted_time($event{end},"hh:mm ampm");
# if both times are am or pm, remove the first one (it's redundant!)
$event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/;
$event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/;
$event_time = " ($event_time)";
}
}
else #multi-day event
{
$date_string = &nice_date_range_format($event{start}, $event{end}, "-");
}
my $event_details = $event{details};
$event_details =~ s/\n\s+/\n/g;
$event_details =~ s/\n{2,}/\n/g;
chomp $event_details;
#indent each line of the details
$event_details =~ s/\n/\n /g;
$html_output .=" $date_string$event_time: $event{title}\n";
if ($event_details ne "")
{
$html_output .= " $event_details\n\n";
}
$html_output .=<
#end timestamp: $recur_end_timestamp
#the start timestamp ($months[$timestamp_array[4]] $timestamp_array[3], $real_year)
#the temp start timestamp ($months[$temp_start_timestamp_array[4]] $temp_start_timestamp_array[3], $temp_start_timestamp_array[5])
#p1
my $weekday_in_month_count = 0;
#figure out what weekday of the month the start timestamp is
for (;$temp_start_timestamp < $start_timestamp;$temp_start_timestamp+=86400)
{
@temp_start_timestamp_array = gmtime($temp_start_timestamp);
if ($temp_start_timestamp_array[6] == $timestamp_array[6])
{
$weekday_in_month_count++;
}
}
#this must be done, or the week-of-month recurring dates will be hosed
#@temp_array = gmtime $start_timestamp;
#my $current_month = $temp_array[4];
my $last_week=0;
# The recurring event algorithm loops through each day in the timeframe
# and tests its validity against the recurrence parameters.
# These tests take the form of "assumed valid unless proven otherwise"
# Doing it this way lets the various recurrence type tests operate
# independently of each other, while looping only once through the timeframe
for ($recur_timestamp = $start_timestamp; $recur_timestamp <= $recur_end_timestamp; $recur_timestamp += 86400)
{
$last_week=0;
my @recur_timestamp_array = gmtime $recur_timestamp;
my $current_month = $recur_timestamp_array[4];
#look a week ahead, to see if the current weekday is the last one in the month
my $recur_timestamp_next_week = $recur_timestamp+604800;
my @recur_timestamp_next_week_array = gmtime $recur_timestamp_next_week;
if ($current_month != $recur_timestamp_next_week_array[4])
{$last_week = 1;}
$real_year = 1900 + $recur_timestamp_array[5];
$recur_timestamp_valid=1;
if ($q->param('recurrence_type') eq "same_day_of_month")
{
if ($recur_timestamp_array[3] != $timestamp_array[3])
{$recur_timestamp_valid=0;}
}
elsif ($q->param('recurrence_type') eq "same_day_of_week")
{
if ($recur_timestamp_array[6] != $timestamp_array[6])
{
$recur_timestamp_valid=0;
}
elsif ($q->param('weekday_of_month_type') eq "only_first_week")
{
if ($weekday_in_month_count != 0)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('weekday_of_month_type') eq "only_second_week")
{
if ($weekday_in_month_count != 1)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('weekday_of_month_type') eq "only_third_week")
{
if ($weekday_in_month_count != 2)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('weekday_of_month_type') eq "only_fourth_week")
{
if ($weekday_in_month_count != 3)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('weekday_of_month_type') eq "only_fifth_week")
{
if ($weekday_in_month_count != 4)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('weekday_of_month_type') eq "only_last_week")
{
if ($last_week != 1)
{$recur_timestamp_valid=0;}
else
{
$debug_info .= "timestamp: $recur_timestamp \n";
$debug_info .= "current month: $current_month \n";
$debug_info .= "lookahead timestamp: $recur_timestamp_next_week \n";
$debug_info .= "lookahead month: $recur_timestamp_next_week_array[4] \n";
$debug_info .= " \n";
}
}
}
elsif ($q->param('recurrence_type') eq "every_x_days")
{
#$debug_info .= $q->param('every_x_days');
#$debug_info .= "\n";
if (($recur_timestamp - $start_timestamp) % (86400 * $q->param('every_x_days')) !=0)
{$recur_timestamp_valid=0;}
}
elsif ($q->param('recurrence_type') eq "every_x_weeks")
{
#$debug_info .= ($q->param('every_x_weeks')."\n");
if (($recur_timestamp - $start_timestamp) % (86400 * 7 * $q->param('every_x_weeks')) !=0)
{$recur_timestamp_valid=0;}
}
if ($q->param('year_fit_type') eq "every_month")
{
}
elsif ($q->param('year_fit_type') eq "custom_months")
{
my $month_valid=0;
foreach $custom_month (@custom_months)
{
if ($custom_month == $recur_timestamp_array[4])
{$month_valid=1;}
}
if ($month_valid == 0)
{$recur_timestamp_valid=0;}
}
if ($recur_timestamp_valid == 1)
{
push @recurring_events_array, $recur_timestamp;
my $real_year = $recur_timestamp_array[5]+1900;
}
#count how many of the event's weekdays we have come across in
#each month. This is for validating events that occur on the
#second tuesday, fifth monday, etc.
if ($recur_timestamp_array[6] == $timestamp_array[6])
{
$weekday_in_month_count++;
}
#reset week_in_month count if this is the last week in the month
if ($last_week == 1 && $recur_timestamp_array[6] == $timestamp_array[6])
{$weekday_in_month_count=0;}
}
if (scalar @recurring_events_array == 0)
{
$debug_info .= "Error! No valid recurring event dates found!\n";
}
return \@recurring_events_array;
}
sub verify_date()
{
# $date is of the format similar to mm/dd/yy (or a permutation like dd/mm/yy)
my ($date) = @_;
my $results="";
if ($date !~ /^(\w{1,2}\/\w{1,2}\/\w{2,4}|\w{1,2}\/\w{2,4}\/\w{1,2}|\w{2,4}\/\w{1,2}\/\w{1,2})$/)
{
$lang{date_verify_err0} =~ s/###date###/$date/;
$lang{date_verify_err0} =~ s/###format###/$current_calendar{date_format}/;
$results .= $lang{date_verify_err0}."\n";
}
if ($q->param('recurrence_type') eq "every_x_days")
{
if ($q->param('every_x_days') == 0)
{$results .= $lang{date_verify_err7}."\n"};
}
elsif ($q->param('recurrence_type') eq "every_x_weeks")
{
if ($q->param('every_x_weeks') == 0)
{$results .= $lang{date_verify_err8}."\n"};
}
if ($date eq "")
{
$results .= $lang{date_verify_err1}."\n";
}
my ($mon, $day, $year) = &format2mdy($date, $current_calendar{date_format});
if ($mon < 1 || $mon > 12)
{
$lang{date_verify_err4} =~ s/###month###/$mon/;
$results .= $lang{date_verify_err4}."\n";
}
$mon --; # convert month to 0-11 format
if ($day < 1 || $day > 31)
{
$lang{date_verify_err5} =~ s/###day###/$day/;
$results .= $lang{date_verify_err5}."\n";
}
if ($year < 100) {$year+=2000;}
if ($year < 1902 || $year > 2037)
{
$lang{date_verify_err6} =~ s/###year###/$year/;
$results .= $lang{date_verify_err6}."\n";
}
return $results;
}
sub verify_time
{
my ($time) = @_;
my $results="";
if ($time !~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/)
{
$lang{time_verify_err0} =~ s/\{0\}/$time/;
$results .= $lang{time_verify_err0};
}
else
{
my $hours = $1;
my $minutes = $2;
my $ampm = $3;
if ($hours > 12 || $hours < 0)
{
$lang{time_verify_err1} =~ s/\{0\}/$hours/;
$results .= $lang{time_verify_err1};
}
if ($minutes > 60 || $minutes < 0)
{
$lang{time_verify_err2} =~ s/\{0\}/$minutes/;
$results .= $lang{time_verify_err2};
}
}
return $results;
}
sub time2seconds
{
my ($time) = @_;
$time =~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/;
my $hours = $1;
my $minutes = $2;
my $ampm = $3;
my $seconds = 3600*$hours + 60*$minutes;
if ($ampm eq $lang{pm} && $hours < 12)
{
$seconds += 3600*12;
}
if ($ampm eq $lang{am} && $hours == 12)
{
$seconds -= 3600*12;
}
return $seconds;
}
sub preview_date
{
my $html_output .=<$lang{date_preview_title}
$lang{date_preview_title}
p1
$recurring_event = $q->param('recurring_event');
$event_start_date = $q->param('evt_start_date');
$recur_end_date = $q->param('recur_end_date');
$event_days = $q->param('evt_days');
$event_cal_id = $q->param('evt_cal_id');
%current_calendar = %{$calendars{$event_cal_id}};
my $custom_months_string = $q->param('custom_months');
local @custom_months = split (/\s/, $custom_months_string);
#//
my $date_valid = &verify_date($event_start_date);
if ($event_days eq "")
{
$date_valid=$lang{date_verify_err2};
}
if ($days =~ m/\D/ || $event_days <= 0)
{
$date_valid=$lang{date_verify_err3};
}
if ($recurring_event)
{
my $temp .= &verify_date($recur_end_date);
if ($temp ne "")
{
$date_valid .= "\n$lang{date_verify_for_recurring_end_date}\n
p1
print $html_output;
}
sub remote_calendar_request()
{
my $html_output .=<param('cal_id');
$results .=<$plans_version
p1
#$debug_info .= "remote calendar request!";
# if the client requests a list of all calendars that are publically share-able.
if ($q->param('get_public_calendars') eq "1")
{
foreach $cal_id (keys %calendars)
{
if ($calendars{$cal_id}{allow_remote_calendar_requests})
{
my $temp=$calendars{$cal_id}{remote_calendar_requests_require_password};
$results .=<$cal_id$calendars{$cal_id}{title}$temp
p1
}
}
}
else # return xml data for the events.
{
my @current_cal_ids = ();
my @temp = split (",",$current_cal_ids_string);
my $cal_id_valid=1;
foreach $cal_id (@temp)
{
if ($cal_id !~ /\D/)
{
push @current_cal_ids, $cal_id;
}
else
{
$cal_id_valid=0;
$results .= "Invalid calendar ID: $cal_id";
last;
}
}
if ($cal_id_valid)
{
foreach $current_cal_id (@current_cal_ids)
{
$results .=<$current_cal_id$calendars{$current_cal_id}{title}$calendars{$current_cal_id}{gmtime_diff}
p1
}
foreach $current_cal_id (@current_cal_ids)
{
foreach $event (keys %events)
{
if ($events{$event}{cal_id} ne $current_cal_id)
{next;}
my $xml_data = &event2xml($events{$event});
$results .=<";
@awords=split(' ', $A);
@bwords=split(' ', $B);
$score=0;
foreach $aword (@awords)
{
if ((index $B,$aword) != -1)
{
# print "$temp";
# print "pruned to \"$A\" and \"$B\" ";
# print "wmatch matched $aword and $bword
";
$score++;
}
}
return $score;
}
sub rgb2hsv {
# r,g,b values are from 0 to 255
# h = [0..360], s = [0..100], v = [0..100]
# if s == 0, then h = -1 (undefined)
my ($r,$g,$b) = @_;
$r /= 255;
$g /= 255;
$b /= 255;
my ($h, $s, $v);
my ($min, $max, $delta);
$min = &min ( $r, $g, $b );
$max = &max ( $r, $g, $b );
# value is just the brightest rgb value
$v = $max;
# account for shades of gray:
$delta = $max - $min;
if ($delta == 0 ) {
$s = 0; # no hue, so it can't be saturated!
$h = -1; # hue is really undefined, but...
return ($h, $s, $v*100);
}
# saturation is intensity/blandness of color:
$s = $delta / $max; # max > 0 or delta would be 0
# hue depends on the relative strengths of the colors:
if( $r == $max ) {
$h = ( $g - $b ) / $delta; # between yellow & magenta
} elsif( $g == $max ) {
$h = 2 + (( $b - $r ) / $delta); # between cyan & yellow
} else {
$h = 4 + (( $r - $g ) / $delta); # between magenta & cyan
}
# it's also calculated as degrees on a color wheel
$h *= 60; # degrees
$h += 360 if ($h < 0);
# s and v are percentages
$s *= 100;
$v *= 100;
return (int( $h ), int($s), int($v));
}
sub hsv2rgb {
my ($hue, $sat, $val) = @_;
my @hsv_map =
(
'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn'
);
# HSV conversions from pages 401-403 "Procedural Elements for Computer
# Graphics", 1985, ISBN 0-07-053534-5.
my @result;
if ($sat <= 0) {
return ( 255 * $val, 255 * $val, 255 * $val );
}
else {
$val >= 0 or $val = 0;
$val <= 1 or $val = 1;
$sat <= 1 or $sat = 1;
$hue >= 360 and $hue %= 360;
$hue < 0 and $hue += 360;
$hue /= 60.0;
my $i = int($hue);
my $f = $hue - $i;
$val *= 255;
my $m = $val * (1.0 - $sat);
my $n = $val * (1.0 - $sat * $f);
my $k = $val * (1.0 - $sat * (1 - $f));
my $v = $val;
my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, );
return @fields{split //, $hsv_map[$i]};
}
}
sub make_consistent
{
my ($string) = @_;
my $input = $q->param($string);
if ($input ne "")
{$consistent_parameter_string .= "&$string=$input";}
}
sub remove_consistent
{
my ($string) = @_;
my $return_string = $consistent_parameter_string;
$return_string =~ s/&$string=.+?&/&/;
return $return_string;
}
sub diagnostic_mode()
{
$html_output .=<Diagnostic mode
Plans Diagnostic information
Script Name:$name Data Storage Mode: $data_storage_mode
p1
if ($email_mode && !$writable{email_reminders_datafile})
{
$html_output .=<Warning: The email reminders data file: $email_reminders_datafile is not writable. This will
cause some email functions to be disabled or not work correctly.
p1
}
if ($data_storage_mode == 0 && !$writable{calendars_file})
{
$html_output .=<Warning: The calendars data file: $calendars_file is not writable. The add/edit calendars tab won't appear
unless this file is writable.
p1
}
if ($data_storage_mode == 0 && !$writable{new_calendars_file})
{
$html_output .=<Warning: The new calendars data file: $new_calendars_file is not writable. The add/edit calendars tab won't appear
unless this file is writable.
p1
}
if ($data_storage_mode == 0 && !$writable{events_file})
{
$html_output .=<Warning: The events data file: $events_file is not writable. The add/edit events tab won't appear
unless this file is writable.
p1
}
$html_output .=<Plans version: $version Perl version: $perl_version script name: $name script url path: $script_url
p1
print $html_output;
} # end diagnostic subroutine
sub assemble_icon_menus()
{
# this function extracts a data structure for the icon menus from the xml definition
my ($data)= @_;
# first, get the menuitems
my @new_menuitems=();
my @menuitems = &xml_extract($data, "menuitem", 0);
if (scalar @menuitems == 0)
{
$debug_info .= "Warning. There's a menu with no menuitems. This may be caused by an older version of Perl ( < 5.6).\n";
$debug_info .= "$data";
}
else
{
foreach my $menuitem (@menuitems)
{
#$debug_info .= "menuitem: $menuitem->{data} ($menuitem->{position}) ";
my $icon_name = $menuitem->{attributes}{"value"};
my $icon_description = $menuitem->{data};
$icon_description = &encode($icon_description);
$new_menuitems[$menuitem->{position}] = [$icon_name,$icon_description];
#$new_menuitems[$menuitem->{position}] = "name,description";
}
}
# then get the submenus
my @submenus = &xml_extract($data, "menu", 0);
foreach $submenu (@submenus)
{
my $temp = $submenu->{data};
my $temp2 = $submenu->{attributes}{name};
my @submenuitems = assemble_icon_menus($temp);
#$debug_info .= "submenu: $temp2 ($submenu->{position}) ";
$new_menuitems[$submenu->{position}] = [$temp2, \@submenuitems];
}
return @new_menuitems;
} #******************** end assemble_icon_menus **********************
sub generate_flat_icon_menus
{
my ($icons_list, $selected_icon) = @_;
my $return_text="";
#$debug_info .= "selected icon: $selected_icon ";
my $indent = " ";
for ($l1=0;$l1<$index_number;$l1++)
{
$indent .= " ";
}
foreach $icon_ref (@{$icons_list})
{
my $identifier = @{$icon_ref}[1];
if ($identifier =~ /ARRAY/) # if it's a submenu
{
$icon_menu_index_number++;
my $submenu_name = @{$icon_ref}[0];
#$debug_info .= "submenu $submenu_name ";
$return_text .= <
p1
$return_text .= &generate_flat_icon_menus(@{$icon_ref}[1], $selected_icon);
$return_text .= <
p1
}
else # if it's a menu item
{
my $icon_filename = @{$icon_ref}[0];
my $icon_name = @{$icon_ref}[1];
$icon_name = &decode($icon_name);
#$debug_info .= "icon name: $icon_name ";
#$debug_info .= "icon filename: $icon_filename ";
#$debug_info .= " ";
if ($icon_filename eq $selected_icon)
{
$return_text .= <$icon_name
p1
}
else
{
$return_text .= <$icon_name
p1
}
}
}
return $return_text;
} #******************** end generate_flat_icon_menus **********************
sub export_calendar_link()
{
my $results = "";
$results .=<$lang{export} $lang{these_events_to}
p1
}
sub format2mdy()
{ # takes a format string (which can be "dd/mm/yy", "yy,mm,dd", etc.)
# and a date in that format, and returns the month, day, and year.
my ($date, $format) = @_;
my @temp_date = split ('/', $date);
my @temp_format = split ('/', $format);
my %temp_format_map;
for (my $l1=0;$l1<3;$l1++)
{
$temp_format_map{$temp_format[$l1]} = $temp_date[$l1];
}
my $mon = $temp_format_map{"mm"};
my $day = $temp_format_map{"dd"};
my $year = $temp_format_map{"yy"};
return ($mon, $day, $year);
}