编写用于封装HTML元素的助手 [英] Write helpers for wrapping HTML elements

查看:255
本文介绍了编写用于封装HTML元素的助手的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Twitter Bootstrap CSS框架编写自己的组件基类,并使用Twitter Bootstrap CSS框架(并避免围绕它的所有样板代码)。它们可以很像现有的表单助手(比如 html div ... )。



水平文本字段(水平形式)的样子如下所示:

  horizo​​ntalTextField:aLabel 
|字段|

field:= WATextInputTag new
class:'input-xlarge';
你自己。

自己的html div
class:'control-group';
with:[
self html label
class:'control-label';
与:aLabel。
自我html div
class:'controls';
与:[self html brush:field]。
]。

^字段。

在渲染组件时,我打算使用这种方式:

 (self horizo​​ntalTextField:'Titel')
on:#title of:self article;
id:'title'。

因此,目标是将实际的文本字段封装在几个div中,但仍然能够如上所示,使用辅助函数(使用普通标记助手访问器)来更改此包装元素。



但是,不起作用

strong>作为:方法会导致包装div在序列化(aka呈现)之前返回元素,然后我无法再编辑。



可能的解决方案


  1. 实际上扩展WACanvasTag子类用于渲染字段,并在我的组件类的自定义助手中创建这些新子类的实例。我会简单地覆盖他们的渲染代码,为我的乐趣。这可能是最面向对象的方式来做事情,但相当艰巨,特别是因为我必须重复相当多的代码来插入我自己的HTML前后这些子类中的每一个的元素(如他们已经必须从我试图包装的Tag类继承)。

  2. 在调用助手时,像自身的horizo​​ntalTextField:'Titel' :[:field | id:'title'] 。该块将在辅助方法中呈现实际文本字段之前应用。这将非常灵活,但不是很漂亮(语法明智)。
  3. Hardcode包装HTML(与这个问题)在我的帮助函数中。像这样: self html html:'< label class =control-label> 等等。不管怎么说,这都是非常面向对象的。

评论?想法?更好的建议?

在Seaside中执行此操作的典型方法是创建一个帮助器方法:

  renderHorizo​​ntalLabel:aLabelRenderer andField:aFieldRenderer on:html 
html div
class:'control -组';
with:[
html标签
class:'control-label';
与:aLabelRenderable。
html div
class:'controls';
with:aFieldRenderer]

上面代码的好处在于 aLabelRenderer aFieldRenderer 可以是任何实现 #renderOn:的对象(String, Number,Block,WAPresenter,WAComponent,...)。

  renderContentOn:html 
self
renderHorizo​​ntalLabel :'Comment'
andField:[
html textField
value:comment;
回调:[:value | comment:= value]]
on:html。
self
renderHorizo​​ntalLabel:'确认'
和字段:[self renderCheckbox:false on:html]
on:html。
...

要生成实际字段,您可以创建其他方法从您传入的块中 aFieldRenderer 。这使您可以灵活地任意组合不同部分。看看Seaside的例子,这种模式有很多用户。


I am currently writing my own Component base class with a whole bunch of helper methods for using the Twitter Bootstrap CSS framework (and avoiding all the boilerplate code around it). They can be used very much like the existing form helpers (like html div ...).

E.g., the one for horizontal text fields (in a horizontal form) looks like this:

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.

Which I aim to be using like this when rendering a component:

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

So, the aim is to wrap the actual text field in a few divs, but still be able to make changes to this wrapped element outside of the helper function (using the normal tag helper accessors), as shown above.

However, this does not work as the with: method causes the wrapping divs to be serialized (aka rendered) before I return the element, which I then cannot edit anymore.

POSSIBLE SOLUTIONS:

  1. Actually extend the WACanvasTag subclasses used for rendering the fields and create instances of those new subclasses in my custom helpers in my component class. I would simply overwrite their rendering code for my pleasure. This would probably be the most object-oriented way to do things, but quite arduous, especially as I'd have to repeat quite a lot of code for inserting my own HTML before and after the element for every single one of these subclasses (as they already have to inherit from the Tag class which I'm trying to wrap).
  2. When calling the helpers, do something like self horizontalTextField: 'Titel' with: [:field | id: 'title']. The block would then be applied before rendering the actual text field in the helper method. This would be quite flexible, but not very pretty (syntax-wise).
  3. Hardcode the wrapping HTML (related to this question) in my helper functions. Like this: self html html: '<label class="control-label"> etc. Quite the hack, in a way, and not very object-oriented.

Comments? Ideas? Better suggestions?

解决方案

As you noticed, the above code does not work because the HTML Canvas emits the HTML right away. Brushes should never be stored anywhere, they are only valid a very short time. The same goes for the HTML canvas, it is very uncommon and a possible cause of bugs to store it somewhere.

The typical way to do this in Seaside is to create a helper method:

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 ]

The nice thing about the above code is that both aLabelRenderer and aFieldRenderer can be any object implementing #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.
   ...

To generate the actual field you could create other methods that you then call from the block you pass in as aFieldRenderer. This gives you the flexibility to arbitrarily compose the different parts. Have a look at the examples in Seaside, there are many users of this pattern.

这篇关于编写用于封装HTML元素的助手的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆