1

私は現在、Twitter Bootstrap CSS フレームワークを使用するためのヘルパー メソッドを多数備えた独自の Component ベース クラスを作成しています (そして、その周りのボイラープレート コードをすべて回避しています)。これらは、既存のフォーム ヘルパー ( などhtml div ...) と非常によく似た方法で使用できます。

たとえば、水平テキスト フィールド (水平形式) の場合は次のようになります。

horizontalTextField: aLabel
| field |

field := WATextInputTag new
    class: 'input-xlarge';
    yourself.

self html div
    class: 'control-group';
    with: [
        self html label
            class: 'control-label';
            with: aLabel.
        self html div
            class: 'controls';
            with: [self html brush: field].
    ].

^ field.

コンポーネントをレンダリングするときに、次のように使用することを目指しています。

(self horizontalTextField: 'Titel')
    on: #title of: self article;
    id: 'title'.

したがって、目的は、実際のテキスト フィールドをいくつかの div でラップすることですが、上記のように、ヘルパー関数の外部で (通常のタグ ヘルパー アクセサーを使用して) このラップされた要素を変更できるようにすることです。

ただし、要素を返す前にメソッドがラッピング div をシリアル化 (別名レンダリング) するため、これは機能しませwith:ん。要素は編集できなくなります。

考えられる解決策:

  1. フィールドのレンダリングに使用される WACanvasTag サブクラスを実際に拡張し、コンポーネント クラスのカスタム ヘルパーでそれらの新しいサブクラスのインスタンスを作成します。喜んでレンダリング コードを上書きするだけです。これはおそらく最もオブジェクト指向の方法ですが、特に、これらのサブクラスのすべての要素の前後に独自の HTML を挿入するために非常に多くのコードを繰り返さなければならないため、非常に困難です (ラップしようとしている Tag クラスから継承する必要があります)。
  2. ヘルパーを呼び出すときは、次のようにしself horizontalTextField: 'Titel' with: [:field | id: 'title']ます。ブロックは、ヘルパー メソッドで実際のテキスト フィールドをレンダリングする前に適用されます。これは非常に柔軟ですが、あまりきれいではありません (構文的に)。
  3. ヘルパー関数でラッピング HTML (この質問に関連) をハードコーディングします。このように:self html html: '<label class="control-label">など。ある意味でかなりのハックであり、あまりオブジェクト指向ではありません。

コメント? アイデア?より良い提案?

4

2 に答える 2

2

お気づきのように、HTML キャンバスはすぐに HTML を発行するため、上記のコードは機能しません。ブラシはどこにも保管しないでください。有効期間は非常に短いです。同じことが HTML キャンバスにも当てはまります。これは非常にまれであり、バグの原因となる可能性があります。

Seaside でこれを行う一般的な方法は、ヘルパー メソッドを作成することです。

renderHorizontalLabel: aLabelRenderer andField: aFieldRenderer on: html
   html div
       class: 'control-group';
       with: [
           html label
               class: 'control-label';
               with: aLabelRenderable.
           html div
               class: 'controls';
               with: aFieldRenderer ]

上記のコードの良いところは、 と の両方aLabelRendereraFieldRenderer任意のオブジェクト#renderOn:(String、Number、Block、WAPresenter、WAComponent など) を実装できることです。

renderContentOn: html
   self
       renderHorizontalLabel: 'Comment'
       andField: [
           html textField
               value: comment;
               callback: [ :value | comment := value ] ]
       on: html.
   self
       renderHorizontalLabel: 'Acknowledge'
       andField: [ self renderCheckbox: false on: html ]
       on: html.
   ...

実際のフィールドを生成するには、 として渡したブロックから呼び出す他のメソッドを作成できますaFieldRenderer。これにより、さまざまなパーツを任意に構成できる柔軟性が得られます。Seaside の例を見てください。このパターンのユーザーはたくさんいます。

于 2012-05-25T05:34:14.660 に答える
0

タグ ブラシのように使用したいように見えるので、拡張 WACanvasTag アプローチを使用することは間違いないと思いますが、実際に horizo​​ntalTextField のような複合「タグ」を作成したい場合に限ります。

行、コンテナーなど、他の Bootstrap の概念については、単純に拡張メソッドを WAHtmlCanvas に追加することをお勧めします。

私はこれを自分で行いました-これがBootstrap NavBarタグの私の実装です:

WABrush subclass: #BSNavBar
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Bootstrap'

BSNavBar>>with: aBlock
    super with: [
        canvas div class: 'navbar'; with: [
            canvas div class: 'navbar-inner'; with: [
                canvas container: aBlock]]].
    closed := true

そして、これが「行」を実装した方法です-

WAHtmlCanvas>>row
    ^self
        div class: 'row'

WAHtmlCanvas>>row: aBlock
    self row with: aBlock

さらに、拡張メソッドを WATagBrush に追加して、スパン、オフセット、プルライト、および流体コンテナーをサポートします。

WATagBrush>>offset: anInteger
    self class: 'offset', anInteger asString

WATagBrush>>beFluid
    self attributeAt: #class 
        put: (((self attributeAt: #class ifAbsent: [^self]) 
            copyReplaceTokens: 'container' with: 'container-fluid')
            copyReplaceTokens: 'row' with: 'row-fluid')

最後に、上記のいくつかを使用する render メソッドの例を次に示します。

renderContentOn: html
    html navBar: [
        html div pullRight; with: [ 
            self session isLoggedIn 
                ifTrue: [self renderUserMenuOn: html] 
                ifFalse: [self renderLoginBoxOn: html]]]
于 2012-05-25T00:17:09.947 に答える