2013/11/27

Sprint Like Mad

荷蘭 Arnhem 是 Four Digits 公司的所在地,它們舉辦了十一月 Plone Sprint,為期五天,共 35 人參與。

活動裡,有個 Don't Break The Build 規則,會場的大螢幕持續顯示 CI server 的狀態,如果爛掉了,會把爐主的名字秀出來,然後爐主要請其他人吃蛋糕。一週的 sprint 後,多數人都增加不少肥肉。

活動結束時,還有 Party 和 Award。決定 Sprint Award 的方法,是利用分貝計,看哪個隊伍的歡呼聲最大。

技術上的成果包括: New Theme for Plone 5, New Way to Work with JavaScript: Mockup (widgets), Remove Selected Portal Tools from Plone, Make main_template More HTML5 Friendly,更多記錄在 Day 1, Day 2, Day 3, Day 4, Wrapup

2013/11/13

Plone Header I18N

On creating a new Plone instance, you will be asked to set its title and description. If localized strings are used for the title field, they are literally displayed in <head><title>Title Here</title></head>. We can not easily switch the the title strings based on a chosen language.

Maybe plone.app.multilingual will take care of this issue, as a whole multilingual story. Anyway, I try to solve this issue by manipulating viewlets.

My theme is based on Sunburst, that uses main_template.pt as the starting point. plone.htmlhead provider (viewlet manager) is where we need to hack into:

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

See plone.app.layout/viewlets/configure.zcml and we will find the related viewlet manager and viewlets:

<browser:viewletManager
  name="plone.htmlhead"
  provides=".interfaces.IHtmlHead"
  permission="zope2.View" ...>

<browser:viewlet
  name="plone.htmlhead.title"
  manager=".interfaces.IHtmlHead"
  class=".common.TitleViewlet" ...>

Now we know TitleViewlet in plone.app.layout/viewlets/common.py is the target:

class TitleViewlet(ViewletBase):
  index = ViewPageTemplateFile('title.pt')

  @property
  @memoize
  def page_title(self):
    '''
    Get the page title.
    '''

Each page has its site_title set as page_titleportal_title. With a little help from my friends -- zope.i18n.translate:

from zope.i18n import translate

def update(self):
  ...
  self.site_title = u"%s &mdash; %s" % (self.page_title,
    translate('portal_title',
              domain='my.theme',
              context=self.request,
              default='I18N Site'))

Finally we need my.theme.po in the locales folder:

#: Default: I18N Site
msgid "portal_title"
msgstr "中文名稱"

2013/11/09

Event Listing View

event_listing 是 plone.app.events 模組裡定義的 Browser Page,可以被指定成為 Plone Site 或 Folder 的 view method 選項,提供豐富的顯示方式。

event_listing.pt 有定義 mode 變數,預設值是 'future':

tal:define="mode request/mode|string:future;"

如果 @@event_listing 沒有指定 mode 變數值,它會再檢查 _date 變數,最後決定 mode 預設值是 'date' 或 'future'。

if self.mode is None:
    self.mode = self._date and 'day' or 'future'

點選 Past 頁籤時,它會指定 'past' 給 mode 變數,此時 header_string() 會回傳 main_msgid 的翻譯值,其他情況下,還可能搭配 sub_msgid 變數值。

頁籤的連結網址,也配合變數值來產生,例如 mode_past_url 會把 'past' 傳給 _date_nav_url():

def _date_nav_url(self, mode, datestr=''):
    return '%s?mode=%s%s' % (
        self.request.getURL(),
        mode,
        datestr and '&date=%s' % datestr or ''
    )

event_listing.pt 經由 view/mode_past_url 來指派網址值:

browser/event_listing.pt
<a class="mode_past" href=""
  tal:attributes="href view/mode_past_url"
  i18n:translate="mode_past_link">Past</a>

2013/11/05

Transmogrifier Revisited

This is detailed sample instruction to Transmogrifier in Action on Plone 4.3.2.

$ cd src
$ ../bin/zopeskel plone crgis.transmogrifier

plone: A project for Plone add-ons

This creates a Plone project (to create a Plone *site*, you probably
want to use the one of the templates for a buildout).

To create a Plone project with a name like 'plone.app.myproject'
(2 dots, a 'nested namespace'), use the 'plone_app' template.


If at any point, you need additional help for a question, you can enter
'?' and press RETURN.

Expert Mode? (What question mode would you like? (easy/expert/all)?) ['easy']:
Version (Version number for project) ['1.0']: 0.1
Description (One-line description of the project) ['']: CRGIS Transmogrifier Package
Register Profile (Should this package register a GS Profile) [False]: True
Creating directory ./crgis.transmogrifier
Replace 0 bytes with 119 bytes (0/0 lines changed; 5 lines added)
Replace 918 bytes with 1074 bytes (0/32 lines changed; 6 lines added)
------------------------------------------------------------------------------
The project you just created has local commands. These can be used from within
the product.

usage: paster COMMAND

Commands:
  addcontent  Adds plone content types to your project

For more information: paster help COMMAND
------------------------------------------------------------------------------

Update configure.zcml as follows:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:five="http://namespaces.zope.org/five"
  xmlns:i18n="http://namespaces.zope.org/i18n"
  xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
  xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier"
  i18n_domain="crgis.transmogrifier">

  <five:registerPackage package="." initialize=".initialize" />

  <genericsetup:registerProfile
    name="default"
    title="crgis.transmogrifier"
    directory="profiles/default"
    description="CRGIS Transmogrifier Package Extension Profile"
    provides="Products.GenericSetup.interfaces.EXTENSION"
    />

  <include package="collective.transmogrifier" />
  <include package="collective.transmogrifier" file="meta.zcml" />
  <transmogrifier:registerConfig
    name="crgis.importer.temple"
    title="CRGIS Importer for Temple Type"
    description="Transmogrifier Pipeline Config to Import Contents."
    configuration="import-temple.cfg"
    />

Update import-temple.cfg then:

[transmogrifier]
pipeline =
    csvsource
    sqlsource
    type-inserter
    path-inserter
    folders
    constructor
    schema-updater
    state-inserter
    workflow-updater
    reindex-object

[csvsource]
blueprint = collective.transmogrifier.sections.csvsource
filename = crgis.transmogrifier:temple-data.csv

[sqlsource]
blueprint = transmogrify.sqlalchemy
dsn = postgresql://USERNAME:PASSWORD@localhost:5432/DB_NAME
query = SELECT id, title, description FROM TB_NAME

[type-inserter]
blueprint = collective.transmogrifier.sections.inserter
key = string:_type
value = string:Temple

[path-inserter]
blueprint = collective.transmogrifier.sections.inserter
key = string:_path
value = string:/myfolder/${item/id}

[folders]
blueprint = collective.transmogrifier.sections.folders

[constructor]
blueprint = collective.transmogrifier.sections.constructor

[schema-updater]
blueprint = plone.app.transmogrifier.atschemaupdater

[state-inserter]
blueprint = collective.transmogrifier.sections.inserter
key = string:_transitions
value = string:publish

[workflow-updater]
blueprint = plone.app.transmogrifier.workflowupdater

[reindex-object]
blueprint = plone.app.transmogrifier.reindexobject

Note that csvsource section is for CSV source, and sqlsource section is for SQL source.

Add a file crgis/transmogrifier/profiles/default/transmogrifier.txt with these:

# this file contains transmogrifier profile names to run
# on GenericSetup transmogrifier's step
crgis.importer.temple

Update setup.py to include SQLAlchemy and psycopg2 dependency.

Finally, edit buildout.cfg:

eggs =
    plone.app.transmogrifier
    collective.transmogrifier
    transmogrify.sqlalchemy
    crgis.transmogrifier

zcml =
    plone.app.transmogrifier
    collective.transmogrifier
    transmogrify.sqlalchemy

2013/11/03

Plone5 Is On Its Way

Plone 5 正由核心團隊努力開發,目前看來已達到堪用地步,或許明年初之際,就能正式發佈。

最大的改變,是 Dexterity 成為預設的 Content Type Framework,長期挑大樑的 Archetypes 成為選項模組。這個改變屬於底層調整,對於直接使用 Plone 5 的新專案而言,操作上仍和 Plone 4 差不多。

另一個大改變,是 AJAX 架構導入 mockup 專案,它讓 Plone 與 JavaScript 模組更容易整合和測試。

像 Diazo 技術在 Plone 5 仍在努力站穩腳步,大的方向上,是期待改版的結果,能協助 JavaScript Programmer 和 Theme Designer 更容易在 Plone 專案裡工作。

範例影片: Widget DemoFolder Content Management Demo

測試 Plone 5 的過程,把看到的改版細節資訊記錄下來。舊版 plone.app.imaging 的 imaging_properties 設定值,無法在 Plone 5 出現,因為它跟 Archetypes 相依,必須進行調整,它在 control panel 的 icon 也需要調整

update on testing: https://github.com/plone/Products.CMFPlone/issues/78

$ bin/test -s Products.CMFPlone
Removing stale bytecode file /home/marr/plone5dev/src/Products.CMFPlone/Products/CMFPlone/CalendarTool.pyc
...
Running Products.CMFPlone.testing.CMFPloneLayer:Functional tests:
  Set up plone.testing.zca.LayerCleanup in 0.000 seconds.
  ...
  Running:

  Ran 28 tests with 0 failures and 0 errors in 32.189 seconds.
Running plone.app.testing.bbb.PloneTestCase:Functional tests:
  Tear down Products.CMFPlone.testing.CMFPloneLayer:Functional in 0.000 seconds.
  ...
  Set up plone.app.testing.bbb.PloneTestCaseFixture in 5.792 seconds.
  ...
  Ran 70 tests with 2 failures and 0 errors in 0.624 seconds.
Tearing down left over layers:
  Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Total: 1061 tests, 4 failures, 0 errors in 9 minutes 22.008 seconds.

跟 Archetypes 有關的模組資訊:

eggs/archetypes.schemaextender
src/Products.Archetypes
src/Products.ATContentTypes
src/plone.formwidget.recurrence