calendar.pl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. # Copyright (C) 2004, 2005, 2006 Alex Schroeder <alex@emacswiki.org>
  2. # Copyright (C) 2006 Ingo Belka
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the
  16. # Free Software Foundation, Inc.
  17. # 59 Temple Place, Suite 330
  18. # Boston, MA 02111-1307 USA
  19. use strict;
  20. use v5.10;
  21. AddModuleDescription('calendar.pl', 'Calendar Extension');
  22. our ($q, %Page, %Action, $Now, $OpenPageName, $CollectingJournal, $FreeLinkPattern, @MyRules);
  23. our ($CalendarOnEveryPage, $CalAsTable, $CalStartMonday);
  24. $CalendarOnEveryPage = 0; # 1=on every page is a month-div situated in the header, use css to control
  25. $CalAsTable = 0; # 0=every month-div is "free", 1=every month-div is caught in a table, use css to control
  26. $CalStartMonday = 0; # 0=week starts with Su, 1=week starts with Mo
  27. *OldCalendarGetHeader = \&GetHeader;
  28. *GetHeader = \&NewCalendarGetHeader;
  29. sub NewCalendarGetHeader {
  30. my $header = OldCalendarGetHeader(@_);
  31. return $header unless $CalendarOnEveryPage;
  32. my $action = GetParam('action', 'browse');
  33. return $header if grep(/^$action$/, ('calendar', 'edit'));
  34. my $cal = Cal();
  35. $header =~ s/<div class="header">/$cal<div class="header">/;
  36. return $header;
  37. }
  38. sub Cal {
  39. my ($year, $mon, $unlink_year, $id) = @_; # example: 2004, 12
  40. $id = FreeToNormal($id);
  41. my ($sec_now, $min_now, $hour_now, $mday_now, $mon_now, $year_now) = localtime($Now);
  42. $mon_now += 1;
  43. $mon = $mon_now unless $mon;
  44. $year_now += 1900;
  45. $year = $year_now unless $year;
  46. if ($year < 1) {
  47. return $q->p(T('Illegal year value: Use 0001-9999'));
  48. }
  49. my @pages = AllPagesList();
  50. my $cal = draw_month($mon, $year);
  51. $cal =~ s{ ( ?\d{1,2})\b}{{
  52. my $day = $1;
  53. my $date = sprintf("%d-%02d-%02d", $year, $mon, $day);
  54. my $re = "^$date";
  55. $re .= ".*$id" if $id;
  56. my $page = $date;
  57. $page .= "_$id" if $id;
  58. my $class = '';
  59. $class .= ' today' if $day == $mday_now and $mon == $mon_now and $year == $year_now;
  60. my @matches = grep(/$re/, @pages);
  61. my $link = ' ';
  62. if (@matches == 0) { # not using GetEditLink because of $class
  63. $link .= ScriptLink('action=edit;id=' . UrlEncode($page), $day, 'edit' . $class);
  64. } elsif (@matches == 1) { # not using GetPageLink because of $class
  65. $link .= ScriptLink($matches[0], $day, 'local exact' . $class);
  66. } else {
  67. $link .= ScriptLink('action=collect;match=' . UrlEncode($re), $day, 'local collection' . $class);
  68. }
  69. $link;
  70. }}eg;
  71. $cal =~ s{(\S+) (\d\d\d\d)}{{
  72. my ($month_text, $year_text) = ($1, $2);
  73. my $date = sprintf("%d-%02d", $year, $mon);
  74. if ($unlink_year) {
  75. $q->span({-class=>'title'}, ScriptLink('action=collect;match=%5e' . $date,
  76. "$month_text $year_text", 'local collection month'));
  77. } else {
  78. $q->span({-class=>'title'}, ScriptLink('action=collect;match=%5e' . $date,
  79. $month_text, 'local collection month') . ' '
  80. . ScriptLink('action=calendar;year=' . $year,
  81. $year_text, 'local collection year'));
  82. }
  83. }}e;
  84. return "<div class=\"cal month\"><pre>$cal</pre></div>";
  85. }
  86. $Action{collect} = \&DoCollect;
  87. # inspired by journal
  88. sub DoCollect {
  89. my $id = shift;
  90. my $match = GetParam('match', '');
  91. my $search = GetParam('search', '');
  92. ReportError(T('The match parameter is missing.')) unless $match or $search;
  93. print GetHeader('', Ts('Page Collection for %s', $match||$search), '');
  94. my @pages = (grep(/$match/, $search
  95. ? SearchTitleAndBody($search)
  96. : AllPagesList()));
  97. if (!$CollectingJournal) {
  98. $CollectingJournal = 1;
  99. # Now save information required for saving the cache of the current page.
  100. local (%Page, $OpenPageName);
  101. print $q->start_div({-class=>'content journal collection'});
  102. PrintAllPages(1, 1, undef, undef, @pages);
  103. print $q->end_div();
  104. }
  105. $CollectingJournal = 0;
  106. PrintFooter();
  107. }
  108. push(@MyRules, \&CalendarRule);
  109. sub CalendarRule {
  110. if (/\G(calendar:(\d\d\d\d))/cg) {
  111. my $oldpos = pos;
  112. Clean(CloseHtmlEnvironments());
  113. Dirty($1);
  114. PrintYearCalendar($2);
  115. pos = $oldpos;
  116. return AddHtmlEnvironment('p');
  117. } elsif (/\G(month:(\d\d\d\d)-(\d\d))/cg) {
  118. my $oldpos = pos;
  119. Clean(CloseHtmlEnvironments());
  120. Dirty($1);
  121. print Cal($2, $3);
  122. pos = $oldpos;
  123. return AddHtmlEnvironment('p');
  124. } elsif (/\G(month:([+-]\d\d?))/cg
  125. or /\G(\[\[month:([+-]\d\d?) $FreeLinkPattern\]\])/cg) {
  126. my $oldpos = pos;
  127. Clean(CloseHtmlEnvironments());
  128. Dirty($1);
  129. my $delta = $2;
  130. my $id = $3;
  131. my ($sec, $min, $hour, $mday, $mon, $year) = localtime($Now);
  132. $year += 1900;
  133. $mon += 1 + $delta;
  134. while ($mon < 1) { $year -= 1; $mon += 12; };
  135. while ($mon > 12) { $year += 1; $mon -= 12; };
  136. print Cal($year, $mon, undef, $id);
  137. pos = $oldpos;
  138. return AddHtmlEnvironment('p');
  139. }
  140. return;
  141. }
  142. sub PrintYearCalendar {
  143. my $year = shift;
  144. print $q->p({-class=>'nav'},
  145. ScriptLink('action=calendar;year=' . ($year-1), T('Previous')),
  146. '|',
  147. ScriptLink('action=calendar;year=' . ($year+1), T('Next')));
  148. if ($CalAsTable) {
  149. print '<table><tr>';
  150. for my $mon (1..12) {
  151. print '<td>'.Cal($year, $mon, 1).'</td>';
  152. if ($mon == 3 or $mon == 6 or $mon == 9) {
  153. print '</tr><tr>';
  154. }
  155. }
  156. print '</tr></table>';
  157. } else {
  158. for my $mon (1..12) {
  159. print Cal($year, $mon, 1);
  160. }
  161. }
  162. }
  163. $Action{calendar} = \&DoYearCalendar;
  164. sub DoYearCalendar {
  165. my ($sec, $min, $hour, $mday, $mon, $year) = localtime($Now);
  166. $year += 1900;
  167. $year = GetParam('year', $year);
  168. print GetHeader('', Ts('Calendar %s', $year), '');
  169. print $q->start_div({-class=>'content cal year'});
  170. PrintYearCalendar($year);
  171. print $q->end_div();
  172. PrintFooter();
  173. }
  174. sub draw_month {
  175. my $month = shift;
  176. my $year = shift;
  177. my @weekday = (T('Su'), T('Mo'), T('Tu'), T('We'),
  178. T('Th'), T('Fr'), T('Sa'));
  179. my ($day, $col, $monthdays, $monthplus, $mod);
  180. my $weekday = zeller(1,$month,$year);
  181. # select the starting day for the week
  182. if ($CalStartMonday){
  183. push @weekday, shift @weekday;
  184. if ($weekday) {
  185. $weekday = $weekday -1;
  186. } else {
  187. $weekday = 6;
  188. }
  189. }
  190. my $start = 1 - $weekday;
  191. my $space_count = int((21 - length(month_name($month).' '.sprintf("%04u",$year)))/2 + 0.5);
  192. # the Cal()-sub needs a 4 digit year working right
  193. my $output = (' ' x $space_count).month_name($month).' '.sprintf("%04u",$year)."\n";
  194. $col = 0;
  195. $monthdays = &month_days($month,&leap_year($year));
  196. if ((($monthdays-$start) < 42) and (($monthdays-$start) > 35)) {
  197. $monthplus=41 - ($monthdays-$start);
  198. } elsif ((($monthdays-$start)<35) and (($monthdays-$start)>28)) {
  199. $monthplus=34 - ($monthdays-$start);
  200. } else {
  201. $monthplus=0;
  202. }
  203. $output .= join('', map {" ".$_} @weekday);
  204. $output .= "\n";
  205. for ($day=$start;$day<=$monthdays+$monthplus;$day++) {
  206. $col++;
  207. if (($day < 1) or ($day>$monthdays)) {
  208. $output .= ' ';
  209. } else {
  210. $output .= sprintf("%3d", $day);
  211. }
  212. $mod=($col/7)-int($col/7);
  213. if ($mod == 0) {
  214. $output .= "\n";
  215. }
  216. if ($year==1582 and $month==10 and $day==4) {
  217. $day=14;
  218. }
  219. }
  220. $output .= "\n" x (8 - ($output =~ tr/\n//)); # every month has to have 8 lines as output
  221. return $output;
  222. }
  223. # formula of Zeller (Julius Christian Johannes Zeller * 1822, + 1899) for countig the day of week
  224. # only works for all years greater then 0 and can handle 1582 the year Pope Gregor has changed the
  225. # calculation of times from the Julian calendar to the Gregorian calendar
  226. sub zeller {
  227. my $t = shift;
  228. my $m = shift;
  229. my $year = shift;
  230. my ($h,$j,$w);
  231. $h=int($year/100);
  232. $j=$year%100;
  233. if ($m<3) {
  234. $m = $m+10;
  235. if ($j==0) {
  236. $j=99;
  237. $h=$h-1;
  238. } else {
  239. $j=$j-1;
  240. }
  241. } else {
  242. $m=$m-2;
  243. }
  244. if (($year > 0) and ($year < 1582)) {
  245. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + 5 - $h;
  246. } elsif ($year==1582) {
  247. if ($m > 10) {
  248. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + 5 - $h;
  249. } elsif ($m==8) {
  250. if ($t>=1 and $t<=4) {
  251. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + 5 - $h;
  252. } elsif ($t>=15) {
  253. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + int($h/4) - (2*$h);
  254. }
  255. } elsif ($m <= 10) {
  256. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + int($h/4) - (2*$h);
  257. }
  258. } elsif ($year > 1582) {
  259. $w = $t + int((2.61 * $m) - 0.2) + $j + int($j/4) + int($h/4) - (2*$h);
  260. }
  261. if (($w % 7) >= 0) {
  262. $w = $w % 7;
  263. } else {
  264. $w = 7 - (-1 * ($w % 7));
  265. }
  266. return $w;
  267. }
  268. sub leap_year {
  269. my $year = shift;
  270. if ((($year % 4)==0) and !((($year % 100)==0) and (($year % 400) != 0))) {
  271. return 1;
  272. } else {
  273. return 0;
  274. }
  275. }
  276. sub month_days {
  277. my $month = shift;
  278. my $leap_year = shift;
  279. my @month_days = (31,28,31,30,31,30,31,31,30,31,30,31);
  280. if (($month == 2) and $leap_year) {
  281. return $month_days[$month - 1] + 1;
  282. } else {
  283. return $month_days[$month - 1];
  284. }
  285. }
  286. sub month_name {
  287. my $month = shift;
  288. my @month_name = (T('January'), T('February'), T('March'), T('April'),
  289. T('May'), T('June'), T('July'), T('August'),
  290. T('September'), T('October'), T('November'),
  291. T('December'));
  292. return $month_name[$month-1];
  293. }