二月 4, 2012

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Products.AutocompleteWidget Sample

Products.AutocompleWidget 有支援 Plone 4.x,範例程式碼並不多,因此特別記錄找到的:

測試結果,使用 multiValued=True 後,編輯介面才看得到變化。

"""Definition of the Wiki Doc content type
"""

from zope.interface import implements, directlyProvides

from Products.Archetypes import atapi
from Products.Archetypes.public import LinesField
from Products.Archetypes.public import DisplayList
from Products.ATContentTypes.content import base
from Products.ATContentTypes.content import schemata
from Products.AutocompleteWidget.AutocompleteWidget import AutocompleteWidget
from Products.CMFCore.utils import getToolByName


from tlc.kbase import kbaseMessageFactory as _
from tlc.kbase.interfaces import IWikiDoc
from tlc.kbase.config import PROJECTNAME

WikiDocSchema = schemata.ATContentTypeSchema.copy() + atapi.Schema((


LinesField('tags',
searchable=1,
required=0,
mutator='setTagSubject',
accessor='getTagSubject',
edit_accessor='getTagSubject',
vocabulary='getSubjectVocab',
widget=AutocompleteWidget(label='Tags'),
enforceVocabulary=0,
),

))

# Set storage on fields copied from ATContentTypeSchema, making sure
# they work well with the python bridge properties.

WikiDocSchema['title'].storage = atapi.AnnotationStorage()
WikiDocSchema['description'].storage = atapi.AnnotationStorage()

schemata.finalizeATCTSchema(WikiDocSchema, moveDiscussion=False)

class WikiDoc(base.ATCTContent):
"""Description of the Example Type"""
implements(IWikiDoc)

meta_type = "Wiki Doc"
schema = WikiDocSchema

title = atapi.ATFieldProperty('title')
description = atapi.ATFieldProperty('description')

def setTagSubject(self, value):
"""Set tag widget contents to subject of object"""
self.getField('subject').set(self, value)

def getTagSubject(self):
"""Set tag widget contents to subject of object"""
return self.Subject()

def getSubjectVocab(self):
"""Get subject (keywords) vocabulary"""
catalog = getToolByName(self, 'portal_catalog')
return catalog.uniqueValuesFor('Subject')

atapi.registerType(WikiDoc, PROJECTNAME)

十二月 29, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Files to Edit for Adding Archetypes Type

除了用 zopeskel 來建立 Content Type 的方法,手動編輯檔案的話,下列是相關檔案的順序列表:

interfaces/__init__.py
interfaces/mytype.py
content/configure.zcml
content/mytype.py
profiles/default/factorytool.xml
profiles/default/types.xml
profiles/default/types/mytype.xml
config.py
browser/configure.zcml
browser/mytype.py
browser/templates/mytype.pt
locales/

十二月 27, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» typesUseViewActionInListings in Plone PropertiesTool

In my archetypes-based project, I create a folderish type Book to contain Chapter type. One of the last steps is to add Chapter type in typesUseViewActionInListings field.

For GenericSetup, it is in profiles/default/propertiestool.xml:

<property name="typesUseViewActionInListings" type="lines">
<element value="Image"/>
<element value="File"/>
<element value="Chapter"/>
</property>

Note that if Book added to that field, it will be bothering when you browse Book items in Contents tab.

十二月 19, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Collective TinyMCE Templates

collective.tinymcetemplates is a TinyMCE Plugin for templates and snippets. It works with Plone 4.1.3. You can see a "Insert predefined template content" icon added:

» Transmogrifier Export in Action

transmogrifier 可以匯入或匯出 Plone 網站的內容,之前的經驗以匯入 CSV 或 PostgreSQL 資料為主,現在完成匯出到 PostgreSQL 的實作。

以 develop.cfg 為例,要修改的內容如下:

eggs +=
psycopg2
SQLAlchemy == 0.6.5
zope.sqlalchemy
plone.app.transmogrifier

客製 myproj.transmogrifier 的內容摘要如下:

myproj.transmogrifier/configure.zcml

<transmogrifier:registerConfig
name="myproj.transmogrifier.exportContent"
title="MyProject Export Content"
description="Transmogrifier Pipeline config to export contents."
configuration="confs/export.cfg"
/>

<!-- register our blueprints -->
<utility
component=".contentexport.ContentExporterSection"
name="myproj.transmogrifier.contentexporter"
/>

myproj.transmogrifier/browser/configure.zcml

<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:zcml="http://namespaces.zope.org/zcml">

<browser:page
for="*"
class=".contentexport.ContentExport"
name="content-export"
permission="cmf.ManagePortal"
/>
<configure>

myproj.transmogrifier/browser/contentexport.py

class ContentExport(BrowserView):

def __call__(self):
transmogrifier = ITransmogrifier(self.context)
transmogrifier('myproj.transmogrifier.exportContent')
self.request.response.write('exported')

myproj.transmogrifier/confs/export.cfg

[transmogrifier]
pipeline =
contentexport

[contentexport]
blueprint = myproj.transmogrifier.contentexporter
dsn = postgresql://myuser:mysecret@localhost:5432/mydb
portal-types = News Item, Event
review-states = published

另外,還有 myproj.transmogrifier/models.py 和 myproj.transmogrifier/contentexport.py 兩個主檔,分別負責資料庫連線和匯出工作。

十二月 18, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Search Portlet for Current Section

By default, Plone provides a searchbox viewlet and a search portlet. With the viewlet, you can decide whether to search only within the current section. However, the porlet does not apply this behavior. My requirement could be illustrated by this screenshot:

Here are the files to be modified:

$ diff plone/app/portlets/portlets/search.py
55a56,61
> def folder_path(self):
> context_state = getMultiAdapter((self.context, self.request),
> name=u'plone_context_state')
> folder = context_state.folder()
> return '/'.join(folder.getPhysicalPath())
>

$ diff plone/app/portlets/portlets/search.pt
29a30,44
>
> <div class="searchSection">
> <input id="searchbox_currentfolder_only"
> class="noborder"
> type="hidden"
> name="path"
> tal:attributes="value view/folder_path"
> />
> <label for="searchbox_currentfolder_only"
> i18n:translate="label_searchbox_currentfolder_only"
> style="cursor: pointer">
> only in current section
> </label>
> </div>
>

十二月 16, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Table View in Contents Tab

Here is the default view for Plone.

I want Published column instead of Modified column. By 'grep -r listing-table' I find the target file is at plone.app.content/browser/table.pt. Related python files are batching.py, container.py and browser/tavleview.py. My naive guess of changing keyword modified to effective, does not work, showing LocationError.

» Display Logos Based on Paths

Here is a customization in plone.app.layout/viewlets/common.py that can display customized logos based on tab paths.

class LogoViewlet(ViewletBase):
index = ViewPageTemplateFile('logo.pt')

def update(self):
super(LogoViewlet, self).update()

portal = self.portal_state.portal()
bprops = portal.restrictedTraverse('base_properties', None)
if bprops is not None:
logoName = bprops.logoName
else:
logoName = 'logo.jpg'
plone_url = getToolByName(self.context, 'portal_url')()
plone_url_len = len(plone_url)
request = self.request
url = request['URL']
path = url[plone_url_len:]
if path.startswith('/news'):
logoName = 'logo-news.png'
if path.startswith('/events'):
logoName = 'logo-events.png'

To illustrate how the path variable works, add a Python Script in ZMI and use the following sample code:

from Products.CMFCore.utils import getToolByName

plone_url = getToolByName(context, 'portal_url')()
print "plone_url = %s\n" % (plone_url),
plone_url_len = len(plone_url)
request = context.REQUEST
url = request['URL']
path = url[plone_url_len:]
print "url = %s, path = %s" % (url, path)
return printed

十二月 15, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» portal_tab globalnav customization

portal_tab, or globalnav, or global_section in Plone, provides clickable links. Let's say, we want a tab to open in new browser window when clicked. The trick is in plone.app.layout/viewlets/sections.pt.

<ul id="portal-globalnav"
tal:define="selected_tab python:view.selected_portal_tab"
><tal:tabs tal:repeat="tab portal_tabs"
><li tal:define="tid tab/id;
turl tab/url"
tal:attributes="id string:portaltab-${tid};
class python:selected_tab==tid and 'selected' or 'plain'"
><a href=""
tal:content="tab/name"
tal:attributes="href tab/url;
title tab/description|nothing;
target python: (turl.endswith('/my-url') and '_blank' or '')">
Tab Name
</a></li></tal:tabs></ul>

十二月 7, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Localization with i18ndude

以 develop.cfg 為例,先在 parts 裡加一行 i18ndude,再加一整段的 [i18ndude] 內容:

parts =
...
i18ndude

[i18ndude]
unzip = true
recipe = zc.recipe.egg
eggs = i18ndude

以 my.example 模組專案為例,處理 .po 檔案的步驟如下:

$ cd src/my.example/my/example
$ vi configure.zcml
<configure
xmlns:i18n="http://namespaces.zope.org/i18n"

<i18n:registerTranslations directory="locales" />

$ mkdir -p locales/zh_TW/LC_MESSAGES
$ i18ndude rebuild-pot --pot locales/my.example.pot --create my.example .
$ touch locales/zh_TW/LC_MESSAGES/my.example.po
$ i18ndude sync --pot locales/my.example.pot locales/zh_TW/LC_MESSAGES/my.example.po
$ msgfmt -o locales/zh_TW/LC_MESSAGES/my.example.mo locales/zh_TW/LC_MESSAGES/my.example.po

如果有手動增加的 po 內容,通常是寫在 manual.pot 裡,再用下列指令併進 pot 檔案裡。

$ i18ndude rebuild-pot --pot locales/my.example.pot --create my.example --merge manual.pot .

十二月 6, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Creating Windows Buildout Project

試著在 Windows 建立 Plone 4.1.2 的 Buildout 專案環境,事先要安裝 Python 2.6.7、PyWin32PIL 1.1.6easy_installSubversionGit。再下載安裝 zopeskel:

C:\> easy_install zopeskel

接著,可以用 zopeskel 來建立 Buildout 專案,範例指令如下:

C:\> mkdir Plone
C:\> cd Plone
C:\Plone> zopeskel basic_buildout

basic_buildout: A basic buildout skeleton
This creates a basic skeleton for a buildout.
Enter project name: myproj

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']:

如果遇到下列訊息,可以予以略過不理會:

UserWarning:
You don't have the C version of NameMapper installed!
I'm disabling Cheetah's useStackFrames option as it is painfully slow
with the Python version of NameMapper.
You should get a copy of Cheetah with the compiled C version of NameMapper.
You don't have the C version of NameMapper installed!

剛建立的 myproj 專案目錄裡,只有 bootstrap.py 和 buildout.cfg 兩個檔案,執行 python bootstrap.py 之後,會建立必要的目錄架構,特別是 bin 目錄裡會建立 buildout 工具程式,額外的撇步是指定 zc.buildout 版本是 1.4.4,不然預設裝的 1.5.2 版本會造成衝突,範例訊息如下:

C:\Plone\myproj> python bootstrap.py -v 1.4.4
Downloading http://pypi.python.org/packages/2.6/s/setuptools/setup
tools-0.6c11-py2.6.egg
Creating directory 'C:\\Plone\\myproj\\bin'.
Creating directory 'C:\\Plone\\myproj\\parts'.
Creating directory 'C:\\Plone\\myproj\\eggs'.
Creating directory 'C:\\Plone\\myproj\\develop-eggs'.
Getting distribution for 'setuptools'.
Got setuptools 0.6c12dev-r88846.
Generated script 'C:\\Plone\\myproj\\bin\\buildout'.

預設的 buildout.cfg 檔案內容如下:

[buildout]
parts =
templer

[templer]
recipe = zc.recipe.egg
eggs =
PasteScript
templer.core

不過,我並沒使用這個 buildout.cfg 內容,而是直接複製 Linux 環境上安裝的 *.cfg 檔案,修改 base.cfg 和 lxml_static.cfg 的 eggs-directory 和 download-cache 配合 Windows 環境的目錄,再執行 buildout:

C:\Plone\myproj> bin\buildout -c develop.cfg
mr.developer: Creating missing sources dir C:\Plone\myproj\src.
Getting distribution for 'zc.recipe.egg==1.2.2'.
Got zc.recipe.egg 1.2.2.
Getting distribution for 'plone.recipe.zope2instance==4.1.9'.
Got plone.recipe.zope2instance 4.1.9.
Getting distribution for 'Zope2==2.13.10'.
Installing Zope2 2.13.10
Caused installation of a distribution:
zope2 2.13.10
with a different project name.
Got zope2 2.13.10.
Getting distribution for 'mailinglogger==3.3.3'.
Got mailinglogger 3.3.3.
Getting distribution for 'nt-svcutils==2.13.0'.
Got nt-svcutils 2.13.0.
Getting distribution for 'Products.StandardCacheManagers==2.13.0'.
Installing Products.StandardCacheManagers 2.13.0
Caused installation of a distribution:
products.standardcachemanagers 2.13.0
with a different project name.
Got products.standardcachemanagers 2.13.0.
Getting distribution for 'Products.PythonScripts==2.13.0'.
...

安裝 Pillow 時,需要安裝 Visual Studio 2008 Express,據說 2008 之外的版本並不行:

error: Setup script exited with error: Unable to find vcvarsall.bat
An error occured when trying to install Pillow 1.7.2. Look above this message fo
r any errors that were output by easy_install.
While:
Installing instance.
Getting distribution for 'Pillow==1.7.2'.
Error: Couldn't install: Pillow 1.7.2

編譯 lxml 如果遇到錯誤,要補足需要的檔案,以 Plone 4.1.3 為例,要下載 lxml 2.3.2 的原始碼。如果沒成功的話,還可以試試直接安裝較低的 lxml 版本

十二月 2, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» File-explorer like Document Management Tool

collective.edm.listing provides a custom view for folder. It works with Plone Quick Upload to upload new files.

十一月 26, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» POSKeyError: 'No blob file'

執行 Plone migration 時,遇到 POSKeyError 錯誤,發現某個目錄裡的 File 內容出了問題,刪除這些 File 之後,就可以順利從 Plone 4.0.5 昇級到 4.1.2。

十一月 23, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Content Not Existing?

遇到 Plone instance 透過 http://mysite.com/news-events 之類的網址,出現「網頁並不存在」的訊息,透過 http://mysite.com/news-events/folder_contents 網址是可以看到內容,最後發現用 http://mysite.com/news-events/selectViewTemplate?templateId=folder_listing 之類的方式,就能解決問題。發生原因是之前選用了 lead image 擴充模組的顯示方式,當這個顯示方式不存在時,就會造成網頁無法正常顯示的問題。

十一月 19, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Content Type Extension

SchemaExtender 可以動態調整 Archetypes 型別定義值,下列是一個 extender.py 範例:

from zope.component import adapts
from zope.interface import implements

from archetypes.schemaextender.interfaces import ISchemaExtender
from archetypes.schemaextender.field import ExtensionField
from plone.app.blob.field import BlobField

from Products.Archetypes import atapi

from example.blobattype.interfaces import IExampleATType
from example.blobattype import blobattypeMessageFactory as _


class ExtensionBlobField(ExtensionField, BlobField):
""" derivative of blobfield for extending schemas """


class ExampleATTypeExtender(object):
adapts(IExampleATType)
implements(ISchemaExtender)

fields = [
ExtensionBlobField('afile',
widget=atapi.FileWidget(
label=_(u"A file"),
description=_(u"Some file"),
),
required=True,
validators=('isNonEmptyFile'),
),

ExtensionBlobField('secondfile',
widget=atapi.FileWidget(
label=_(u"Some other file"),
description=_(u"Some other file"),
),
required=True,
validators=('isNonEmptyFile'),
),
]

def __init__(self, context):
self.context = context

def getFields(self):
return self.fields

十一月 17, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» ATBTreeFolder vs ATFolder

最近把一個 Plone 網站從 3.3.5 昇級到 4.0.7,在 ZMI 裡看得到 ATBTreeFolder 和 ATFolder 兩種目錄型別,ATBTreeFolder 就是所謂的 Large Folder,在 Plone 3 之前的時代,用它來儲存大量的內容項目,到 Plone 4 之後,目錄型別被統合了

ATBTreeFolder 在 ZMI 裡提供 Security 設定頁籤,可以指定 Local Roles,不過 Plone 4 裡的 ATFolder 並沒有這樣的設定介面,必須搭配 plone.app.workflow 編輯 sharing.xml 來擴充權限設定介面

十一月 8, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» CMF Action Condition

使用 Products.Carousel 時,會新增一個 Carousel tab,如果想在特定的目錄裡才出現它,可以在 ZMI portal_actions/object/carousel 的 Condition (Expression) 欄位輸入下列表示式:

python: (context.id in ['carousel']) and plone_context_state.is_folderish()

十月 17, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Search Events and News via Calendar Portlet

Plone 的月曆方框預設是搭配 Event 來顯示,如果某一天是在 Event 發生的期間,就可以在月曆上點選來顯示,它會先利用類似 search?review_state=published&start.query;:record:list:date... 網址格式來搜尋,如果想要增加其他內容型別到月曆方框,例如新聞的話,就要到 ZMI 的 portal_calendar 新增型別,並為型別新增 start 和 end 屬性值。

十月 15, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» RelStorage Installation

RelStorage 是 ZODB 的後端儲存工具,能夠將 pickle 資料存到關聯式資料庫,也就是說,經由 RelStorage 和 ZODB 的合作,Plone 裡的內容可以直接轉存到 MySQL、PostgreSQL 之類的資料庫裡,讓資料庫的類型選擇和轉換更具彈性。

經過原作者 Shane Hathaway 不斷的改進,安裝 RelStorage 變得很簡單,以 Ubuntu 和 PostgreSQL 為搭配範例,先要建立適當的帳號和資料庫:

$ sudo su - postgres
$ createuser --pwprompt zodbuser
$ createdb -O zodbuser zodb

編輯 /etc/postgresql/8.4/main/pg_hba.conf 存取控制規則,範例如下:

local  zodb  zodbuser  md5

接著可以修改 develop.cfg 的 eggs 設定區段:

eggs +=
psycopg2
RelStorage

修改 base.cfg 的 instance 設定區段,其中 blob-dir 參數指定一個目錄名稱,就是用來儲存 ZODB 的 BLOB 檔案:

rel-storage =
type postgresql
dbname zodb
host localhost
user zodbuser
password mypass
blob-dir var/blobs

執行 buildout 生效並啟動系統後,可以查看到資料庫的表單內容:

public | blob_chunk        | table    | zodbuser
public | commit_lock | table | zodbuser
public | current_object | table | zodbuser
public | object_ref | table | zodbuser
public | object_refs_added | table | zodbuser
public | object_state | table | zodbuser
public | pack_object | table | zodbuser
public | pack_state | table | zodbuser
public | pack_state_tid | table | zodbuser
public | transaction | table | zodbuser
public | zoid_seq | sequence | zodbuser

object_state 表單用來記錄 Page、Folder 等的內容,它的欄位包括:

zoid, tid, prev_tid, md5, state_size, state
其中 state 欄位記錄的就是內容項目的資料值。

十月 14, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» EEA Faceted Navigation Installation

EEA Faceted Navigation 已經正式支援 Plone 4.x 版本,測試成功的安裝方式是,先到 zinstance/src 目錄下載程式碼:

$ cd ~/Plone/zinstance/src
$ svn co http://svn.plone.org/svn/collective/eea.facetednavigation/trunk eea.facetednavigation
$ svn co http://svn.plone.org/svn/collective/eea.jquery/trunk eea.jquery
$ svn co http://svn.plone.org/svn/collective/eea.faceted.vocabularies/trunk eea.faceted.vocabularies

編輯 develop.cfg 內容,下列是範例:

[sources]
eea.facetednavigation = fs eea.facetednavigation
eea.jquery = fs eea.jquery
eea.faceted.vocabularies = fs eea.faceted.vocabularies

[buildout]
eggs +=
eea.facetednavigation

zcml +=
eea.facetednavigation-meta
eea.facetednavigation-overrides
eea.facetednavigation

執行 buildout 生效:

$ cd ~/Plone/zinstance
$ bin/buildout -c develop.cfg

啟用模組後,在目錄的 Action 下拉選單,可以看到 Enable faceted navigation 選項,生效後可以再到 Faceted settings 和 Faceted criteria 設定細項。

A Feedjack powered Planet
A Django site.