イベントカレンダーの作成 [Plone3.3]

eventcalendar.jpg年・月・日表示ができるイベントカレンダーをコレクションのビューとして作成する。利用方法はコレクションで表示するイベントタイプの検索条件(コンテンツタイプ、位置、日付など)を指定することを想定する。

スキンレイヤ

スキンレイヤの登録

まず portal_skins 内に新しくスキン格納用のフォルダ(eng_calendar_skins)を追加する。次に portal_skins の Properties で、custom の下に eng_calendar_skins を追加する。これでスキンにこのディレクトリも読み込まれるようになる。

Name : Plone Default
Layers :
  custom
  eng_calendar_skins
   :

 

スキンの作成

週の文字列生成スクリプト

週の文字列を生成するスクリプト eng_calendar_weekstr をスキンレイヤ内に作成する。

from Products.CMFCore.utils import getToolByName
from Products.CMFPlone import PloneMessageFactory

translation_service = getToolByName(context, 'translation_service');
result_list = []
for i in xrange(7):
    msgid = translation_service.day_msgid(i, format='a')
    english = translation_service.weekday_english(i, format='a')
    result_list.append(PloneMessageFactory(msgid, default=english))

return result_list

イベントリスト生成スクリプト

1ヶ月のイベントリスト生成スクリプト eng_calendar を次のように作成する。パラメータとしてリストを作成する年、月を渡す。

Parameter List

year, month

本体

end_date = container.portal_calendar.getNextMonth(month, year) - 1
last_day = end_date.day()

results = context.queryCatalog(
              end =  { 'query' : DateTime(year, month, 1, 0, 0), 'range' : 'min'},
              start = { 'query' : DateTime(year, month, last_day, 23, 59), 'range' : 'max'},
              sort_on = 'start',
)

event_list = []
for i in xrange(last_day):
    day = i + 1
    event_list.append({ 'day': day,
                        'week': DateTime(year, month, day).dow(),
                        'daily_events': [], })

for result in results:
    if result.start.Date() == result.end.Date():
        day = result.start.day()
        event_list[day-1]['daily_events'].append( { 'title': result.Title,
                                                    'start': result.start,
                                                    'end': result.end,
                                                    'location': result.location,
                                                    'url': result.getURL(), } )
    else:
        if result.start < DateTime(year, month, 1, 0, 0):
            day_begin = 1
        else:
            day_begin = result.start.day()
        if result.end > DateTime(year, month, last_day, 23, 59):
            day_end = last_day
        else:
            day_end = result.end.day()
        for day in xrange(day_begin, day_end + 1):
            event_list[day-1]['daily_events'].append( { 'title': result.Title,
                                                        'start': result.start,
                                                        'end': result.end,
                                                        'location': result.location,
                                                        'url': result.getURL(), } )

return event_list

カレンダーテンプレート

イベントカレンダーを表示するテンプレートを eng_calendar_view として次のように作成する。

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      metal:use-macro="here/main_template/macros/master"
      i18n:domain="plone">

<body>
<div metal:fill-slot="main">
<metal:main_macro define-macro="main">
    <metal:body define-macro="body_macro"
                tal:define="kssClassesView context/@@kss_field_decorator_view;
                            getKssClasses nocall:kssClassesView/getKssClassesInlineEditable;
                            templateId template/getId">

        <div tal:replace="structure provider:plone.abovecontenttitle" />

        <h1 class="documentFirstHeading"> 
            <metal:field use-macro="python:here.widget('title', mode='view')">
            Title
            </metal:field>
        </h1>

        <div tal:replace="structure provider:plone.belowcontenttitle" />

        <p class="documentDescription">
            <metal:field use-macro="python:here.widget('description', mode='view')">
            Description
            </metal:field>
        </p>

        <div tal:replace="structure provider:plone.abovecontentbody" />

        <div tal:define="translation python:context.translation_service;
                         today python:DateTime();
                         month request/month | today/month;
                         month python:test(not request.has_key('month') and request.has_key('year'), 4, month);
                         month python:int(month);
                         day request/day | today/day;
                         day python:int(day);
                         orig_year request/year | today/year;
                         orig_year python:int(orig_year);
                         year python:month<4 and orig_year-1 or orig_year;
                         week_list python:context.eng_calendar_weekstr();
                         en_week_list python: [ translation.weekday_english(i, format='a') for i in range(0,7) ];
                         month_english python:translation.month_english(month);
                         event_list python:context.eng_calendar(orig_year, month);
                         base_url python:context.absolute_url();
                         msgfactory python:modules['Products.CMFPlone'].PloneMessageFactory;
                         param_year python:request.has_key('year');
                         param_month python:request.has_key('month');
                         param_day python:request.has_key('day');">

          <!-- 年別タブ -->
          <div tal:define="results python:context.queryCatalog( sort_on='start' );"
               tal:condition="results">
          <div id="year-tabs" tal:define="today_year today/year;
                                          today_year python:int(today_year);
                                          results python:context.queryCatalog( sort_on='start' );
                                          month_begin python:test(results, results[0].start.month(), month);
                                          year_begin python:test(results, results[0].start.year(), orig_year);
                                          year_begin python:month_begin<4 and year_begin-1 or year_begin;
                                          results python:context.queryCatalog( sort_on='end' );
                                          month_end python:test(results, results[len(results)-1].end.month(), month);
                                          year_end python:test(results, results[len(results)-1].end.year(), orig_year);
                                          year_end python:month_end<4 and year_end-1 or year_end;">
            <ul>
              <tal:items tal:repeat="item python:xrange(year_begin, year_end+1)">
                <li class="year-tab">
                  <a href="#"
                     tal:attributes="href python:base_url + '?year=' + str(item)">
                    <span tal:replace="python:str(item)" /><span tal:replace="python:test(language == 'ja', u'\u5e74\u5ea6', '')" />
                  </a>
                </li>
              </tal:items>
            </ul>
          </div>
          </div>
          <div class="visualClear"><!-- --></div>

          <h2><span tal:replace="year" /> <span tal:replace="python:test(language == 'ja', u'\u5e74\u5ea6', u'Events')" /></h2>

          <!-- 月別タブ -->
          <div id="month-tabs" tal:define="month_list python:range(4,13) + range(1,4);"
                               tal:condition="python:not param_year or param_month or param_day">
            <ul>
              <tal:item repeat="month_num month_list">
	        <li class="month-tab"
                    tal:define="tab_year python:test(month_num<4, year+1, year)"
	            tal:attributes="class python:(month_num == month and 'active ' or '') + 'month_tab'">
	          <a href="#"
	             tal:attributes="href python:base_url + '?year=' + str(tab_year) + '&month=' + str(month_num);">
	            <span tal:define="english python:translation.month_english(month_num);
	        		      msgid python:translation.month_msgid(month_num);
	        		      msg python:msgfactory(msgid, default=english);"
		          tal:replace="msg">
	              April
	            </span>
	          </a>	       
	        </li>
              </tal:item>
            </ul>
          </div>

          <!-- 月カレンダーのヘッダ -->
          <div id="calendar_header"
               tal:condition="python:not param_day and (param_month or not param_year)">
            <div id="april-logo" class="month-logo"
                 tal:attributes="id python:month_english.lower() + '-logo';
                                 class string:month-logo;">
            <img tal:attributes="src python:month_english.lower() + '-logo.jpg';
                                 alt python:month_english;" />
            </div>
            <div id="april-picture" class="month-picture"
                 tal:attributes="id python:month_english.lower() + '-picture';
                                 class string:month-picture;">
            <img tal:attributes="src python:month_english.lower() + '-picture.jpg';" />
            </div>
          </div>

          <!-- 月カレンダーのカレンダー部 -->
          <table id="current_month_events"
                 tal:condition="python:not param_day and (param_month or not param_year)">
            <tal:item tal:repeat="item event_list">
            <tr class="event_item"
                tal:define="week_str python:week_list[item['week']];
                            en_week_str python:en_week_list[item['week']].lower();"
                tal:attributes="class python:'event_item week_' + en_week_str; ">
              <td class="day">
                <a href="#"
                   tal:omit-tag="python:not item['daily_events']"
                   tal:attributes="href python:base_url + '?year=' + str(orig_year) + '&month=' + str(month) + '&amp;day=' + str(item['day'])">
                  <span tal:replace="python:item['day']">1</span>
                </a>
              </td>
              <td class="week">
                <span tal:content="week_str">Mon</span>
              </td>
              <td class="event_of_day">
                <ul tal:condition="item/daily_events">
                  <li tal:repeat="event item/daily_events">
                    <a href="#" tal:attributes="href event/url">
                      <span tal:replace="event/title" />
                    </a>
                  </li>
                </ul>
              </td>
            </tr>
            </tal:item>
          </table>

          <!-- 日カレンダーのヘッダ -->
          <div tal:condition="python:param_day">
          <div id="calendar_header"
               tal:define="msgid python:translation.month_msgid(month);
                           english python:translation.month_english(month);
                           month_msg python:msgfactory(msgid, default=english);
                           week_num python:event_list[day-1]['week'];
                           week_msgid python:translation.day_msgid(week_num);
                           week_english python:translation.weekday_english(week_num);
                           week_msg python:msgfactory(week_msgid, default=week_english);">

            <div class="current-date">
              <div class="today" tal:condition="python:language == 'ja'">
                <span class="month" tal:content="month_msg" />
                <span class="day" tal:content="python:str(day)">28</span><tal:date tal:replace="python:u'\u65e5'" />
                <span class="weekday" tal:content="week_msg" />
              </div>
              <div class="today" tal:condition="python:language != 'ja'">
                <span class="weekday" tal:content="week_msg">Monday</span>,
                <span class="month" tal:content="month_msg">April</span>
                <span class="day" tal:content="python:str(day)">28</span>
              </div>
            </div>

            <div id="current_month_calendar" class="event_calendar">
              <div id="calendar_month">
                <span tal:replace="month_msg">March</span>
              </div>
              <table>
                <tr>
                  <td class="weekday_sun" i18n:translate="weekday_sun_short">Su</td>
                  <td class="weekday_mon" i18n:translate="weekday_mon_short">Mo</td>
                  <td class="weekday_tue" i18n:translate="weekday_tue_short">Tu</td>
                  <td class="weekday_wed" i18n:translate="weekday_wed_short">We</td>
                  <td class="weekday_thu" i18n:translate="weekday_thu_short">Th</td>
                  <td class="weekday_fri" i18n:translate="weekday_fri_short">Fr</td>
                  <td class="weekday_sat" i18n:translate="weekday_sat_short">Sa</td>
                </tr>
                <tr tal:define="first_week python:event_list[0]['week'];
                                week_num python:len(event_list) + first_week;
                                week_num python:test(week_num%7, int(week_num/7)+1, int(week_num/7));"
                    tal:repeat="week python:xrange(week_num)">
                  <tal:item repeat="date python:xrange(week*7-first_week+1, week*7-first_week+8)">
                  <td tal:condition="python:date>0 and date<=len(event_list)"
                      tal:attributes="class python:event_list[date-1]['daily_events'] and 'event' or 'no_event';">
                    <a href="#"
                       tal:omit-tag="python:not event_list[date-1]['daily_events']"
                       tal:attributes="href python:base_url + '?year=' + str(orig_year) + '&month=' + str(month) + '&amp;day=' + str(date);">
                      <span tal:replace="python:str(date)">1</span>
                    </a>
                  </td>
                  <td tal:condition="python:not (date>0 and date<=len(event_list))" />
                  </tal:item>
                </tr>
              </table>
            </div>
          </div>
          </div>

          <!-- 日カレンダー -->
          <div id="day_events" tal:condition="python:param_day">
            <div class="no_event_today"
                 tal:condition="python:not event_list[day-1]['daily_events']"
                 tal:content="python:test(language == 'ja', u'\u672c\u65e5\u958b\u50ac\u4e88\u5b9a\u306e\u30a4\u30d9\u30f3\u30c8\u306f\u3042\u308a\u307e\u305b\u3093\u3002', 'No Events Today.')"></div>
            <table id="today_events" tal:condition="python:event_list[day-1]['daily_events']">
              <tr class="day_list_header">
                <th class="event_title"
                    tal:content="python:language=='ja' and u'\u884c\u4e8b\u540d' or 'Event'">Event</th>
                <th class="event_when"
                    tal:content="python:language=='ja' and u'\u65e5\u6642\u30fb\u5834\u6240' or 'Date/Time, Location'">Date/Time</th>
              </tr>
              <tal:item tal:repeat="item python:event_list[day-1]['daily_events']">
              <tr class="event_item">
                <td class="event_title">
                  <a href="#" tal:attributes="href item/url;" tal:content="item/title" />
                </td>
                <td class="event_when"
                    tal:define="start_date item/start/Date;
                                end_date item/end/Date;">
                  <div tal:condition="python:start_date == end_date" tal:omit-tag="">
                    <span tal:content="item/start/TimeMinutes">3:10</span> - 
                    <span tal:content="item/end/TimeMinutes"
                          tal:condition="python:item['start'] != item['end']">5:45</span>
                    <br /><span tal:content="item/location" />
                  </div>
                  <div tal:condition="python:start_date != end_date" tal:omit-tag=""
                       tal:define="notime python:test(item['start'].TimeMinutes()=='00:00' and item['end'].TimeMinutes()=='00:00', True, False)">
                    <span tal:content="python:item['start'].Date() + test(notime, '', ' ' + item['start'].TimeMinutes())">3:10</span> - 
                    <span tal:content="python:item['end'].Date() + test(notime, '', ' ' + item['end'].TimeMinutes())">5:45</span>
                    <br /><span tal:content="item/location" />
                  </div>
                </td>
              </tr>
              </tal:item>
            </table>
          </div>

          <!-- 年カレンダー -->
          <div class="year-page" tal:condition="python:param_year and not param_month and not param_day">
          <div tal:define="month_list python:range(4,13) + range(1,4);"
               tal:repeat="month month_list" tal:omit-tag="">
            <div tal:define="tab_year python:test(month<4, year+1, year);
                             english python:translation.month_english(month, format='a').lower();"
                 tal:attributes="class python:'calendar-item calendar-' + english;">
              <div class="year" tal:content="tab_year" />
              <div class="month">
                <a href="#"
                   tal:attributes="href python:base_url + '?year=' + str(tab_year) + '&month=' + str(month);"
                   tal:content="month">1</a>
              </div>
              <table tal:define="msgid python:translation.month_msgid(month);
                                 english python:translation.month_english(month);
                                 month_msg python:msgfactory(msgid, default=english);
                                 event_list python:context.eng_calendar(tab_year, month);">
                <tr class="week_head">
                  <td class="weekday_sun" i18n:translate="weekday_sun_short">Su</td>
                  <td class="weekday_mon" i18n:translate="weekday_mon_short">Mo</td>
                  <td class="weekday_tue" i18n:translate="weekday_tue_short">Tu</td>
                  <td class="weekday_wed" i18n:translate="weekday_wed_short">We</td>
                  <td class="weekday_thu" i18n:translate="weekday_thu_short">Th</td>
                  <td class="weekday_fri" i18n:translate="weekday_fri_short">Fr</td>
                  <td class="weekday_sat" i18n:translate="weekday_sat_short">Sa</td>
                </tr>
                <tr tal:define="first_week python:event_list[0]['week'];
                                week_num python:len(event_list) + first_week;
                                week_num python:test(week_num%7, int(week_num/7)+1, int(week_num/7));"
                    tal:repeat="week python:xrange(week_num)">
                  <tal:item repeat="date python:xrange(week*7-first_week+1, week*7-first_week+8)">
                  <td tal:condition="python:date>0 and date<=len(event_list)"
                      tal:attributes="class python:event_list[date-1]['daily_events'] and 'event' or 'no_event';">
                    <a href="#"
                       tal:omit-tag="python:not event_list[date-1]['daily_events']"
                       tal:attributes="href python:base_url + '?year=' + str(tab_year) + '&month=' + str(month) + '&amp;day=' + str(date);">
                      <span tal:replace="python:str(date)">1</span>
                    </a>
                  </td>
                  <td tal:condition="python:not (date>0 and date<=len(event_list))" />
                  </tal:item>
                </tr>
              </table>
            </div>
            <div class="visualClear"
                 tal:condition="python: month % 3 == 0"><!-- --></div>
          </div>
          </div>
        </div>

    </metal:body>

</metal:main_macro>
</div>
</body>
</html>

画像

デザイン用の各月の画像などを同じレイヤに作成する。

イベントのXML出力

他のサイトとのイベント連携も可能となるよう XML 出力もできるようにしておく。ページテンプレートとしてスキンフォルダに eng_events_xml を追加する。追加したテンプレートの Properties タブより content_type を次のように変更する。

content_type : text/xml

テンプレートは次のように定義する。

<?xml version="1.0" encoding="UTF-8" ?>
<items xmlns:tal="http://xml.zope.org/namespaces/tal"
       xmlns:i18n="http://xml.zope.org/namespaces/i18n"
       xmlns:metal="http://xml.zope.org/namespaces/metal"
       tal:define="year request/year;
                   year python:int(year);
                   month request/month;
                   month python:int(month);
                   end_date python:context.portal_calendar.getNextMonth(month, year) - 1;
                   last_day python:end_date.day();
                   results python:here.queryCatalog({
                       'end' :  { 'query' : DateTime(year, month, 1, 0, 0), 'range' : 'min'},
                       'start' : { 'query' : DateTime(year, month, last_day, 23, 59), 'range' : 'max'},
                       'sort_on' : 'start'});">
<item tal:repeat="result results">
<url tal:content="python:result.getObject().absolute_url()" />
<title tal:content="result/Title" />
<location tal:content="result/location" />
<start tal:content="result/start" />
<end tal:content="result/end" />
</item>
</items>

呼び出すには year と month を指定して次のように行う。これで指定した月のイベント一覧を出力できる。

http://イベントカレンダー用コレクションのURL/eng_events_xml?year=2009&month=4

 

設定

Topicのビューで選択できるものを指定する

フォルダのビューで選択できるものを指定する。上で作成した、eng_calendar_view も設定できるようにする。portal_types/Topic を開き Available view methods に次の行を追加する。

eng_calendar_view

曜日と月名の翻訳を追加する

Plone3では曜日と月の翻訳が定義されていないため、plone.app.locales/plone/app/locales/i18n/plone-ja.po を編集してPlone2.5時の翻訳を追加する。

#. Default: "Sun"
#: datetime abbreviation of a day, format %a
msgid "weekday_sun_abbr"
msgstr "日"

#. Default: "Mon"
#: datetime abbreviation of a day, format %a
msgid "weekday_mon_abbr"
msgstr "月"

#. Default: "Tue"
#: datetime abbreviation of a day, format %a
msgid "weekday_tue_abbr"
msgstr "火"

#. Default: "Wed"
#: datetime abbreviation of a day, format %a
msgid "weekday_wed_abbr"
msgstr "水"

#. Default: "Thu"
#: datetime abbreviation of a day, format %a
msgid "weekday_thu_abbr"
msgstr "木"

#. Default: "Fri"
#: datetime abbreviation of a day, format %a
msgid "weekday_fri_abbr"
msgstr "金"

#. Default: "Sat"
#: datetime abbreviation of a day, format %a
msgid "weekday_sat_abbr"
msgstr "土"

#. Default: "Sunday"
#: datetime name of a day, format %A
msgid "weekday_sun"
msgstr "日曜日"

#. Default: "Monday"
#: datetime name of a day, format %A
msgid "weekday_mon"
msgstr "月曜日"

#. Default: "Tuesday"
#: datetime name of a day, format %A
msgid "weekday_tue"
msgstr "火曜日"

#. Default: "Wednesday"
#: datetime name of a day, format %A
msgid "weekday_wed"
msgstr "水曜日"

#. Default: "Thursday"
#: datetime name of a day, format %A
msgid "weekday_thu"
msgstr "木曜日"

#. Default: "Friday"
#: datetime name of a day, format %A
msgid "weekday_fri"
msgstr "金曜日"

#. Default: "Saturday"
#: datetime name of a day, format %A
msgid "weekday_sat"
msgstr "土曜日"

# Shorthand for "Sunday"
#. Default: "Su"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_sun_short"
msgstr "日"

# Shorthand for "Monday"
#. Default: "Mo"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_mon_short"
msgstr "月"

# Shorthand for "Tuesday"
#. Default: "Tu"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_tue_short"
msgstr "火"

# Shorthand for "Wednesday"
#. Default: "We"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_wed_short"
msgstr "水"

# Shorthand for "Thursday"
#. Default: "Th"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_thu_short"
msgstr "木"

# Shorthand for "Friday"
#. Default: "Fr"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_fri_short"
msgstr "金"

# Shorthand for "Saturday"
#. Default: "Sa"
#: datetime two letter abbreviation of a day used in the portlet_calendar
msgid "weekday_sat_short"
msgstr "土"


#. Default: "January"
#: datetime name of a month, format %B
msgid "month_jan"
msgstr "1月"

#. Default: "February"
#: datetime name of a month, format %B
msgid "month_feb"
msgstr "2月"

#. Default: "March"
#: datetime name of a month, format %B
msgid "month_mar"
msgstr "3月"

#. Default: "April"
#: datetime name of a month, format %B
msgid "month_apr"
msgstr "4月"

#. Default: "May"
#: datetime name of a month, format %B
msgid "month_may"
msgstr "5月"

#. Default: "June"
#: datetime name of a month, format %B
msgid "month_jun"
msgstr "6月"

#. Default: "July"
#: datetime name of a month, format %B
msgid "month_jul"
msgstr "7月"

#. Default: "August"
#: datetime name of a month, format %B
msgid "month_aug"
msgstr "8月"

#. Default: "September"
#: datetime name of a month, format %B
msgid "month_sep"
msgstr "9月"

#. Default: "October"
#: datetime name of a month, format %B
msgid "month_oct"
msgstr "10月"

#. Default: "November"
#: datetime name of a month, format %B
msgid "month_nov"
msgstr "11月"

#. Default: "December"
#: datetime name of a month, format %B
msgid "month_dec"
msgstr "12月"