installers (calendaring), RT#16584
[freeside.git] / rt / share / html / Search / Calendar.html
1 <%args>
2 $Month => (localtime)[4]
3 $Year => (localtime)[5] + 1900
4 $Query => undef
5 $Format => undef
6 $Order => undef
7 $OrderBy => undef
8 $RowsPerPage => undef
9 $NewQuery => 0
10 $WeekDay => undef
11 $WeekMonth => undef
12 $WeekYear => undef
13 $OrigMonth => undef
14 $OrigYear => undef
15 $Embed => undef
16 $DayDisplay => undef
17 @DayDisplayArgs => ()
18 </%args>
19
20 % my $title;
21 % if ( $WeekMonth ) {
22 %   if ( $start->month == $end->month ) {
23 %     $title = $rtdate->GetMonth( $start->month -1 ). ' '.
24 %              $start->day. '-'. $end->day. ', '. $start->year;
25 %   } elsif ( $start->year == $end->year ) {
26 %     $title =
27 %       $rtdate->GetMonth( $start->month -1 ). ' '. $start->day. ' - '.
28 %       $rtdate->GetMonth( $end->month  -1 ). ' '. $end->day.  ', '. $end->year;
29 %   } else {
30 %     $title =
31 %       $rtdate->GetMonth( $start->month -1 ).' '.$start->day.', '.$start->year.
32 %       ' - '.
33 %       $rtdate->GetMonth( $end->month  -1 ). ' '.$end->day.  ', '. $end->year;
34 %   }
35 % } else {
36 %   $title = $rtdate->GetMonth($Month) . " $Year" 
37 % }
38
39 % unless ( $Embed ) {
40
41 <& /Elements/Header, Title => $title &>
42 <& /Elements/Tabs &>
43
44 % }
45
46 <&| /Widgets/TitleBox,
47      title => loc('Calendar for '). $title,
48      title_class=> 'inverse',
49      color => "#993333" &>
50
51 % my($PMonth, $PYear, $NMonth, $NYear);
52 % unless ( $WeekDay ) {
53
54     <table width="100%">
55       <tr>
56         <td align="left">
57 % ($PMonth, $PYear) = ($Month - 1, $Year);
58 % if ($PMonth < 0) {
59 %    $PYear--;
60 %    $PMonth = 11;
61 % }
62           <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">«<%$rtdate->GetMonth($PMonth)%></a>
63         </td>
64         <th align="center">
65           <font size="+1"><% $rtdate->GetMonth($Month). " $Year" %></font>
66         </th>
67         <td align="right">
68 % ($NMonth, $NYear) = ($Month + 1, $Year);
69 % if ($NMonth > 11) {
70 %    $NYear++;
71 %    $NMonth = 0;
72 % }
73           <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%>»</a>
74         </td>
75       </tr>
76     </table>
77 % }
78
79 <table class="rtxcalendar">
80
81 <thead>
82 <tr>
83 <td class="labels" colspan=<% $WeekDay ? 2 : 1 %>></td>
84 % for ( @{$week{$weekstart}} ) {
85 <th width="14%" colspan=<% $WeekDay ? $slots : 1 %>><%$rtdate->GetWeekday($_)%></th>
86 % }
87 </tr>
88 </thead>
89
90 <tbody>
91 <tr>
92
93 % if ( $WeekDay ) {
94   <td class="controls" rowspan=<% $rowspan+1 %> valign="middle">
95     <& week_collapse, date=>$start, Month=>$OrigMonth, Year=>$OrigYear, QueryString=>$QueryString, Embed=>$Embed, &>
96   </td>
97   </td>
98 % } else {
99   <& td_week_expand, date=>$start, Month=>$Month, Year=>$Year, QueryString=>$QueryString, Embed=>$Embed, &>
100 % }
101
102 % if ( $WeekDay ) {
103
104     <td class="labels"></td>
105
106 %   my $date = $start;
107 %   while ($date <= $end) {
108 %
109 %     my $is_today     = (DateTime->compare($today,     $date) == 0);
110 %     my $is_yesterday = (DateTime->compare($yesterday, $date) == 0);
111 %     my $is_aweekago  = (DateTime->compare($aweekago,  $date) == 0);
112
113       <td colspan=<%$slots%>
114           class="weekly
115                  <%   $is_today     ? 'today'
116                     : $is_yesterday ? 'yesterday'
117                     : $is_aweekago  ? 'aweekago'
118                     : ''
119                  %>"
120       >
121         <div class="<%   $is_today ? 'todays'
122                        : ''
123                     %>calendardate"
124         ><% $rtdate->GetMonth($date->month-1). ' '. $date->day %></div>
125
126       </td>
127
128 %     $date = $set->next($date);
129 %     if ( $date->day_of_week == $startday_of_week ) {
130         </tr>
131 %       if ( $date <= $end ) { #a second week? not going to work for week view yet
132           <tr>
133               <td class="controls" rowspan=<% $rowspan + 1 %> valign="middle">
134                 <& week_collapse, date=>$date, Month=>$OrigMonth, Year=>$OrigYear, QueryString=>$QueryString, Embed=>$Embed, &>
135               </td>
136 %       }
137 %     }
138
139 %   } #while ($date <= $end)
140
141 %   my $sday = 0;
142 %   my @slots = ( [], [], [], [], [], [], [] );
143 %   foreach my $row ( @week_rows ) {
144
145       <tr>
146       <& td_time, $row &>
147
148 %     $date = $start;
149 %     $sday = 0;
150 %     while ($date <= $end) {
151 %
152 %       my $is_today     = (DateTime->compare($today,     $date) == 0);
153 %       my $is_yesterday = (DateTime->compare($yesterday, $date) == 0);
154 %       my $is_aweekago  = (DateTime->compare($aweekago,  $date) == 0);
155
156 %#        <td colspan=<%$slots%>
157 %#            class="<%   $is_today     ? 'today'
158 %#                      : $is_yesterday ? 'yesterday'
159 %#                      : $is_aweekago  ? 'aweekago'
160 %#                      : ''
161 %#                   %>"
162 %#        >
163
164 % #XXX display these in a time aware fashion
165 %#%       my $sp = 3;
166 %#%       for my $t ( @{ $Tickets{$date->strftime("%F")} } ) {
167 %#%         $sp--;
168 %#          <& /Elements/CalendarEvent, Object => $t, Date => $date, DateTypes => \%DateTypes &>
169 %#%       }
170 %#        <% ($sp>0) ? '<BR>'x$sp : '' |n %>
171
172 %       for my $t ( @{ $Tickets{$date->strftime("%F")} } ) {
173 %
174 %         #XXX off by 1h on daylight savings boundaries... two sundays a year
175 %         my $starts = ($t->StartsObj->Unix - $t->StartsObj->SetToMidnight(Timezone=>'user'))/60;
176 %
177 %         if ( $starts >= $row && $starts < ($row + $timestep) ) {
178 %           #then we're a new entry, find a slot for us
179 %           my $s = 0;
180 %           while ( ref($slots[$sday]->[$s]) ) { $s++ }
181 %           $slots[$sday]->[$s] = [ $t->Id, $t ];
182 %         }
183 %
184 %         #XXX also off by 1h on daylight savings boundaries
185 %         my $due = $t->DueObj->Unix - $t->DueObj->SetToMidnight;
186 %
187 %         if ( $due <= $row && $due > ($row + $timestep ) ) {
188 %           #then find our slot and remove us
189 %           @{ $slots[$sday] } =
190 %             map { (!ref($_) || $_->[0] != $t->Id) ? $_ : '' }
191 %               @{ $slots[$sday] };
192 %         }
193 %
194 %       }
195 %
196 %       pop @{ $slots[$sday] } while @{ $slots[$sday] } && !ref($slots[$sday]->[-1]);
197 %
198 %       #now display:
199 %
200 %       if ( scalar(@{$slots[$sday]}) > $slots ) {
201 %         #overflow situation, eek... could be handled better, how?
202
203           <td colspan=<%$slots%>
204               class="weekly
205                      <%   $is_today     ? 'today'
206                         : $is_yesterday ? 'yesterday'
207                         : $is_aweekago  ? 'aweekago'
208                         : ''
209                      %>"
210           >MULTIPLE
211           </td>
212
213 %       } else {
214 %
215 %         foreach my $slot ( @{ $slots[$sday] } ) {
216 %           my( $id, $ticket ) = @$slot;
217
218             <td class="weekly
219                        <%   $is_today     ? 'today'
220                           : $is_yesterday ? 'yesterday'
221                           : $is_aweekago  ? 'aweekago'
222                           : ''
223                        %>"
224             ><% $id %>
225             </td>
226
227 %         }
228 %
229 %         if ( scalar(@{$slots[$sday]}) < $slots ) {
230
231             <td colspan=<% $slots - scalar(@{$slots[$sday]}) %>
232                 class="weekly
233                        <%   $is_today     ? 'today'
234                           : $is_yesterday ? 'yesterday'
235                           : $is_aweekago  ? 'aweekago'
236                           : ''
237                        %>"
238             >
239             </td>
240 %         }
241 %
242 %       }
243
244 %       $date = $set->next($date);
245 %       if ( $date->day_of_week == $startday_of_week ) {
246           </tr>
247 %         if ( $date <= $end ) { #a second week? not going to work for week view yet
248             <tr>
249               <td class="controls" rowspan=<% $rowspan + 1 %> valign="middle">
250                   <& week_collapse, date=>$date, Month=>$OrigMonth, Year=>$OrigYear, QueryString=>$QueryString, Embed=>$Embed, &>
251                 </td>
252 %         }
253 %       }
254 %
255 %       $sday++;
256 %     } #while ($date <= $end)
257 %   } #foreach my $row ( @week_rows )
258 %
259 % } else {
260 %
261 %   my $date = $start;
262 %   while ($date <= $end) {
263 %
264 %     my $offmonth = !$WeekDay && $date->month != ($Month + 1);
265 %     my $is_today     = (DateTime->compare($today,     $date) == 0);
266 %     my $is_yesterday = (DateTime->compare($yesterday, $date) == 0);
267 %     my $is_aweekago  = (DateTime->compare($aweekago,  $date) == 0);
268
269       <td
270           class="<%   $offmonth     ? 'offmonth'
271                     : $is_today     ? 'today'
272                     : $is_yesterday ? 'yesterday'
273                     : $is_aweekago  ? 'aweekago'
274                     : ''
275                  %>"
276       >
277         <div class="<%   $is_today ? 'todays'
278                        : $offmonth ? 'offmonth'
279                        : ''
280                     %>calendardate"
281         ><% $date->day %></div>
282
283 %       if ( defined($DayDisplay) && $DayDisplay =~ /^(\w+)$/ ) {
284 %
285 %         my $el = "/Elements/CalendarDay$1";
286           <& $el, Tickets   => $Tickets{$date->strftime("%F")},
287                   Date      => $date,
288                   DateTypes => \%DateTypes,
289                   @DayDisplayArgs,
290           &>
291 %
292 %       } else {
293 %
294 %         my $sp = 3;
295 %         for my $t ( @{ $Tickets{$date->strftime("%F")} } ) {
296 %           $sp--;
297             <& /Elements/CalendarEvent, Object => $t, Date => $date, DateTypes => \%DateTypes &>
298 %         }
299           <% ($sp>0) ? '<BR>'x$sp : '' |n %>
300 %
301 %       }
302
303       </td>
304
305 %     $date = $set->next($date);
306 %     if ( $date->day_of_week == $startday_of_week ) {
307         </tr>
308 %       if ( $date <= $end ) {
309           <tr>
310             <& td_week_expand, date=>$date, Month=>$Month, Year=>$Year, QueryString=>$QueryString, Embed=>$Embed, &>
311 %       }
312 %     }
313
314 %   } #while ($date <= $end)
315
316 % }
317 </tbody>
318 </table>
319
320 % unless ( $WeekDay ) {
321
322     <table width="100%">
323       <tr>
324         <td align="left">
325           <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">«<%$rtdate->GetMonth($PMonth)%></a>
326         </td>
327
328         <td valign="top" align="center">
329           <form action="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?<%$QueryString%>" method="post">
330
331             <select name="Month">
332 %             for (0..11) {
333                 <option value="<%$_%>" <% $_ == $Month ? 'selected' : ''%> ><%$rtdate->GetMonth($_)%></option>
334 %             }
335             </select>
336
337 %           my $year = (localtime)[5] + 1900;
338             <select name="Year">
339 %             for ( ($year-5) .. ($year+5)) {
340                 <option value="<%$_%>" <% $_ == $Year ? 'selected' : ''%>><%$_%></option>
341 %             }
342             </select>
343
344 %# <& /Elements/Submit&>
345             <input type="submit" value="<% loc('Submit') %>" class="button" />
346
347           </form>
348         </td>
349
350         <td align="right">
351           <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%>»</a>
352         </td>
353       </tr>
354   </table>
355
356 % }
357
358 % unless ( $Embed ) {
359
360 <table width="100%">
361 <tr>
362
363 <td valign="top" rowspan=9>
364   <BR>
365   <a href="<%$RT::WebPath%>/Prefs/Calendar.html">Calendar Preferences and Help</a>
366 </td>
367
368 % foreach my $legend (keys %legend) {
369     <tr>
370       <td align="right">
371         <img src="<%$RT::WebImagesURL%>/<%$legend%>.png" />
372       </td>
373       <td align="left">
374 %       my $more = 0;
375 %       foreach ( @{$legend{$legend}} ) {
376           <% $more++ ? ', ' : '' %>
377           <&|/l&><% $_ %></&>
378 %       }
379       </td>
380     </tr>
381 % }
382
383 </table>
384
385 % }
386
387 </&>
388
389 <%ONCE>
390
391 my %legend = (
392   'created'     => ['Created'],
393   'due'         => ['Due'],
394   'resolved'    => ['Resolved'],
395   'updated'     => ['Last Updated'],
396   'created_due' => ['Created','Due'],
397   'reminder'    => ['Reminders'],
398   'started'     => ['Started'],
399   'starts_due'  => ['Starts','Due'],
400 );
401
402 my $stime    = RT->Config->Get('CalendarWeeklyStartMin');
403 $stime = 480 unless $stime =~ /^\d+$/; #8am
404 my $etime    = RT->Config->Get('CalendarWeeklyEndMin');
405 $etime = 1080 unless $etime =~ /^\d+$/; #6pm
406
407 my $timestep =  RT->Config->Get('CalendarWeeklySizeMin') || 30; #1/2h
408 my $rowspan = ($etime-$stime) / $timestep;
409
410 my $slots = RT->Config->Get('CalendarWeeklySlots') || 5;
411
412 my $wt = $stime;
413 my @week_rows = ();
414 while ( $wt < $etime ) { push @week_rows, $wt; $wt+=$timestep }
415
416 </%ONCE>
417 <%INIT>
418 use RTx::Calendar qw(FirstDay LastDay LastDayOfWeek);
419
420 $Embed =~ /^[\w\.]+$/ or die 'xss';
421
422 my $title = loc("Calendar");
423
424 my @DateTypes = qw/Created Starts Started Due LastUpdated Resolved/;
425
426 my $rtdate = RT::Date->new($session{'CurrentUser'});
427
428 my $time_zone = $session{'CurrentUser'}->UserObj->Timezone
429                   || RT->Config->Get('Timezone');
430
431 my $weekstart = 'Sunday'; #RT::SiteConfig?  user pref?
432 my %week = (
433   'Saturday' => [6,0..5],
434   'Sunday'   => [0..6],
435   'Monday'   => [1..6,0],
436 );
437 my $startday_of_week = ${$week{$weekstart}}[0]  || 7;
438 my $endday_of_week   = ${$week{$weekstart}}[-1] || 7;
439
440 my $today = DateTime->today( time_zone=>$time_zone );
441 my $yesterday = $today->clone->subtract( days=>1 );
442 my $aweekago  = $today->clone->subtract( days=>7 );
443
444 my( $start, $end );
445 if ( $WeekDay ) {
446   $start = DateTime->new( year      => $WeekYear,
447                           month     => $WeekMonth+1,
448                           day       => $WeekDay,
449                           time_zone => $time_zone,
450                         );
451   $end  = LastDayOfWeek( $WeekYear, $WeekMonth+1, $WeekDay, $endday_of_week );
452 } else {
453   $start = FirstDay($Year, $Month + 1, $startday_of_week );
454   $end   = LastDay ($Year, $Month + 1, $endday_of_week );
455 }
456
457 # use this to loop over days until $end
458 my $set = DateTime::Set->from_recurrence(
459     next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
460 );
461
462 my $QueryString;
463 if ($Query) {
464   $QueryString =
465       $m->comp(
466         '/Elements/QueryString',
467         Query   => $Query,
468         Format  => $Format,
469         Order   => $Order,
470         OrderBy => $OrderBy,
471         Rows    => $RowsPerPage,
472         @DayDisplayArgs,
473       );
474 } else {
475   $QueryString =
476       $m->comp(
477         '/Elements/QueryString',
478         NewQuery => 1,
479         @DayDisplayArgs,
480       );
481 }
482
483 # Default Query and Format
484 my $TempFormat = "__Starts__ __Due__";
485 my $TempQuery = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
486  AND ( Owner = '" . $session{CurrentUser}->Id ."' OR Owner = 'Nobody'  )
487  AND ( Type = 'reminder' OR 'Type' = 'ticket' )";
488
489 if ( my $Search = RTx::Calendar::SearchDefaultCalendar($session{CurrentUser}) ) {
490   $TempFormat = $Search->SubValue('Format');
491   $TempQuery = $Search->SubValue('Query');
492 }
493
494 # we overide them if needed
495 $TempQuery  = $Query  if $Query;
496 $TempFormat = $Format if $Format;
497
498 # we search all date types in Format string
499 my @Dates = grep { $TempFormat =~ m/__${_}(Relative)?__/ } @DateTypes;
500
501 # used to display or not a date in Element/CalendarEvent
502 my %DateTypes = map { $_ => 1 } @Dates;
503
504 $TempQuery .= RTx::Calendar::DatesClauses(\@Dates, $start->strftime("%F"), $end->strftime("%F"));
505
506 # print STDERR ("-" x 30), "\n", $TempQuery, "\n";
507
508 my %Tickets = RTx::Calendar::FindTickets($session{'CurrentUser'}, $TempQuery, \@Dates, $start->strftime("%F"), $end->strftime("%F"));
509
510 </%INIT>
511 <%def td_week_expand>
512 <%args>
513   $date  => undef
514   $Month => undef
515   $Year  => undef
516   $QueryString => undef
517   $Embed => undef
518 </%args>
519   <td class="controls">
520     <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?WeekDay=<% $date->day %>&WeekMonth=<% $date->month -1 %>&WeekYear=<% $date->year %>&OrigMonth=<% $Month %>&OrigYear=<% $Year %>&<%$QueryString%>"><img src="<%$RT::WebPath%>/NoAuth/images/week-expand.gif"></a>
521   </td>
522 </%def>
523
524 <%def week_collapse>
525 <%args>
526   $date  => undef
527   $Month => undef
528   $Year  => undef
529   $QueryString => undef
530   $Embed => undef
531 </%args>
532     <a href="<%$RT::WebPath%>/Search/<%$Embed||'Calendar.html'%>?Month=<% $Month %>&Year=<% $Year %>&<%$QueryString%>"><img src="<%$RT::WebPath%>/NoAuth/images/week-collapse.gif" STYLE="height:384px;width:11px"></a>
533 </%def>
534
535 <%def td_time>
536 % my( $min ) = shift;
537     <td class="labels"><% pretty_time($min) |n %></td>
538 <%init>
539 sub pretty_time {
540   my $t = shift;
541
542   return 'Midnight' if $t == 0 || $t == 1440;
543   return 'Noon'     if $t == 720;
544
545   my $h = int( $t / 60 );
546   my $m = $t % 60;
547
548   my $ap = 'AM';
549   if    ( $h == 0 || $h == 24 ) { $h = 12; }
550   elsif ( $h == 12 )           { $ap = 'PM'; }
551   elsif ( $h > 12 )            { $ap = 'PM'; $h -= 12; }
552
553   sprintf('%02d:%02d&nbsp;'.$ap, $h, $m);
554
555 }
556 </%init>
557 </%def>