EventAggregator

Changeset

0:c1127ca770b7
2009-03-21 Paul Boddie raw files shortlog changelog graph An event aggregator, producing a calendar containing events from pages in certain categories, where each event page describes the event using a definition list.
css/event-aggregator.css (file) docs/COPYING.txt (file) docs/LICENCE.txt (file) macros/EventAggregator.py (file)
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/css/event-aggregator.css	Sat Mar 21 21:39:17 2009 +0100
     1.3 @@ -0,0 +1,50 @@
     1.4 +/*  event-aggregator.css - some additional styles for the EventAggregator macro
     1.5 +                           which can be included in screen.css using...
     1.6 +
     1.7 +                           @import "event-aggregator.css";
     1.8 +
     1.9 +                           ...before any rules.
    1.10 +
    1.11 +Copyright (c) 2009 by Paul Boddie
    1.12 +Licensed under the GNU GPL (v2 or later), see COPYING.txt for details.
    1.13 +*/
    1.14 +
    1.15 +.event-month {
    1.16 +    width: 100%;
    1.17 +}
    1.18 +
    1.19 +.event-month-heading {
    1.20 +    background-color: #dddddd;
    1.21 +    text-align: center;
    1.22 +}
    1.23 +
    1.24 +.event-day-heading {
    1.25 +    background-color: #9999ff;
    1.26 +}
    1.27 +
    1.28 +.event-day {
    1.29 +    width: 14%;
    1.30 +}
    1.31 +
    1.32 +.event-day-empty {
    1.33 +    background-color: #ffffff;
    1.34 +}
    1.35 +
    1.36 +.event-day-busy {
    1.37 +    background-color: #ff9999;
    1.38 +}
    1.39 +
    1.40 +.event-day-excluded {
    1.41 +    background-color: #dddddd;
    1.42 +}
    1.43 +
    1.44 +.event-day-empty .event-day-number {
    1.45 +    color: #999999;
    1.46 +}
    1.47 +
    1.48 +.event-day-busy .event-day-number {
    1.49 +    color: #000000;
    1.50 +}
    1.51 +
    1.52 +/* vim: tabstop=4 expandtab shiftwidth=4
    1.53 + */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/docs/COPYING.txt	Sat Mar 21 21:39:17 2009 +0100
     2.3 @@ -0,0 +1,27 @@
     2.4 +Licence Agreement
     2.5 +-----------------
     2.6 +
     2.7 +Copyright (C) 2008, 2009 Paul Boddie <paul@boddie.org.uk>
     2.8 +
     2.9 +Some pieces of MoinMoin code were used in this work -
    2.10 +specifically the category regular expression code from
    2.11 +MoinMoin.config.multiconfig - and are thus covered by the
    2.12 +following copyrights:
    2.13 +
    2.14 +Copyright (C) 2000-2004 Juergen Hermann <jh@web.de>
    2.15 +Copyright (C) 2005-2008 MoinMoin:ThomasWaldmann
    2.16 +
    2.17 +This software is free software; you can redistribute it and/or
    2.18 +modify it under the terms of the GNU General Public License as
    2.19 +published by the Free Software Foundation; either version 2 of
    2.20 +the License, or (at your option) any later version.
    2.21 +
    2.22 +This software is distributed in the hope that it will be useful,
    2.23 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.24 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.25 +GNU General Public License for more details.
    2.26 +
    2.27 +You should have received a copy of the GNU General Public
    2.28 +License along with this library; see the file LICENCE.txt
    2.29 +If not, write to the Free Software Foundation, Inc.,
    2.30 +51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/docs/LICENCE.txt	Sat Mar 21 21:39:17 2009 +0100
     3.3 @@ -0,0 +1,339 @@
     3.4 +		    GNU GENERAL PUBLIC LICENSE
     3.5 +		       Version 2, June 1991
     3.6 +
     3.7 + Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
     3.8 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     3.9 + Everyone is permitted to copy and distribute verbatim copies
    3.10 + of this license document, but changing it is not allowed.
    3.11 +
    3.12 +			    Preamble
    3.13 +
    3.14 +  The licenses for most software are designed to take away your
    3.15 +freedom to share and change it.  By contrast, the GNU General Public
    3.16 +License is intended to guarantee your freedom to share and change free
    3.17 +software--to make sure the software is free for all its users.  This
    3.18 +General Public License applies to most of the Free Software
    3.19 +Foundation's software and to any other program whose authors commit to
    3.20 +using it.  (Some other Free Software Foundation software is covered by
    3.21 +the GNU Lesser General Public License instead.)  You can apply it to
    3.22 +your programs, too.
    3.23 +
    3.24 +  When we speak of free software, we are referring to freedom, not
    3.25 +price.  Our General Public Licenses are designed to make sure that you
    3.26 +have the freedom to distribute copies of free software (and charge for
    3.27 +this service if you wish), that you receive source code or can get it
    3.28 +if you want it, that you can change the software or use pieces of it
    3.29 +in new free programs; and that you know you can do these things.
    3.30 +
    3.31 +  To protect your rights, we need to make restrictions that forbid
    3.32 +anyone to deny you these rights or to ask you to surrender the rights.
    3.33 +These restrictions translate to certain responsibilities for you if you
    3.34 +distribute copies of the software, or if you modify it.
    3.35 +
    3.36 +  For example, if you distribute copies of such a program, whether
    3.37 +gratis or for a fee, you must give the recipients all the rights that
    3.38 +you have.  You must make sure that they, too, receive or can get the
    3.39 +source code.  And you must show them these terms so they know their
    3.40 +rights.
    3.41 +
    3.42 +  We protect your rights with two steps: (1) copyright the software, and
    3.43 +(2) offer you this license which gives you legal permission to copy,
    3.44 +distribute and/or modify the software.
    3.45 +
    3.46 +  Also, for each author's protection and ours, we want to make certain
    3.47 +that everyone understands that there is no warranty for this free
    3.48 +software.  If the software is modified by someone else and passed on, we
    3.49 +want its recipients to know that what they have is not the original, so
    3.50 +that any problems introduced by others will not reflect on the original
    3.51 +authors' reputations.
    3.52 +
    3.53 +  Finally, any free program is threatened constantly by software
    3.54 +patents.  We wish to avoid the danger that redistributors of a free
    3.55 +program will individually obtain patent licenses, in effect making the
    3.56 +program proprietary.  To prevent this, we have made it clear that any
    3.57 +patent must be licensed for everyone's free use or not licensed at all.
    3.58 +
    3.59 +  The precise terms and conditions for copying, distribution and
    3.60 +modification follow.
    3.61 +
    3.62 +		    GNU GENERAL PUBLIC LICENSE
    3.63 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    3.64 +
    3.65 +  0. This License applies to any program or other work which contains
    3.66 +a notice placed by the copyright holder saying it may be distributed
    3.67 +under the terms of this General Public License.  The "Program", below,
    3.68 +refers to any such program or work, and a "work based on the Program"
    3.69 +means either the Program or any derivative work under copyright law:
    3.70 +that is to say, a work containing the Program or a portion of it,
    3.71 +either verbatim or with modifications and/or translated into another
    3.72 +language.  (Hereinafter, translation is included without limitation in
    3.73 +the term "modification".)  Each licensee is addressed as "you".
    3.74 +
    3.75 +Activities other than copying, distribution and modification are not
    3.76 +covered by this License; they are outside its scope.  The act of
    3.77 +running the Program is not restricted, and the output from the Program
    3.78 +is covered only if its contents constitute a work based on the
    3.79 +Program (independent of having been made by running the Program).
    3.80 +Whether that is true depends on what the Program does.
    3.81 +
    3.82 +  1. You may copy and distribute verbatim copies of the Program's
    3.83 +source code as you receive it, in any medium, provided that you
    3.84 +conspicuously and appropriately publish on each copy an appropriate
    3.85 +copyright notice and disclaimer of warranty; keep intact all the
    3.86 +notices that refer to this License and to the absence of any warranty;
    3.87 +and give any other recipients of the Program a copy of this License
    3.88 +along with the Program.
    3.89 +
    3.90 +You may charge a fee for the physical act of transferring a copy, and
    3.91 +you may at your option offer warranty protection in exchange for a fee.
    3.92 +
    3.93 +  2. You may modify your copy or copies of the Program or any portion
    3.94 +of it, thus forming a work based on the Program, and copy and
    3.95 +distribute such modifications or work under the terms of Section 1
    3.96 +above, provided that you also meet all of these conditions:
    3.97 +
    3.98 +    a) You must cause the modified files to carry prominent notices
    3.99 +    stating that you changed the files and the date of any change.
   3.100 +
   3.101 +    b) You must cause any work that you distribute or publish, that in
   3.102 +    whole or in part contains or is derived from the Program or any
   3.103 +    part thereof, to be licensed as a whole at no charge to all third
   3.104 +    parties under the terms of this License.
   3.105 +
   3.106 +    c) If the modified program normally reads commands interactively
   3.107 +    when run, you must cause it, when started running for such
   3.108 +    interactive use in the most ordinary way, to print or display an
   3.109 +    announcement including an appropriate copyright notice and a
   3.110 +    notice that there is no warranty (or else, saying that you provide
   3.111 +    a warranty) and that users may redistribute the program under
   3.112 +    these conditions, and telling the user how to view a copy of this
   3.113 +    License.  (Exception: if the Program itself is interactive but
   3.114 +    does not normally print such an announcement, your work based on
   3.115 +    the Program is not required to print an announcement.)
   3.116 +
   3.117 +These requirements apply to the modified work as a whole.  If
   3.118 +identifiable sections of that work are not derived from the Program,
   3.119 +and can be reasonably considered independent and separate works in
   3.120 +themselves, then this License, and its terms, do not apply to those
   3.121 +sections when you distribute them as separate works.  But when you
   3.122 +distribute the same sections as part of a whole which is a work based
   3.123 +on the Program, the distribution of the whole must be on the terms of
   3.124 +this License, whose permissions for other licensees extend to the
   3.125 +entire whole, and thus to each and every part regardless of who wrote it.
   3.126 +
   3.127 +Thus, it is not the intent of this section to claim rights or contest
   3.128 +your rights to work written entirely by you; rather, the intent is to
   3.129 +exercise the right to control the distribution of derivative or
   3.130 +collective works based on the Program.
   3.131 +
   3.132 +In addition, mere aggregation of another work not based on the Program
   3.133 +with the Program (or with a work based on the Program) on a volume of
   3.134 +a storage or distribution medium does not bring the other work under
   3.135 +the scope of this License.
   3.136 +
   3.137 +  3. You may copy and distribute the Program (or a work based on it,
   3.138 +under Section 2) in object code or executable form under the terms of
   3.139 +Sections 1 and 2 above provided that you also do one of the following:
   3.140 +
   3.141 +    a) Accompany it with the complete corresponding machine-readable
   3.142 +    source code, which must be distributed under the terms of Sections
   3.143 +    1 and 2 above on a medium customarily used for software interchange; or,
   3.144 +
   3.145 +    b) Accompany it with a written offer, valid for at least three
   3.146 +    years, to give any third party, for a charge no more than your
   3.147 +    cost of physically performing source distribution, a complete
   3.148 +    machine-readable copy of the corresponding source code, to be
   3.149 +    distributed under the terms of Sections 1 and 2 above on a medium
   3.150 +    customarily used for software interchange; or,
   3.151 +
   3.152 +    c) Accompany it with the information you received as to the offer
   3.153 +    to distribute corresponding source code.  (This alternative is
   3.154 +    allowed only for noncommercial distribution and only if you
   3.155 +    received the program in object code or executable form with such
   3.156 +    an offer, in accord with Subsection b above.)
   3.157 +
   3.158 +The source code for a work means the preferred form of the work for
   3.159 +making modifications to it.  For an executable work, complete source
   3.160 +code means all the source code for all modules it contains, plus any
   3.161 +associated interface definition files, plus the scripts used to
   3.162 +control compilation and installation of the executable.  However, as a
   3.163 +special exception, the source code distributed need not include
   3.164 +anything that is normally distributed (in either source or binary
   3.165 +form) with the major components (compiler, kernel, and so on) of the
   3.166 +operating system on which the executable runs, unless that component
   3.167 +itself accompanies the executable.
   3.168 +
   3.169 +If distribution of executable or object code is made by offering
   3.170 +access to copy from a designated place, then offering equivalent
   3.171 +access to copy the source code from the same place counts as
   3.172 +distribution of the source code, even though third parties are not
   3.173 +compelled to copy the source along with the object code.
   3.174 +
   3.175 +  4. You may not copy, modify, sublicense, or distribute the Program
   3.176 +except as expressly provided under this License.  Any attempt
   3.177 +otherwise to copy, modify, sublicense or distribute the Program is
   3.178 +void, and will automatically terminate your rights under this License.
   3.179 +However, parties who have received copies, or rights, from you under
   3.180 +this License will not have their licenses terminated so long as such
   3.181 +parties remain in full compliance.
   3.182 +
   3.183 +  5. You are not required to accept this License, since you have not
   3.184 +signed it.  However, nothing else grants you permission to modify or
   3.185 +distribute the Program or its derivative works.  These actions are
   3.186 +prohibited by law if you do not accept this License.  Therefore, by
   3.187 +modifying or distributing the Program (or any work based on the
   3.188 +Program), you indicate your acceptance of this License to do so, and
   3.189 +all its terms and conditions for copying, distributing or modifying
   3.190 +the Program or works based on it.
   3.191 +
   3.192 +  6. Each time you redistribute the Program (or any work based on the
   3.193 +Program), the recipient automatically receives a license from the
   3.194 +original licensor to copy, distribute or modify the Program subject to
   3.195 +these terms and conditions.  You may not impose any further
   3.196 +restrictions on the recipients' exercise of the rights granted herein.
   3.197 +You are not responsible for enforcing compliance by third parties to
   3.198 +this License.
   3.199 +
   3.200 +  7. If, as a consequence of a court judgment or allegation of patent
   3.201 +infringement or for any other reason (not limited to patent issues),
   3.202 +conditions are imposed on you (whether by court order, agreement or
   3.203 +otherwise) that contradict the conditions of this License, they do not
   3.204 +excuse you from the conditions of this License.  If you cannot
   3.205 +distribute so as to satisfy simultaneously your obligations under this
   3.206 +License and any other pertinent obligations, then as a consequence you
   3.207 +may not distribute the Program at all.  For example, if a patent
   3.208 +license would not permit royalty-free redistribution of the Program by
   3.209 +all those who receive copies directly or indirectly through you, then
   3.210 +the only way you could satisfy both it and this License would be to
   3.211 +refrain entirely from distribution of the Program.
   3.212 +
   3.213 +If any portion of this section is held invalid or unenforceable under
   3.214 +any particular circumstance, the balance of the section is intended to
   3.215 +apply and the section as a whole is intended to apply in other
   3.216 +circumstances.
   3.217 +
   3.218 +It is not the purpose of this section to induce you to infringe any
   3.219 +patents or other property right claims or to contest validity of any
   3.220 +such claims; this section has the sole purpose of protecting the
   3.221 +integrity of the free software distribution system, which is
   3.222 +implemented by public license practices.  Many people have made
   3.223 +generous contributions to the wide range of software distributed
   3.224 +through that system in reliance on consistent application of that
   3.225 +system; it is up to the author/donor to decide if he or she is willing
   3.226 +to distribute software through any other system and a licensee cannot
   3.227 +impose that choice.
   3.228 +
   3.229 +This section is intended to make thoroughly clear what is believed to
   3.230 +be a consequence of the rest of this License.
   3.231 +
   3.232 +  8. If the distribution and/or use of the Program is restricted in
   3.233 +certain countries either by patents or by copyrighted interfaces, the
   3.234 +original copyright holder who places the Program under this License
   3.235 +may add an explicit geographical distribution limitation excluding
   3.236 +those countries, so that distribution is permitted only in or among
   3.237 +countries not thus excluded.  In such case, this License incorporates
   3.238 +the limitation as if written in the body of this License.
   3.239 +
   3.240 +  9. The Free Software Foundation may publish revised and/or new versions
   3.241 +of the General Public License from time to time.  Such new versions will
   3.242 +be similar in spirit to the present version, but may differ in detail to
   3.243 +address new problems or concerns.
   3.244 +
   3.245 +Each version is given a distinguishing version number.  If the Program
   3.246 +specifies a version number of this License which applies to it and "any
   3.247 +later version", you have the option of following the terms and conditions
   3.248 +either of that version or of any later version published by the Free
   3.249 +Software Foundation.  If the Program does not specify a version number of
   3.250 +this License, you may choose any version ever published by the Free Software
   3.251 +Foundation.
   3.252 +
   3.253 +  10. If you wish to incorporate parts of the Program into other free
   3.254 +programs whose distribution conditions are different, write to the author
   3.255 +to ask for permission.  For software which is copyrighted by the Free
   3.256 +Software Foundation, write to the Free Software Foundation; we sometimes
   3.257 +make exceptions for this.  Our decision will be guided by the two goals
   3.258 +of preserving the free status of all derivatives of our free software and
   3.259 +of promoting the sharing and reuse of software generally.
   3.260 +
   3.261 +			    NO WARRANTY
   3.262 +
   3.263 +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
   3.264 +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
   3.265 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
   3.266 +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
   3.267 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   3.268 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
   3.269 +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
   3.270 +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
   3.271 +REPAIR OR CORRECTION.
   3.272 +
   3.273 +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   3.274 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
   3.275 +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
   3.276 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
   3.277 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
   3.278 +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
   3.279 +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
   3.280 +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
   3.281 +POSSIBILITY OF SUCH DAMAGES.
   3.282 +
   3.283 +		     END OF TERMS AND CONDITIONS
   3.284 +
   3.285 +	    How to Apply These Terms to Your New Programs
   3.286 +
   3.287 +  If you develop a new program, and you want it to be of the greatest
   3.288 +possible use to the public, the best way to achieve this is to make it
   3.289 +free software which everyone can redistribute and change under these terms.
   3.290 +
   3.291 +  To do so, attach the following notices to the program.  It is safest
   3.292 +to attach them to the start of each source file to most effectively
   3.293 +convey the exclusion of warranty; and each file should have at least
   3.294 +the "copyright" line and a pointer to where the full notice is found.
   3.295 +
   3.296 +    <one line to give the program's name and a brief idea of what it does.>
   3.297 +    Copyright (C) <year>  <name of author>
   3.298 +
   3.299 +    This program is free software; you can redistribute it and/or modify
   3.300 +    it under the terms of the GNU General Public License as published by
   3.301 +    the Free Software Foundation; either version 2 of the License, or
   3.302 +    (at your option) any later version.
   3.303 +
   3.304 +    This program is distributed in the hope that it will be useful,
   3.305 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   3.306 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   3.307 +    GNU General Public License for more details.
   3.308 +
   3.309 +    You should have received a copy of the GNU General Public License along
   3.310 +    with this program; if not, write to the Free Software Foundation, Inc.,
   3.311 +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   3.312 +
   3.313 +Also add information on how to contact you by electronic and paper mail.
   3.314 +
   3.315 +If the program is interactive, make it output a short notice like this
   3.316 +when it starts in an interactive mode:
   3.317 +
   3.318 +    Gnomovision version 69, Copyright (C) year name of author
   3.319 +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   3.320 +    This is free software, and you are welcome to redistribute it
   3.321 +    under certain conditions; type `show c' for details.
   3.322 +
   3.323 +The hypothetical commands `show w' and `show c' should show the appropriate
   3.324 +parts of the General Public License.  Of course, the commands you use may
   3.325 +be called something other than `show w' and `show c'; they could even be
   3.326 +mouse-clicks or menu items--whatever suits your program.
   3.327 +
   3.328 +You should also get your employer (if you work as a programmer) or your
   3.329 +school, if any, to sign a "copyright disclaimer" for the program, if
   3.330 +necessary.  Here is a sample; alter the names:
   3.331 +
   3.332 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
   3.333 +  `Gnomovision' (which makes passes at compilers) written by James Hacker.
   3.334 +
   3.335 +  <signature of Ty Coon>, 1 April 1989
   3.336 +  Ty Coon, President of Vice
   3.337 +
   3.338 +This General Public License does not permit incorporating your program into
   3.339 +proprietary programs.  If your program is a subroutine library, you may
   3.340 +consider it more useful to permit linking proprietary applications with the
   3.341 +library.  If this is what you want to do, use the GNU Lesser General
   3.342 +Public License instead of this License.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/macros/EventAggregator.py	Sat Mar 21 21:39:17 2009 +0100
     4.3 @@ -0,0 +1,361 @@
     4.4 +# -*- coding: iso-8859-1 -*-
     4.5 +"""
     4.6 +    MoinMoin - EventAggregator Macro
     4.7 +
     4.8 +    @copyright: 2008, 2009 by Paul Boddie <paul@boddie.org.uk>
     4.9 +    @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
    4.10 +                2005-2008 MoinMoin:ThomasWaldmann.
    4.11 +    @license: GNU GPL (v2 or later), see COPYING.txt for details.
    4.12 +"""
    4.13 +
    4.14 +from MoinMoin.Page import Page
    4.15 +from MoinMoin import wikiutil, search, version
    4.16 +import calendar
    4.17 +import re
    4.18 +
    4.19 +__version__ = "0.1"
    4.20 +
    4.21 +Dependencies = ['pages']
    4.22 +
    4.23 +# Regular expressions where MoinMoin does not provide the required support.
    4.24 +
    4.25 +category_regexp = None
    4.26 +definition_list_regexp = re.compile(ur'^\s+(?P<term>.*?)::\s(?P<desc>.*?)$', re.UNICODE | re.MULTILINE)
    4.27 +date_regexp = re.compile(ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})', re.UNICODE)
    4.28 +month_regexp = re.compile(ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})', re.UNICODE)
    4.29 +
    4.30 +# Date labels.
    4.31 +
    4.32 +month_labels = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    4.33 +weekday_labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
    4.34 +
    4.35 +# Utility functions.
    4.36 +
    4.37 +def isMoin15():
    4.38 +    return version.release.startswith("1.5.")
    4.39 +
    4.40 +def getCategoryPattern(request):
    4.41 +    global category_regexp
    4.42 +
    4.43 +    try:
    4.44 +        return request.cfg.cache.page_category_regexact
    4.45 +    except AttributeError:
    4.46 +
    4.47 +        # Use regular expression from MoinMoin 1.7.1 otherwise.
    4.48 +
    4.49 +        if category_regexp is None:
    4.50 +            category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE)
    4.51 +        return category_regexp
    4.52 +
    4.53 +# The main activity functions.
    4.54 +
    4.55 +def getPages(pagename, request):
    4.56 +
    4.57 +    "Return the links minus category links for 'pagename' using the 'request'."
    4.58 +
    4.59 +    query = search.QueryParser().parse_query('category:%s' % pagename)
    4.60 +    if isMoin15():
    4.61 +        results = search.searchPages(request, query)
    4.62 +        results.sortByPagename()
    4.63 +    else:
    4.64 +        results = search.searchPages(request, query, "page_name")
    4.65 +
    4.66 +    cat_pattern = getCategoryPattern(request)
    4.67 +    pages = []
    4.68 +    for page in results.hits:
    4.69 +        if not cat_pattern.match(page.page_name):
    4.70 +            pages.append(page)
    4.71 +    return pages
    4.72 +
    4.73 +def getPrettyPageName(page):
    4.74 +
    4.75 +    "Return a nicely formatted title/name for the given 'page'."
    4.76 +
    4.77 +    return page.split_title(force=1).replace("_", " ").replace("/", u" » ")
    4.78 +
    4.79 +def getEventDetails(page):
    4.80 +
    4.81 +    "Return a dictionary of event details from the given 'page'."
    4.82 +
    4.83 +    event_details = {}
    4.84 +
    4.85 +    if page.pi["format"] == "wiki":
    4.86 +        for match in definition_list_regexp.finditer(page.body):
    4.87 +            # Permit case-insensitive list terms.
    4.88 +            term = match.group("term").lower()
    4.89 +            desc = match.group("desc")
    4.90 +            if term in ("start", "end"):
    4.91 +                desc = getDate(desc)
    4.92 +            if desc is not None:
    4.93 +                event_details[term] = desc
    4.94 +
    4.95 +    return event_details
    4.96 +
    4.97 +def getDate(s):
    4.98 +
    4.99 +    "Parse the string 's', extracting and returning a date string."
   4.100 +
   4.101 +    m = date_regexp.search(s)
   4.102 +    if m:
   4.103 +        return tuple(map(int, m.groups()))
   4.104 +    else:
   4.105 +        return None
   4.106 +
   4.107 +def getMonth(s):
   4.108 +
   4.109 +    "Parse the string 's', extracting and returning a month string."
   4.110 +
   4.111 +    m = month_regexp.search(s)
   4.112 +    if m:
   4.113 +        return tuple(map(int, m.groups()))
   4.114 +    else:
   4.115 +        return None
   4.116 +
   4.117 +def execute(macro, args):
   4.118 +
   4.119 +    """
   4.120 +    Execute the 'macro' with the given 'args': an optional list of selected
   4.121 +    category names (categories whose pages are to be shown), together with
   4.122 +    optional named arguments of the form "start=YYYY-MM" and "end=YYYY-MM"
   4.123 +    (indicating a restricted view of all events), and "mode=list" or
   4.124 +    "mode=calendar" (indicating the style of view).
   4.125 +    """
   4.126 +
   4.127 +    request = macro.request
   4.128 +    fmt = macro.formatter
   4.129 +    page = fmt.page
   4.130 +    _ = request.getText
   4.131 +
   4.132 +    # Interpret the arguments.
   4.133 +
   4.134 +    try:
   4.135 +        parsed_args = args and wikiutil.parse_quoted_separated(args, name_value=False) or []
   4.136 +    except AttributeError:
   4.137 +        parsed_args = args.split(",")
   4.138 +
   4.139 +    parsed_args = [arg for arg in parsed_args if arg]
   4.140 +
   4.141 +    # Get special arguments.
   4.142 +
   4.143 +    category_names = []
   4.144 +    calendar_start = None
   4.145 +    calendar_end = None
   4.146 +    mode = "calendar"
   4.147 +
   4.148 +    for arg in parsed_args:
   4.149 +        if arg.startswith("start="):
   4.150 +            calendar_start = getMonth(arg[6:])
   4.151 +        elif arg.startswith("end="):
   4.152 +            calendar_end = getMonth(arg[4:])
   4.153 +        elif arg.startswith("mode="):
   4.154 +            mode = arg[5:]
   4.155 +        else:
   4.156 +            category_names.append(arg)
   4.157 +
   4.158 +    # Generate a list of events found on pages belonging to the specified
   4.159 +    # categories, as found in the macro arguments.
   4.160 +
   4.161 +    events = []
   4.162 +    shown_events = []
   4.163 +    earliest = calendar_start
   4.164 +    latest = calendar_end
   4.165 +
   4.166 +    for category_name in category_names:
   4.167 +
   4.168 +        # Get the pages and page names in the category.
   4.169 +
   4.170 +        pages_in_category = getPages(category_name, request)
   4.171 +
   4.172 +        # Visit each page in the category.
   4.173 +
   4.174 +        for page_in_category in pages_in_category:
   4.175 +            pagename = page_in_category.page_name
   4.176 +
   4.177 +            # Get a real page, not a result page.
   4.178 +
   4.179 +            real_page_in_category = Page(request, pagename)
   4.180 +            event_details = getEventDetails(real_page_in_category)
   4.181 +            event = (real_page_in_category, event_details)
   4.182 +            events.append(event)
   4.183 +
   4.184 +            # Test for the suitability of the event.
   4.185 +
   4.186 +            if event_details.has_key("start") and event_details.has_key("end"):
   4.187 +
   4.188 +                start_month = event_details["start"][:2]
   4.189 +                end_month = event_details["end"][:2]
   4.190 +
   4.191 +                # Compare the months of the dates to the requested calendar
   4.192 +                # window, if any.
   4.193 +
   4.194 +                if (calendar_start is None or end_month >= calendar_start) and \
   4.195 +                    (calendar_end is None or start_month <= calendar_end):
   4.196 +
   4.197 +                    shown_events.append(event)
   4.198 +
   4.199 +                    if earliest is None or start_month < earliest:
   4.200 +                        earliest = start_month
   4.201 +                    if latest is None or end_month > latest:
   4.202 +                        latest = end_month
   4.203 +
   4.204 +    # Make a calendar.
   4.205 +
   4.206 +    output = []
   4.207 +
   4.208 +    if mode == "calendar":
   4.209 +
   4.210 +        end_year = latest[0]
   4.211 +
   4.212 +        for year in range(earliest[0], end_year + 1):
   4.213 +            if year < latest[0]:
   4.214 +                end_month = 12
   4.215 +            else:
   4.216 +                end_month = latest[1]
   4.217 +
   4.218 +            if year > earliest[0]:
   4.219 +                start_month = 1
   4.220 +            else:
   4.221 +                start_month = earliest[1]
   4.222 +
   4.223 +            for month in range(start_month, end_month + 1):
   4.224 +
   4.225 +                # Output a month.
   4.226 +
   4.227 +                output.append(fmt.table(on=1, attrs={"tableclass" : "event-month"}))
   4.228 +
   4.229 +                output.append(fmt.table_row(on=1))
   4.230 +                output.append(fmt.table_cell(on=1, attrs={"class" : "event-month-heading", "colspan" : "7"}))
   4.231 +                output.append(fmt.span(on=1))
   4.232 +                output.append(fmt.text(_(month_labels[month - 1]))) # zero-based labels
   4.233 +                output.append(fmt.span(on=0))
   4.234 +                output.append(fmt.text(" "))
   4.235 +                output.append(fmt.span(on=1))
   4.236 +                output.append(fmt.text(year))
   4.237 +                output.append(fmt.span(on=0))
   4.238 +                output.append(fmt.table_cell(on=0))
   4.239 +                output.append(fmt.table_row(on=0))
   4.240 +
   4.241 +                # Weekday headings.
   4.242 +
   4.243 +                output.append(fmt.table_row(on=1))
   4.244 +
   4.245 +                for weekday in range(0, 7):
   4.246 +                    output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading"}))
   4.247 +                    output.append(fmt.text(_(weekday_labels[weekday])))
   4.248 +                    output.append(fmt.table_cell(on=0))
   4.249 +
   4.250 +                output.append(fmt.table_row(on=0))
   4.251 +
   4.252 +                # Process the days of the month.
   4.253 +
   4.254 +                start_weekday, number_of_days = calendar.monthrange(year, month)
   4.255 +
   4.256 +                # The start weekday is the weekday of day number 1.
   4.257 +                # Find the first day of the week, counting from below zero, if
   4.258 +                # necessary, in order to land on the first day of the month as
   4.259 +                # day number 1.
   4.260 +
   4.261 +                first_day = 1 - start_weekday
   4.262 +
   4.263 +                while first_day <= number_of_days:
   4.264 +
   4.265 +                    # Output a week.
   4.266 +
   4.267 +                    output.append(fmt.table_row(on=1))
   4.268 +
   4.269 +                    for weekday in range(0, 7):
   4.270 +                        day = first_day + weekday
   4.271 +
   4.272 +                        # Output out-of-month days.
   4.273 +
   4.274 +                        if day < 1 or day > number_of_days:
   4.275 +                            output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"}))
   4.276 +                            output.append(fmt.table_cell(on=0))
   4.277 +
   4.278 +                        # Output normal days.
   4.279 +
   4.280 +                        else:
   4.281 +                            # Get event details.
   4.282 +                            # NOTE: Can be made more efficient.
   4.283 +
   4.284 +                            date = (year, month, day)
   4.285 +                            day_events = []
   4.286 +
   4.287 +                            for event_page, event_details in shown_events:
   4.288 +
   4.289 +                                # Test for the event on the current day.
   4.290 +
   4.291 +                                if event_details["start"] <= date <= event_details["end"]:
   4.292 +                                    day_events.append((event_page, event_details))
   4.293 +
   4.294 +                            # Output the day.
   4.295 +
   4.296 +                            if day_events:
   4.297 +                                output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"}))
   4.298 +                            else:
   4.299 +                                output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"}))
   4.300 +
   4.301 +                            output.append(fmt.div(on=1, css_class="event-day-number"))
   4.302 +                            output.append(fmt.text(day))
   4.303 +                            output.append(fmt.div(on=0))
   4.304 +
   4.305 +                            # Show event details.
   4.306 +
   4.307 +                            for event_page, event_details in day_events:
   4.308 +
   4.309 +                                # Get a pretty version of the page name.
   4.310 +
   4.311 +                                pretty_pagename = getPrettyPageName(event_page)
   4.312 +
   4.313 +                                # Output the event.
   4.314 +
   4.315 +                                output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
   4.316 +                                output.append(fmt.linebreak())
   4.317 +
   4.318 +                            # End of day.
   4.319 +
   4.320 +                            output.append(fmt.table_cell(on=0))
   4.321 +
   4.322 +                    output.append(fmt.table_row(on=0))
   4.323 +
   4.324 +                    first_day += 7
   4.325 +
   4.326 +                # End of month.
   4.327 +
   4.328 +                output.append(fmt.table(on=0))
   4.329 +
   4.330 +    elif mode == "list":
   4.331 +        output.append(fmt.bullet_list(on=1, attr={"class" : "event-listings"}))
   4.332 +
   4.333 +        for event_page, event_details in shown_events:
   4.334 +
   4.335 +            # Get a pretty version of the page name.
   4.336 +
   4.337 +            pretty_pagename = getPrettyPageName(event_page)
   4.338 +
   4.339 +            output.append(fmt.listitem(on=1, attr={"class" : "event-listing"}))
   4.340 +
   4.341 +            # Link to the page using the pretty name.
   4.342 +
   4.343 +            output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
   4.344 +
   4.345 +            # Add the event details.
   4.346 +
   4.347 +            output.append(fmt.definition_list(on=1, attr={"class" : "event-details"}))
   4.348 +
   4.349 +            for key, value in event_details.items():
   4.350 +                output.append(fmt.definition_term(on=1))
   4.351 +                output.append(fmt.text(key))
   4.352 +                output.append(fmt.definition_term(on=0))
   4.353 +                output.append(fmt.definition_desc(on=1))
   4.354 +                output.append(fmt.text(value))
   4.355 +                output.append(fmt.definition_desc(on=0))
   4.356 +
   4.357 +            output.append(fmt.definition_list(on=0))
   4.358 +            output.append(fmt.listitem(on=0))
   4.359 +
   4.360 +        output.append(fmt.bullet_list(on=0))
   4.361 +
   4.362 +    return ''.join(output)
   4.363 +
   4.364 +# vim: tabstop=4 expandtab shiftwidth=4