2010/03/31

Utilizing JavaScript in Plone Without Knowing

This is an abstract from Utilize Available JavaScript in Plone without Knowing JavaScript by Chrissy Wainwright.

使用 Plone 預設操作介面時,有些 script 已經在默默運作,更棒的是,只要粗略了解程式碼運作的原理,不必精通 Javascript 的細節,就可以搭配 portal_skins/plone_ecmascript 裡的 .js 內容,將頁面調整成我們想要的效果。

編輯內容時,想要把內容拆開在不同的 tab 頁面顯示,不必重傳網頁內容,這樣的效果稱為 FormTabbing 技巧。

form_tabbing.js 檔案就是達成上述效果的工具,下列的程式碼示範它的運作方式:

<dl class="enableFormTabbing">
<dt id="fieldsetlegend-unique-id1">button one</dt>
<dt id="fieldsetlegend-unique-id2">button two</dt>
<dd id="fieldset-unique-id1">content one</dd>
<dd id="fieldset-unique-id2">content two</dd>
</dl>

範例中的兩個按鈕,分別由 <dt> 標籤語法所指定,按鈕的 id 要以 fieldsetlegend- 字樣開頭,按鈕所對應的內容,分別由 <dd> 標籤語法所指定,其 id 則要以 fieldset- 字樣開頭。同樣的道理,上述程式碼的原理,也可以用於 <form> 標籤裡:

<form class="enableFormTabbing">
<fieldset id="fieldset-[unique-id]">
<legend id="fieldsetlegend-[same-id-as-above]">Title</legend>
</fieldset>
</form>

除此之外,還有 table_sorter.js 和 collapsiblesections.js 的範例,有興趣就去試吧。

2010/03/26

ZopeSkel local commands

UnifiedInstaller 是目前開發 Plone 的建議起步方式,特別是 Plone 3 UnifiedInstaller 把 buildout 整合後,系統的安裝和擴充都變得更方便了。
不過,最近想用 paster 來建立 archetype 專案,還是讓我遇到 local commands 找不到的問題。雖然應該不是 paster_plugin 的問題,但在 buildout.cfg 調整下列的設定值,同樣能解決我的困擾:
[zopeskel]
recipe = zc.recipe.egg
dependent-scripts = true
eggs =
PasteScript
ZopeSkel
initialization =
import paste.script.command
paste.script.command.system_plugins.append('zopeskel')
假設在 src 目錄裡,先用 paster 建立一個名稱為 myproject.mytype 的 archetype 專案,就可以在專案目錄裡執行 paster --help 看到 addcontent 等的 local command 資訊。

ZPublisher.Conflict ConflictError

My log contains the following message:

INFO ZPublisher.Conflict ConflictError at /VirtualHostBase/http/my.host.org:80/MySite/VirtualHostRoot/_vh_MySite/some-folder/mportal_factory/MyTypes/mytype.2010-03-26.5609762949/@@plone_lock_operations/refresh_lock: database conflict error (oid 0x02 d2e1, class BTrees._IOBTree.IOBucket, serial this txn started with 0x0385090b54cf6f88 2010-03-26 02:51:19.877413, serial currently committed 0x0385090b54cf6f88 2010-03-26 02:51:35.450306) (1 conflicts (0 unresolved) since startup at Fri Mar 26 03:55:41 2010)

It seems similar to the message in http://n2.nabble.com/ZPublisher-Conflict-ConflictError-td339922.html. In my case, a package webcouturier.dropdownmenu is used and 'Depth of dropdown menus' is set as 3, without enabling caching. Since there are more and more items added to the folder, 3 levels of dropdown menus bring us problem. After the level is set to 2, the page response time much improves. Problably the BTrees object is from cataloguing for dropdown menus.

ZServer uncaptured python exception

http://aspn.activestate.com/ASPN/Mail/Message/zope-list/3492748 提到,使用者臨時取消網頁存取動作,例如按了瀏覽器的停止鍵,會產生這類的訊息,一般是無須追究的情況,真想探究 exception 內容的話,要主動去接取它。如果伴隨系統資源吃緊的狀況,可用 'debug spinning zope' 關鍵字來查詢除錯技巧,或是查詢 spider 或 bot 的造訪狀況,必要時採用 iptables -A INPUT -s -j DROP 的激烈手段。

2010/03/13

User SubGroup and Associated Roles

Plone 3.2 版本之前的會員管理介面 prefs_users_overview 執行搜尋時,只能針對 full name 欄位進行比對,不能比對 id 欄位,另外也有 subgroup 與 role 的顯示問題,症狀主要記錄於 #9317#8940。目前已在 changeset 33533 完成修訂,並整理出新的管理介面。

2010/03/08

Fake Eggs ?

This is an abstract from Scrambled eggs by Martin Aspeli.

藉由 egg 機制,我們可以更順暢地進行模組軟體的包裝與散佈,但是,遇到 buildout 想要自動昇級某些模組時,為了滿足相依衝突時,egg 也可能帶來許多痛苦,我們會被一堆版本昇級要求資訊淹沒。

由於 Plone 3.0 到 3.1 搭配的 Zope 並沒有包裝成 egg 檔案,導致 setuptools 無從得知 Zope 3 模組的 egg metadata 資訊。舉例來說,如果你安裝一個相依於 zope.component 的模組,但是 setuptools 並不知道你已經有 zope.component 了,因此會試著下載最新版的 zope.component。由於新版 zope.component 的下載動作會引發其他相依關係,很容易造成永無止境的昇級要求。

為了解決上述問題,plone.recipe.zope2install 這個 recipe 預設會安裝一些 fake egg,它的效果,就像是建立一堆指到 parts/zope2/lib/python/* 的 egg。如此一來,setuptools 就能知道系統裡存在 zope.component、zope.interface 等標準模組,不需要再去下載新版檔案。

常見的情況是,我們只知道需要安裝某個檔案,但不清楚所需的明確版本,因此 fake egg 會指定為 0.0 版本,除非你為特定的 recipe 額外指定它的版本號碼。也就是說,如果有個模組的相依關係是 zope.component >= 3.1,setuptools 仍然會以為系統既有的 zope.component 版本過舊,將嘗試下載新的版本。

那麼,模組的相依資訊被記錄於何處? 它的來源大致有兩類,一是在模組檔案的 setup.py 內容裡,二是從 buildout.cfg 檔案的 eggs 設定值尋找。相依資訊的常見形式,又可分成兩類,第一類的例子是「我需要和 zope.component 一起工作」,只指定模組名稱,而不指定模組版本,第二類的例子是「我需要和 zope.component >= 3.4 版本一起工作」,同時指定模組名稱與版本條件。

有時,在 setup.py 裡指定最小版本號碼是必要的,因為某些版本以上的模組,才提供我們需要的功能。當然,在 setup.py 裡明確指定「我需要和 zope.component == 3.4 版本工作」是合法的設定方式,但通常會造成日後的災難,而指定最大版本號碼的方式,例如「我需要和 zope.component >=3.4, <=3.4.999 版本工作」,通常也是很糟的形式。一般而言,除非有必要,永遠不要在 setup.py 裡指定「==」的版本要求,頂多使用「<=」的版本形式。因為,這類不適當的設定值一旦出錯,除錯工作極度困難。

另一方面,目前 setuptools 的運作方式,是找尋最新版本來下載,如果它先下載了某個模組的新版本,就會順著它的相依關係來下載其他模組,即使某個舊版本提供更合適的相依條件,setuptools 並無從得知,這會導致下列問題:

* setuptools 下載過新版本的模組,和稍後模組的最大版本條件相衝突。幸好,這個問題並不難解決。

* 原本 buildout 運作正常,但是有人在 PyPI 上傳新版模組,造成相依關係更新,接著你又執行 buildout 更新動作,下載了新版模組,引發更多新版模組的下載。運氣好的話,系統會通知版本衝突的訊息,運氣不好的話,表面上 build 動作完成,但執行系統時卻失敗。

2010/03/03

Quote Portlet

想在 Plone 網站加上 quote portlet 嗎? 利用 collective.portlet.quote 輕鬆就能完成,它還有 Quote Folder 專門來放 Quote Type。不過,並不喜歡預設的方框樣版,想要改個樣子,於是動手修改兩個檔案。

修改 randomquote.pt 內容如下:
    <dd class="portletItem odd">
<q tal:content="structure view/get_quote">
Body text
</q>
</dd>
<dd class="QuoteSource">
<span class="portletBottomLeft"></span>
<p tal:condition="not:view/has_link">

<tal:block replace="view/get_source"/>
</p>
<tal:block condition="view/has_link">
<a tal:attributes="href view/get_link">

<tal:block replace="view/get_source"/>
</a>
</tal:block>
<span class="portletBottomRight"></span>
</dd>

新增 ploneCustom.css 內容如下:
.QuoteSource
{
border-color: #8CACBB;
border-width: 1px;
border-style: none solid none;
margin: 0;
text-align: right;
padding: 0.25em 1em;
}
有圖有真相。