line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTML::Make::Calendar; |
2
|
1
|
|
|
1
|
|
762
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
3
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
80
|
|
4
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
61
|
|
5
|
1
|
|
|
1
|
|
6
|
use utf8; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
6
|
|
|
|
|
|
|
require Exporter; |
7
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
8
|
|
|
|
|
|
|
our @EXPORT_OK = qw/calendar/; |
9
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
10
|
|
|
|
|
|
|
all => \@EXPORT_OK, |
11
|
|
|
|
|
|
|
); |
12
|
|
|
|
|
|
|
our $VERSION = '0.00_04'; |
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
664
|
use Date::Calc ':all'; |
|
1
|
|
|
|
|
6542
|
|
|
1
|
|
|
|
|
388
|
|
15
|
1
|
|
|
1
|
|
601
|
use HTML::Make; |
|
1
|
|
|
|
|
15596
|
|
|
1
|
|
|
|
|
39
|
|
16
|
1
|
|
|
1
|
|
601
|
use Table::Readable 'read_table'; |
|
1
|
|
|
|
|
1407
|
|
|
1
|
|
|
|
|
1184
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Default HTML elements and classes. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my @dowclass = (undef, "mon", "tue", "wed", "thu", "fri", "sat", "sun"); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Read the configuration file. |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my $html_file = __FILE__; |
25
|
|
|
|
|
|
|
$html_file =~ s!\.pm!/html.txt!; |
26
|
|
|
|
|
|
|
my @html = read_table ($html_file); |
27
|
|
|
|
|
|
|
my %html; |
28
|
|
|
|
|
|
|
for (@html) { |
29
|
|
|
|
|
|
|
$html{$_->{item}} = $_ |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Add an HTML element defined by $thing to $parent. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub add_el |
35
|
|
|
|
|
|
|
{ |
36
|
0
|
|
|
0
|
0
|
|
my ($parent, $thing) = @_; |
37
|
0
|
|
|
|
|
|
my $class = $thing->{class}; |
38
|
0
|
|
|
|
|
|
my $type = $thing->{element}; |
39
|
0
|
|
|
|
|
|
my $element; |
40
|
0
|
0
|
|
|
|
|
if ($class) { |
41
|
|
|
|
|
|
|
# HTML::Make should have a class pusher since it is so common |
42
|
|
|
|
|
|
|
# http://mikan/bugs/bug/2108 |
43
|
0
|
|
|
|
|
|
$element = $parent->push ($type, attr => {class => $class}); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
else { |
46
|
|
|
|
|
|
|
# Allow non-class elements if the user doesn't want a class. |
47
|
0
|
|
|
|
|
|
$element = $parent->push ($type); |
48
|
|
|
|
|
|
|
} |
49
|
0
|
|
|
|
|
|
return $element; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub option |
53
|
|
|
|
|
|
|
{ |
54
|
0
|
|
|
0
|
0
|
|
my ($ref, $options, $what) = @_; |
55
|
0
|
0
|
|
|
|
|
if ($options->{$what}) { |
56
|
0
|
|
|
|
|
|
$$ref = $options->{$what}; |
57
|
0
|
|
|
|
|
|
delete $options->{$what}; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub calendar |
62
|
|
|
|
|
|
|
{ |
63
|
0
|
|
|
0
|
1
|
|
my (%options) = @_; |
64
|
0
|
|
|
|
|
|
option (\my $verbose, \%options, 'verbose'); |
65
|
0
|
|
|
|
|
|
my ($year, $month, undef) = Today (); |
66
|
0
|
|
|
|
|
|
option (\$year, \%options, 'year'); |
67
|
0
|
|
|
|
|
|
option (\$month, \%options, 'month'); |
68
|
0
|
|
|
|
|
|
option (\my $dayc, \%options, 'dayc'); |
69
|
0
|
|
|
|
|
|
option (\my $cdata, \%options, 'cdata'); |
70
|
0
|
|
|
|
|
|
my $html_week = $html{week}{element}; |
71
|
0
|
|
|
|
|
|
option (\$html_week, \%options, 'html_week'); |
72
|
0
|
|
|
|
|
|
my $first = 1; |
73
|
0
|
|
|
|
|
|
option (\$first, \%options, 'first'); |
74
|
0
|
0
|
|
|
|
|
if ($first != 1) { |
75
|
0
|
0
|
0
|
|
|
|
if (int ($first) != $first || $first < 1 || $first > 7) { |
|
|
|
0
|
|
|
|
|
76
|
0
|
|
|
|
|
|
carp "Use a number between 1 (Monday) and 7 (Sunday) for first"; |
77
|
0
|
|
|
|
|
|
$first = 1; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
# To do: Allow the user to use their own HTML tags. |
81
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
for my $k (sort keys %options) { |
83
|
0
|
0
|
|
|
|
|
if ($options{$k}) { |
84
|
0
|
|
|
|
|
|
carp "Unknown option '$k'"; |
85
|
0
|
|
|
|
|
|
delete $options{$k}; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
# Map from columns of the calendar to days of the week, e.g. 1 -> |
89
|
|
|
|
|
|
|
# 7 if Sunday is the first day of the week. |
90
|
0
|
|
|
|
|
|
my %col2dow; |
91
|
0
|
|
|
|
|
|
for (1..7) { |
92
|
0
|
|
|
|
|
|
my $col2dow = $_ + $first - 1; |
93
|
0
|
0
|
|
|
|
|
if ($col2dow > 7) { |
94
|
0
|
|
|
|
|
|
$col2dow -= 7; |
95
|
|
|
|
|
|
|
} |
96
|
0
|
|
|
|
|
|
$col2dow{$_} = $col2dow; |
97
|
|
|
|
|
|
|
} |
98
|
0
|
|
|
|
|
|
my %dow2col = reverse %col2dow; |
99
|
0
|
|
|
|
|
|
my $dim = Days_in_Month ($year, $month); |
100
|
0
|
0
|
|
|
|
|
if ($verbose) { |
101
|
|
|
|
|
|
|
# To do: Add a messaging routine with caller line numbers |
102
|
|
|
|
|
|
|
# rather than just use print. |
103
|
0
|
|
|
|
|
|
print "There are $dim days in month $month of $year.\n"; |
104
|
|
|
|
|
|
|
} |
105
|
0
|
|
|
|
|
|
my @col; |
106
|
|
|
|
|
|
|
# The number of weeks |
107
|
0
|
|
|
|
|
|
my $weeks = 1; |
108
|
0
|
|
|
|
|
|
my $prev = 0; |
109
|
0
|
|
|
|
|
|
for my $day (1..$dim) { |
110
|
0
|
|
|
|
|
|
my $dow = Day_of_Week ($year, $month, $day); |
111
|
0
|
|
|
|
|
|
my $col = $dow2col{$dow}; |
112
|
0
|
|
|
|
|
|
$col[$day] = $col; |
113
|
0
|
0
|
|
|
|
|
if ($col < $prev) { |
114
|
0
|
|
|
|
|
|
$weeks++; |
115
|
|
|
|
|
|
|
} |
116
|
0
|
|
|
|
|
|
$prev = $col; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
# The number of empty cells we need at the start of the month. |
119
|
0
|
|
|
|
|
|
my $fill_start = $col[1] - 1; |
120
|
0
|
|
|
|
|
|
my $fill_end = 7 - $col[-1]; |
121
|
0
|
0
|
|
|
|
|
if ($verbose) { |
122
|
0
|
|
|
|
|
|
print "Start $fill_start, end $fill_end, weeks $weeks\n"; |
123
|
|
|
|
|
|
|
} |
124
|
0
|
|
|
|
|
|
my @cells; |
125
|
|
|
|
|
|
|
# To do: Allow the user to colour or otherwise alter empty cells, |
126
|
|
|
|
|
|
|
# for example with a callback or with a user-defined class. |
127
|
0
|
|
|
|
|
|
for (1..$fill_start) { |
128
|
0
|
|
|
|
|
|
push @cells, {}; |
129
|
|
|
|
|
|
|
} |
130
|
0
|
|
|
|
|
|
for (1..$dim) { |
131
|
0
|
|
|
|
|
|
my $col = $col[$_]; |
132
|
0
|
|
|
|
|
|
push @cells, {dom => $_, col => $col, dow => $col2dow{$col}}; |
133
|
|
|
|
|
|
|
} |
134
|
0
|
|
|
|
|
|
for (1..$fill_end) { |
135
|
0
|
|
|
|
|
|
push @cells, {}; |
136
|
|
|
|
|
|
|
} |
137
|
0
|
|
|
|
|
|
my $calendar = HTML::Make->new ($html{calendar}{element}); |
138
|
|
|
|
|
|
|
# As far as I know, is the correct HTML, although
139
|
|
|
|
|
|
|
# nobody really does this. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# To do: inspect the type of $html{calendar} and don't add the |
142
|
|
|
|
|
|
|
# | unless it is a element.
143
|
0
|
|
|
|
|
|
my $tbody = $calendar->push ('tbody'); |
144
|
|
|
|
|
|
|
# To do: These should be overridden if the caller doesn't want to |
145
|
|
|
|
|
|
|
# use table, tr, td to construct the calendar. |
146
|
0
|
|
|
|
|
|
my $titler = $tbody->push ('tr'); |
147
|
0
|
|
|
|
|
|
my $titleh = $titler->push ('th', attr => {colspan => 7}); |
148
|
|
|
|
|
|
|
# To do: Allow the caller to override this. |
149
|
0
|
|
|
|
|
|
my $my = Month_to_Text ($month) . " $year"; |
150
|
0
|
|
|
|
|
|
$titleh->add_text ($my); |
151
|
|
|
|
|
|
|
# To do: Allow the user to override this. |
152
|
0
|
|
|
|
|
|
my $wdr = $tbody->push ('tr'); |
153
|
0
|
|
|
|
|
|
for my $col (1..7) { |
154
|
|
|
|
|
|
|
# To do: Allow the user to use their own weekdays (possibly |
155
|
|
|
|
|
|
|
# allow them to use the language specifier of Date::Calc). |
156
|
0
|
|
|
|
|
|
my $dow = $col2dow{$col}; |
157
|
0
|
|
|
|
|
|
my $wdt = substr (Day_of_Week_to_Text ($dow), 0, 2); |
158
|
0
|
|
|
|
|
|
my $dow_el = add_el ($wdr, $html{dow}); |
159
|
0
|
|
|
|
|
|
$dow_el->add_text ($wdt); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
# wom = week of month |
162
|
0
|
|
|
|
|
|
for my $wom (1..$weeks) { |
163
|
0
|
|
|
|
|
|
my $week = add_el ($tbody, $html{week}); |
164
|
0
|
|
|
|
|
|
for my $col (1..7) { |
165
|
|
|
|
|
|
|
# dow = day of week |
166
|
0
|
|
|
|
|
|
my $dow = $col2dow{$col}; |
167
|
0
|
|
|
|
|
|
my $day = add_el ($week, $html{day}); |
168
|
0
|
|
|
|
|
|
my $cell = shift @cells; |
169
|
|
|
|
|
|
|
# dom = day of month |
170
|
0
|
|
|
|
|
|
my $dom = $cell->{dom}; |
171
|
0
|
0
|
|
|
|
|
if (defined $dom) { |
172
|
0
|
|
|
|
|
|
$day->add_class ('cal-' . $dowclass[$dow]); |
173
|
0
|
0
|
|
|
|
|
if ($dayc) { |
174
|
0
|
|
|
|
|
|
&{$dayc} ($cdata, |
|
0
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
{ |
176
|
|
|
|
|
|
|
year => $year, |
177
|
|
|
|
|
|
|
month => $month, |
178
|
|
|
|
|
|
|
dom => $dom, |
179
|
|
|
|
|
|
|
dow => $dow, |
180
|
|
|
|
|
|
|
wom => $wom, |
181
|
|
|
|
|
|
|
}, |
182
|
|
|
|
|
|
|
$day); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
else { |
185
|
0
|
|
|
|
|
|
$day->push ('span', text => $dom, |
186
|
|
|
|
|
|
|
attr => {class => 'cal-dom'}); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
else { |
190
|
0
|
|
|
|
|
|
$day->add_class ('cal-noday'); |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
# To do: allow a callback on the packing cells |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
} |
195
|
0
|
|
|
|
|
|
return $calendar; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
1; |
|