二月 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)

一月 11, 2012

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Map Should Be Art Work

黃清琦老師的演講裡,他提到「地圖應該可以包含藝術美感的元素,而不只是客觀數據的呈現,有時候必須加入製圖人的主觀美學意見」。舉的例子是,從 GIS 精準的角度,標示的點可能出現在不符規範的位置,例如某個城市被標在河湖裡,此時適度地移標是必要的。臺灣輿圖暨解說圖研究的完成,是以台灣地形圖為基礎來整合舊的史地資料,必須假設長期以來地形未變,如果有局部的資料顯示地形隨時間曾改變,則需要修正。

十二月 29, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» KeyError: 'constrainTypesMode'

Here is an excerpt of error I run into:

URL: plone/app/layout/viewlets/contentactions.pt
Line 32, Column 8
Expression: <StringExpr u'plone.contentmenu'>
...
URL: plone/app/contentmenu/contentmenu.pt
Line 1, Column 0
Expression: <PathExpr standard:u'view/menu'>
...
KeyError: 'constrainTypesMode'

It turns out from my typo in content/mytype.py, by the time when I hesitate whether if using a folderish type:

-ArticleSchema = folder.ATContentTypeSchema.copy()
+ArticleSchema = folder.ATFolderSchema.copy()

» 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.

十一月 30, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Workteam with oDesk

感謝 pofeng 的安排,有機會到 CloudTW 聚會分享 oDesk 的使用經驗。

簡報檔: http://www.slideshare.net/marr/workteam-with-odesk

討論過程中,有人回應「這是個讓 developer 找 developer 的服務」,沒錯,所以適合在技術人員聚會裡介紹 oDesk 服務,用它來累積專案管理的經驗,oDesk 試著促成一個良性循環,讓雇主和工程師都願意重視評價結果,彼此長期建立良好名聲。

自己的使用經驗,只以 employer 身份發包 Plone web development,值得找機會以 developer 角色登入,了解專業技能認證的流程。

十一月 29, 2011

marr's weblog
marrtw
marr weblog is about »

tag cloud

» Joyent Cloud Computing

CloudTW 有段 SmartOS 的討論,於是查了相關資訊。Joyent 成立於 2004 年,業務內容與日俱進,目前已發展為 cloud computing software stack 提供者,據說公司接收了 OpenSolarisIllumos 的開發人員,併購 LayerBoom 的案例,也能跟台灣教改挫敗扯上關係,總之,這些都算是藉由 cloud computing 時代造英雄的例子。

網路上找到的既有資料,都顯示 Joyent 是家強調技術本位的公司,看了 Community Manager 也就是技術公關,心想,台灣何時會有這種角色?

十一月 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 來擴充權限設定介面

A Feedjack powered Planet
A Django site.