view data/plugin/parser/ @ 630:f3676743483d

initial version of an ical/ics data parser rendered by fullcalendar attachment default.ics is rendered on default requires python package icalendar and js libray fullcalendar (both on PyPi)
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Tue, 02 Dec 2014 13:51:53 +0100
children 127da830be6c
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
    MoinMoin - fullcalendar

    This parser is used to visualize icals date entries by fullcalendar

    You may want to add to your something like
    html_head = '''
<link rel="stylesheet" type="text/css" charset="utf-8" href="%(url_prefix_static)s/fullcalendar/fullcalendar.css">
<link rel="stylesheet" type="text/css" charset="utf-8" media="print" href="%(url_prefix_static)s/fullcalendar/fullcalendar.print.css">
<script src='%(url_prefix_static)s/fullcalendar/lib/moment.min.js'></script>
<script src='%(url_prefix_static)s/fullcalendar/lib/jquery.min.js'></script>
<script src='%(url_prefix_static)s/fullcalendar/fullcalendar.min.js'></script>
''' % {"url_prefix_static": url_prefix_static}

    #format fullcalendar maxwidth=400px, week_numbers=1, left=today

    @copyright: 2014 by MoinMoin:ReimarBauer
    @license: GNU GPL, see COPYING for details.

    import icalendar
except ImportError:
    icalendar = None

import os
import json
import datetime
from MoinMoin import config, wikiutil
from MoinMoin.action import AttachFile

def fullcalendar_settings(attachfile=u'default.ics', editable=0, default_date=u'',
                          left=u'prev,next,today', right=u'month,agendaWeek,agendaDay',
    dummy function to initialize all default parameters for fullcalendar.
    The parameters are checked for wrong input.
    @param attachfile: name of attachmet to read ical data from and convert to json
    @param editable: default false
    @param default_date: default current day
    @param week_numbers: default false, determines if week numbers should be displayed on the calendar.
    @param left: default: 'prev,next,today'
           prev: button for moving the calendar back one month/week/day,
           next: button for moving the calendar forward one month/week/day
           today: button for moving the calendar to the current month/week/day
    @param right: default: month,agendaWeek,agendaDay'
           month: view month
           agendaWeek: view week
           agendaDay:  view day
    @param title: default title,text containing the current month/week/day
    @param maxwidth: width used default 900px
    return locals()

Dependencies = ["page"]

class Parser:
    """ fullcalendar parser """
    extensions = '*.ics'
    def __init__(self, raw, request, **kw):
        self.pagename =
        self.raw = raw.strip('\n')
        self.request = request
        self.formatter = request.formatter
        self.form = None
        self.ical_data = None
        self.json_data = u""
        self.attachfile = u"default.ical"
        self.editable = 0
        self.default_date = u''
        self.week_numbers = 0
        self.left = u'prev,next,today'
        self.right = u'month,agendaWeek,agendaDay'
        self.title = u'title'
        self.maxwidth = u'900px'
        self._ = request.getText

        args = kw.get('format_args', '')
        self.init_settings = False
            settings = wikiutil.invoke_extension_function(request, fullcalendar_settings, args)
            for key, value in settings.items():
                setattr(self, key, value)
            # saves the state of valid input
            self.init_settings = True
        except ValueError, err:
            msg = u"fullcalendar: %s" % err.args[0]

    def render(self, formatter):
        """ renders calendar  """

        _ = self._

        # checks if initializing of all attributes in __init__ was done
        if self.init_settings:
            # reads in datafile if exists and converts it to json
            editable = 'false'
            if self.editable == 1:
                editable = 'true'
            default_date = self.default_date
            if default_date == u'':
                default_date =
            week_numbers = 'false'
            if self.week_numbers == 1:
                week_numbers = 'true'

            html_text = """

        $(document).ready(function() {

			header: {
				left: '%(left)s',
				center: '%(title)s',
				right: '%(right)s'
                defaultDate: '%(default_date)s',
                editable: %(editable)s,
                eventLimit: true, // allow "more" link when too many events
                weekNumbers: %(week_numbers)s,



        #calendar {
            max-width: %(maxwidth)s;
            margin: 0 auto;

    <div id='calendar'></div>

            return html_text % {"left": self.left,
                                "title": self.title,
                                "right": self.right,
                                "default_date": default_date,
                                "editable": editable,
                                "week_numbers": week_numbers,
                                "json": self.json_data,
                                "maxwidth": self.maxwidth,

    def get_ical_data(self):
        reads ical attachfile
        if icalendar is None:

        if and AttachFile.exists(self.request, self.pagename, self.attachfile):
            ical_file = os.path.join(AttachFile.getAttachDir(self.request, self.pagename), self.attachfile).encode(config.charset)
            with open(ical_file, 'rb') as fhandler:
                self.ical_data = icalendar.Calendar.from_ical(

    def ical2json(self):
        comverts ical data to json
        This routine was inspired by this blog article
        events = []
        if self.ical_data is not None:
            for item in self.ical_data.walk():
                if == 'VEVENT':
                    new_event = {'editable': False,
                                 'allDay': False}
                    new_event['title'] = item.get('summary')
                    new_event['start'] = item.get('dtstart').dt.isoformat()
                    new_event['end'] = item.get('dtend').dt.isoformat()
                    if item.get('location'):
                        new_event['url'] = item.get('location')
            self.json_data = json.dumps(events, indent=4)

    def format(self, formatter):
        """ parser output """
        # checks if initializing of all attributes in __init__ was done
        if self.init_settings:
            self.request.write(self.formatter.div(1, css_class="fullcalendar"))