Friday, September 14, 2007

Ofbiz Screen

ถ้าใครลองเปิด source code ของ ofbiz ดู
จะเห็นว่า หน้าจอของ ofbiz ส่วนใหญ่ render โดยใช้ screen component

ลองดูตัวอย่าง definition ของ screen สักอัน
<screen name="NewInvoice">
<section>
<actions>
<set field="title" value="New Invoice"/>
<set field="titleProperty" value="PageTitleEditInvoice"/>
<entity-one entity-name="Invoice" value-name="invoice"/>
</actions>
<widgets>
<decorator-screen name="CommonInvoiceDecorator" location="${parameters.mainDecoratorLocation}">
<decorator-section name="body">
<section>
<widgets>
<label style="head1" text="${uiLabelMap.AccountingCreateNewSalesInvoice}"></label>
<include-form name="NewSalesInvoice" location="component://accounting/webapp/accounting/invoice/InvoiceForms.xml"/>
<label style="head1" text="${uiLabelMap.AccountingCreateNewPurchaseInvoice}"/>
<include-form name="NewPurchaseInvoice" location="component://accounting/webapp/accounting/invoice/InvoiceForms.xml"/>
</widgets>
</section>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>


ลองมาดูว่า feature ของ screen นั้นมีอะไรบ้าง
เริ่มที่ child element ของ screen ก่อน กำหนดไว้ว่าต้องเป็น <section> เท่านั้น

<screen>
<section>
...
</section>
</screen>


ภายใน section สามารถมี element ได้ 4 แบบ
<screen>
<section>
<condition>...</condition>
<actions>...</actions>
<widgets>...</widgets>
<fail-widgets>...</fail-widgets>
</section>
</screen>

ตัว condition ก็คือ expression ที่จะถูก evaluate เมื่อ screen เริ่มทำงาน
ถ้าได้ผลลัพท์เป็น true ก็จะ
ทำการเรียกใช้ actions และ render output โดยใช้ block widgets
แต่ถ้าได้ผลลัพท์เป็น false ก็จะ
render ด้วย block fail-widgets แทน

Note: ตัว condition, action, และ fail-widgets ถือว่าเป็น optional element
จะมีหรือไม่มีก็ได้

condition block ส่วนใหญ่จะไว้ใช้ check พวก authorize เช่น
<condition>
<or>
<if-has-permission permission="ORDERMGR" action="_VIEW"/>
</or>
</condition>

ส่วนภายใน action block, มีคำสั่งให้ใช้อีก 9 คำสั่ง
ซึ่งขอยกรายละเอียดไปพูดใน post หน้า

ภายใน widgets หรือ fail-widgets เราสามารถมี element ได้ดังนี้
  • section
    Note: จะเห็นว่าใน widgets ก็สามารถมี section ซ้อนอยู่ข้างในได้อีก
  • container
    container ก็คือ wrapper ที่ไว้จัดกลุ่ม widget
    การทำงานภายในของมัน ก็คือเวลามัน render html มันจะ render
    <div> block คร่อม widget ที่อยู่ข้างในมัน
  • include-screen
    อันนี้ตรงไปตรงมา ก็คือ include screen อื่นๆเข้ามา
  • decorator-screen, decorator-section-include
    อันนี้ถือเป็นหัวใจของการใช้ screen
    ถ้าเราสังเกตดูหน้าจอของ ofbiz เวลาใช้งาน
    จะเห็นว่าเวลาเราเลือก action ต่างๆ หน้าจอส่วนใหญ่จะไม่เปลี่ยนแปลง
    ส่วนที่เปลี่ยน จะเป็นแค่ region เล็กๆเท่านั้น
    ofbiz ก็เลยนำ decorator pattern มาใช้สำหรับ render code ที่ซ้ำๆกัน
    วิธีใช้ก็คือ
    <screen>
    <section>
    <widgets>
    <decorator-screen name="CommonFixedAssetDecorator" location="${parameters.mainDecoratorLocation}">
    <decorator-section name="body">
    ... widget go here.
    </decorator-section>
    </decorator-screen>
    </widgets>
    </section>
    </screen>

    <screen name="CommonFixedAssetDecorator">
    <section>
    <widgets>
    <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}">
    <decorator-section name="body">
    ....
    <decorator-section-include name="body"/>
    </decorator-section>
    </decorator-screen>
    </widgets>
    </section>
    </screen>

    Note: ใน ofbiz เรามักจะเห็น decorator ซ้อนไปซ้อนมาจนน่าปวดหัว
  • label
    render string ธรรมดา
    ซึ่งกรณีที่ render ออก html ก็จะมี ครอบให้ด้วย
  • include-form, include-menu, include-tree, content, sub-content, link, image, iterate-section
    อันนี้เป็นเรื่องใหญ่อีกเรื่อง ที่จะยังไม่พูดถึง
  • platform-specific
    อันนี้พบบ่อยมาก
    วิธีใช้ก็ fix ตายตัว นั่นคือใช้เรียก html-template มาทำงาน
    โดย support เฉพาะ Freemarker เท่านั้น
    <platform-specific>
    <html>
    <html-template location="component://accounting/webapp/accounting/invoice/sendPerEmail.ftl"/>
    </html>
    </platform-specific>

Related link from Roti

No comments: