help-block in Bootstrap forms

385 views
Skip to first unread message

Annet

unread,
Dec 12, 2013, 1:08:15 PM12/12/13
to web...@googlegroups.com
Some field definitions in my models have comments, which in a Bootstrap form are
being displayed in a help-block.

The problem is that this help-block

<span class="help-block">my comment</span>

is added to every form field, resulting in 20 px of extra padding between form fields, margin-bottom: 10px
and margin-bottom: 5px. Is there a way to make adding a help-block conditional?

So far I made the following adjustments to a custom formstyle function:

def bootstrap3(form, fields):
    form.add_class('form-horizontal')
    parent = FIELDSET()
    for id, label, controls, help in fields:
        # wrappers
        _help = SPAN(help, _class='help-block')
        # embed _help into _controls
        _controls = DIV(controls, _help, _class='controls col-sm-8')
        # submit unflag by default
        _submit = False

        if isinstance(controls, INPUT):
            controls.add_class('form-control')
            if controls['_type'] == 'submit':
                # flag submit button
                _submit = True
                controls['_class'] = 'btn btn-primary'
            if controls['_type'] == 'file':
                controls['_class'] = 'input-file'

        # For password fields, which are wrapped in a CAT object.
        if isinstance(controls, CAT) and isinstance(controls[0], INPUT):
            controls[0].add_class('form-control')

        if isinstance(controls, SELECT):
            controls.add_class('form-control')

        if isinstance(controls, TEXTAREA):
            controls.add_class('form-control')

        if isinstance(label, LABEL):
            label['_class'] = 'col-sm-4 control-label'

        if _submit:
            # submit button has unwrapped label and controls, different class
            parent.append(DIV(label, controls, _class='col-sm-offset-4 col-sm-8 form-actions', _id=id))
            # unflag submit (possible side effect)
            _submit = False
        else:
            # unwrapped label
            parent.append(DIV(label, _controls, _class='form-group', _id=id))
    return parent



Kind regards,

Annet

Massimo Di Pierro

unread,
Dec 12, 2013, 4:32:32 PM12/12/13
to web...@googlegroups.com
Can you please open a ticket about this so it does not get lost? We need to port welcome to bootstrap 3 asap.

Paolo Caruccio

unread,
Dec 12, 2013, 5:25:34 PM12/12/13
to web...@googlegroups.com
In this days I'm finishing an external module (based on DOM server-side manipulation) that converts web2py elements (at the moment: the auth navbar, the menu and SQLform) to bootstrap3. It is my intention make this module easy to extend to other frameworks also. Bootstrap3 and Foundation5 are almost ready and I'm working on "ink sapo framework" just to try if it's possible the porting to something different. 
I'm posting the code and examples on this group before xmas for testing and feedback purposes. Some screenshots here attached.
bs3_index.jpg
bs3-form.jpg
f5-form.jpg
f5-index.jpg
ink2.jpg

LightDot

unread,
Dec 13, 2013, 5:54:21 AM12/13/13
to web...@googlegroups.com
That's excellent! I just started converting the welcome app to bs3 yesterday and got as far as converting and tweaking the html and adding 2nd level submenu support. Foundation 5 was the next on my list.

It seems that you've gotten further along so I'll wait for your code and help out once it's published. Drop me a note directly if you could use any help before that.

Regards
w2p_welcome_2013-12-13_.png

Paolo Caruccio

unread,
Dec 13, 2013, 9:21:28 AM12/13/13
to web...@googlegroups.com
Thank you LightDot.
In the next few days I'll send to your private email the files for bootstrap3 and foundation5 so you will able to check my code and yours.
My bootstrap 3 code supports multilevel (2, 3 and so on) menu also. Both bs3 and f5 manage the errors in form (see attached image) and the auth navbar is easily customizable by the user. There are other small features too. Of course they are responsive and should work also in mobile machines. 
But more important thing is that by making small changes to it,  the code can be applied also to other framework and therefore we will isolate this matters from web2py core. The package for each framework  is constitued by a python module, custom css file and a custom js file  in addition to the framework files obviously.
I hope this will be the first step to the web2py theming.
f5-form-errors.jpg
tb3-form-errors.png

Niphlod

unread,
Dec 13, 2013, 11:22:35 AM12/13/13
to web...@googlegroups.com
is the endgame really let response.menu generate a structure than is converted every time server-side ?
Shouldn't we avoid server-side dom at all costs ?

Paolo Caruccio

unread,
Dec 13, 2013, 12:00:02 PM12/13/13
to web...@googlegroups.com
Well we could convert the menu on client side but I found several ugly rendering issues.
And why we should avoid server-side dom? I think that it is an interesting web2py feature. 

However since your opinion is important for me, do you think the following function might have a bad impact server-side?

def menu():
   
# get the current menu
    current_menu
= current.response.menu
   
# set the new menu
    menu
= MENU(current_menu,
                   _class
='nav navbar-nav',
                   li_class
='dropdown',
                   ul_class
='dropdown-menu')
   
# add here any menu customization
    menu
= menu.serialize(menu.data)
    dropdowns
= menu.elements('ul.dropdown-menu')
   
for dropdown in dropdowns:
        toggle
= dropdown.parent
       
if toggle.parent['_class'] == 'nav navbar-nav':
            toggle
['_data-w2pmenulevel'] = "l0"
            toggle
.element('a',
                           replace
=lambda t: A(t[0], ' ',
                                               SPAN
('', _class="caret"),
                                               _href
=t['_href'],
                                               _class
='dropdown-toggle',
                                               
**{'_data-toggle': 'dropdown'}))
       
else:
            toggle
['_class'] = toggle['_class'].replace('dropdown',
                                                       
'dropdown-submenu')


   
return menu

And in the layout.html:

            {{if response.menu:}}
           
{{=bs3.menu()}}
           
{{pass}}

Thank you in advance for your feedback.

Niphlod

unread,
Dec 13, 2013, 2:33:40 PM12/13/13
to web...@googlegroups.com
IMHO there's no point on having web2py serializing by default a structure (response.menu) to a string (the html markup) and then reparse it back to a structure (elements) to move a few pieces back and forth and then reserializing those pieces back to html markup. It's just a waste of cpu.

The way to go NEEDS to be modules with overrides, not server-side DOM manipulations...
I agree that right now you can only act on the MENU() function, but a way must be figured out to avoid serverside DOM parsing or we'll soon face an untouchable MENU() that can't accomodate for new features 'cause there are lots of code expecting a fixed html markup.
Same goes for forms and widgets: fortunately we have already a formstyle that takes a callback, but I don't see why noone is coming up with a new set of widgets that override the default one composing the html elements the way they are supposed to be in the first place

Paolo Caruccio

unread,
Dec 13, 2013, 6:50:04 PM12/13/13
to web...@googlegroups.com
Thank you Niphlod. I see what you mean. I'll try to convert my code in order to build a custom formstyle. However, I'll share my code with the web2py users group: maybe it could be useful to someone. 
About the menu, I have in my mind a simple change to the MENU helper that should semplify its customization client side (jquery and css) but I have to investigate more on this.
Anyway, the menu complexity is due to lack of support for multilevel submenus. If we need a single level menu there's no need to modify the web2py code. 
For the sake of completeness, Foundation framework supports the multilevel menu, but its css breaks the web2py calendar css. 
It seems that every css framework has its own Achilles' Heel.  

LightDot

unread,
Dec 13, 2013, 8:33:23 PM12/13/13
to web...@googlegroups.com
Most of the work already done on bootstrap 3, foundation 5, etc. can be reused. The DOM manipulating parts are also bound to be useful - as an example of what can be done, if nothing else.

I'm using the plugin_layout_<cssfw> functionality to keep bootstrap 2 & 3, bootswatch 2 & 3 and foundation 5 playing along within a single app. I'm aiming for slightly different bs2, bs3, foundation5, etc. welcome apps, that can be packed as plugin_layout_<cssfw> and updated as someone needs them.

About the other part of the equation - the support for different CSS frameworks from within gluon or contrib - there was a discussion about how to implement all this a while ago and I think we really ought to finish it...

My thoughts as far as functionality goes:
- user would set a global variable (ie. styleserializer=bootstrap3 ..or bootstrap2, foundation5 or some other predefined style) and thus define the serialization of menus, forms, tables, grid, flash messages, etc. all in one place
- existing menu, formstyle, etc. functionality stays, this is needed for backward compatibility and is also useful. User could ie. use the global variable to set everything to bootstrap3, then override the formstyle setting for one specific form to, let's say, bootstrap3-inline.

All that is left for a user is to drop in a correct welcome app and voila, foundation 5 or bootstrap 3 based web2py.

The implementation is something I'm not clear about. Should everything be kept in gluon, as it is now..? Should old formstyles (table3cols, etc.) stay within gluon, while bootstrap, bootstrap3 (it's already done, since recently) and future ones get moved to contrib?  Should MENU() be deprecated, keeping it as is, or should it be extended to accomodate more CSS frameworks? Perhaps a new menu function altogether, in contrib?

What else am I not thinking of..?
Reply all
Reply to author
Forward
0 new messages