1

我目前正在编写自己的 Component 基类,其中包含一大堆帮助方法,用于使用 Twitter Bootstrap CSS 框架(并避免其周围的所有样板代码)。它们可以非常像现有的表单助手(如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 中,但仍然能够在辅助函数之外(使用普通的标签辅助访问器)对这个被包装的元素进行更改,如上所示。

但是,这不起作用,因为该with:方法会导致包装 div 在我返回元素之前被序列化(也就是渲染),然后我无法再对其进行编辑。

可能的解决方案

  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 Canvas 会立即发出 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 ]

上述代码的好处是两者都aLabelRenderer可以aFieldRenderer是任何实现的对象#renderOn:(字符串、数字、块、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 方法 - 但只有当您真正想要创建一个复合“标签”时,例如在水平文本字段的情况下。

对于其他 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')

最后,这是一个使用上述一些方法的示例渲染方法:

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 回答