Esempio n. 1
0
    def test_SCRIPT(self):
        self.assertEqual(
            SCRIPT('<>', _a='1', _b='2').xml(), '''<script a="1" b="2"><!--
<>
//--></script>''')
        self.assertEqual(
            SCRIPT('<>').xml(), '''<script><!--
<>
//--></script>''')
        self.assertEqual(SCRIPT().xml(), b'<script></script>')
Esempio n. 2
0
    def __call__(self, field, value, **attributes):
        from gluon.sqlhtml import StringWidget
        default = dict(
            _type='text',
            value=(not value is None and str(value)) or '',
        )
        attr = StringWidget._attributes(field, default, **attributes)
        div_id = self.keyword + '_div'
        attr['_autocomplete'] = 'off'
        attr['_class'] = 'select2-chosen'
        select_script = """
        $('#{0:s}').select2({{
            placeholder: "Search for vulnerability...",
            minimumlength: {1:d},
            ajax: {{
                url: "{2:s}",
                dataType: 'json',
                data: function(term, page) {{
                    return {{
                        {3:s}: term
                    }}
                }},
                results: function (data) {{
                    return {{
                        results: $.map(data, function (item) {{
                            console.log(item);
                            return {{
                                text: item.{4:s},
                                id: item.id
                            }}
                        }})
                    }};
                }}
            }},
            initSelection: '',
            dropdownCssClass: "bigdrop",
        }});
        """.format(attr['_id'], self.min_length, self.url, self.keyword,
                   self.fields[0].name)

        if self.is_reference:
            key2 = self.keyword + '_aux'
            attr['_class'] = 'string span8'  # XXX: ugly hardcoding of span8!
            if 'requires' in attr:
                del attr['requires']
            attr['_name'] = key2
            value = attr['value']
            record = self.db(self.fields[1] == value).select(
                self.fields[0]).first()
            attr['value'] = record and record[self.fields[0].name]
            return TAG[''](SPAN(**attr), SCRIPT(select_script))
        else:
            attr['_name'] = field.name
            return TAG[''](SPAN(**attr), SCRIPT(select_script))
Esempio n. 3
0
 def div_modal(self, content_modal):
     div_modal = DIV(
         DIV(
             # BUTTON("x", _type="button", _class="close", **{'data-dismiss':"modal", 'aria-hidden':"true"}),
             BUTTON(
                 "x", **{
                     "_type": "button",
                     "_class": "close",
                     "_data-dismiss": "modal",
                     "_aria-hidden": "true"
                 }),
             H3(self.title_modal, _id="myModalLabel"),
             _class="modal-header"),
         DIV(content_modal, _class="modal-body", _id="host-modal"),
         SCRIPT(
             "$('#%s').on('show', function () { $(this).find('.modal-body').css({'overflow-y':'scroll', 'width':'auto', 'height':'auto'});});"
             % self.modal_id),
         **{
             "_id": "%s" % self.modal_id,
             "_class": "modal hide face",
             "_tabindex": "-1",
             "_role": "dialog",
             "_data-keyboard": "false",
             "_aria-hidden": "true",
             "_aria-labelledby": "myModalLabel"
         })
     return div_modal
Esempio n. 4
0
    def widget(self, f, v):
        """El widget
        """
        import uuid
        uid = str(uuid.uuid4())[:8]
        d_id = "cascade-" + uid
        wrapper = TABLE(_id=d_id, _class='cascade-widget')
        parent = None
        parent_format = None
        fn = ''
        vr = 'var dd%s = [];var oi%s = [];\n' % (uid, uid)
        prompt = [self.prompt(table) for table in self.tables]
        vr += 'var pr%s = ["' % uid + '","'.join([str(p)
                                                  for p in prompt]) + '"];\n'
        f_inp = SQLFORM.widgets.string.widget(f, v)
        f_id = f_inp['_id']
        f_inp['_type'] = "hidden"
        for tc, table in enumerate(self.tables):
            db = table._db
            format = table._format
            options = db(table['id'] > 0).select()
            id = str(table) + '_' + format[2:-2]
            opts = [OPTION(format % opt,_value=opt.id,
                                 _parent=opt[str(parent)] if parent else '0') \
                                  for opt in options]
            opts.insert(0, OPTION(prompt[tc], _value=0))
            inp = SELECT(opts ,_parent=str(parent) + \
                                  "_" + str(parent_format),
                                  _id=id,_name=id,
                                  _disabled="disabled" if parent else None)
            wrapper.append(TR(inp))
            next = str(tc + 1)
            vr += 'var p%s = jQuery("#%s #%s"); dd%s.push(p%s);\n' % (
                tc, d_id, id, uid, tc)
            vr += 'var i%s = jQuery("option",p%s).clone(); oi%s.push(i%s);\n' % (
                tc, tc, uid, tc)
            fn_in = 'for (i=%s;i<%s;i+=1){dd%s[i].find("option").remove();'\
                    'dd%s[i].append(\'<option value="0">\' + pr%s[i] + \'</option>\');'\
                    'dd%s[i].attr("disabled","disabled");}\n' % \
                           (next,len(self.tables),uid,uid,uid,uid)
            fn_in +='oi%s[%s].each(function(i){'\
                    'if (jQuery(this).attr("parent") == dd%s[%s].val()){'\
                    'dd%s[%s].append(this);}});' % (uid,next,uid,tc,uid,next)
            fn_in += 'dd%s[%s].removeAttr("disabled");\n' % (uid, next)
            fn_in += 'jQuery("#%s").val("");' % f_id
            if (tc < len(self.tables) - 1):
                fn += 'dd%s[%s].change(function(){%s});\n' % (uid, tc, fn_in)
            else:
                fn_in = 'jQuery("#%s").val(jQuery(this).val());' % f_id
                fn += 'dd%s[%s].change(function(){%s});\n' % (uid, tc, fn_in)
                if v:
                    fn += 'dd%s[%s].val(%s);' % (uid, tc, v)
            parent = table
            parent_format = format[2:-2]

        wrapper.append(f_inp)
        wrapper.append(SCRIPT(vr, fn))
        return wrapper
Esempio n. 5
0
def myfolderwidgetmultiple(field, value, **attributes):
    _id = '%s_%s' % (field._tablename, field.name)
    _name = field.name
    _class = 'string folders span10'
    _style = "display: inline-block;"
    requires = field.requires if isinstance(field.requires,
                                            (IS_NOT_EMPTY,
                                             IS_LIST_OF)) else None
    items = [
        LI(
            DIV(SPAN(I(_class="icon-folder-open"), _class="add-on"),
                INPUT(_class=_class,
                      _name=_name,
                      value=v,
                      hideerror=True,
                      requires=requires,
                      _style=_style),
                _class="input-prepend span9",
                _style=_style)) for v in value or ['']
    ]
    script = SCRIPT("""
// from http://refactormycode.com/codes/694-expanding-input-list-using-jquery
(function(){
jQuery.fn.grow_input_fold = function() {
return this.each(function() {
var ul = this;
jQuery(ul).find(":text").after('<a href="javascript:void(0)">+</a>').keypress(function (e) { return (e.which == 13) ? pe(ul) : true; }).next().click(function(){ pe(ul) });
});
};
function pe(ul) {
var new_line = ml(ul);
rel(ul);
new_line.appendTo(ul);
new_line.find(":text").focus().after('<a href="javascript:void(0)">+</a>').keypress(function (e) { return (e.which == 13) ? pe(ul) : true; }).next().click(function(){ pe(ul) });
new_line.find(":text").scanfolders();
return false;
}
function ml(ul) {
var line = jQuery(ul).find("li:first").clone();
line.find(':text').val('');
line.find('a').remove();
return line;
}
function rel(ul) {
return;
jQuery(ul).find("li").each(function() {
var trimmed = jQuery.trim(jQuery(this.firstChild).val());
if (trimmed=='') jQuery(this).remove(); else jQuery(this.firstChild).val(trimmed);
});
}
})();
jQuery(document).ready(function(){
    jQuery('#%s_grow_input').grow_input_fold();
    });
""" % _id)
    attributes['_id'] = _id + '_grow_input'
    return TAG[''](UL(*items, _class="unstyled", **attributes), script)
Esempio n. 6
0
def tz_nice_detector_widget(field, value, **attributes):
    options = []
    value_missing = True
    for tzn in TZSETS:
        #retrieve offset
        localized = datetime.datetime.now(pytz.timezone(tzn[0]))
        if value == tzn[0]:
            # This is the preselected value.
            value_missing = False
            options.append(
                OPTION(
                    tzn[1],
                    _value=tzn[0],
                    _selected="selected",
                    data=dict(localized=localized.strftime('%Y-%m-%d %H:%M'))))
        else:
            options.append(
                OPTION(
                    tzn[1],
                    _value=tzn[0],
                    data=dict(localized=localized.strftime('%Y-%m-%d %H:%M'))))

    _id = '%s_%s' % (field._tablename, field.name)
    _name = field.name

    if value_missing and 'autodetect' in attributes and attributes.pop(
            'autodetect') is True:
        current.response.files.append(
            URL('static', 'plugin_timezone/jstz.min.js'))
        script = """
jQuery(document).ready(function () {
  var tz = jstz.determine();
  var nice_tz_select = jQuery('#%(_id)s');
  nice_tz_select.on('change.plugin_timezone', function(e, data) {
      var localized = jQuery('#%(_id)s option:selected').data('localized');
      var placeholder = '#plugin_timezone_localized';
      if (!jQuery(placeholder).length) nice_tz_select.after('<span id="plugin_timezone_localized" style="display: block" />');
      if (typeof (data) !== 'undefined') {
        localized = 'auto: ' + localized;
      }
      else {
        manual = 'auto: ' + localized;
      }
      // jQuery(placeholder).html(localized);
  });
  if (typeof (tz) !== 'undefined') {
      var name = tz.name();
      nice_tz_select.val(name).trigger('change.plugin_timezone', [name]);
  }
});
    """ % dict(_id=_id)
        return CAT(SELECT(*options, _id=_id, _name=_name, **attributes),
                   SCRIPT(script))
    return SELECT(*options, _id=_id, _name=_name, **attributes)
Esempio n. 7
0
def latlng_widget(field, value):
    wrapper = DIV()
    input_latlng = SQLFORM.widgets.string.widget(field, value, _type="hidden")
    point = str(value).split(',')
    javascript = SCRIPT("""
        var map = L.map('map').setView([-26.83077, -65.21644], 8);
        map.addControl(new L.Control.Fullscreen());

        L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoiYnJ1aW5vIiwiYSI6ImNqeTBiam9zMTAxZ2czZ3E4aGE2ZHQ0bGIifQ.SbLskdmBG33M34jXkrSSOA', {
            attribution: '© <a href="https://www.mapbox.com/feedback/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
        }).addTo(map);

        var marker;
        
        function onMapClick(e) {
            if (marker) map.removeLayer(marker);
            marker = new L.Marker(e.latlng, { draggable: false });
            map.addLayer(marker);
            $("#%s").val(e.latlng.lat + "," + e.latlng.lng);
            // marker.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
        }
        map.on('click', onMapClick);
        
        L.Control.geocoder({
            defaultMarkGeocode: false,
            collapsed: false,
            placeholder: 'Buscar',
            errorMessage: 'No encontrado.',
            // geocoder: L.Control.Geocoder.google("AIzaSyBoaA9X9yKIpEfAcleKRXf78DKm51AYLjw")
            })
            .on('markgeocode', function (e) {
                if (marker) map.removeLayer(marker);
                marker = new L.Marker(e.geocode.center, { draggable: true });
                map.addLayer(marker);
                map.setView(e.geocode.center, 15);
                $("#%s").val(e.geocode.center.lat + "," + e.geocode.center.lng);
            })
            .addTo(map);

            latlng = %s;
            if(latlng != ['None']) {
                marker = new L.Marker(latlng, { draggable: true });
                map.addLayer(marker);
                map.setView(latlng, 13);
            }
    """ % (input_latlng['_id'], input_latlng['_id'], point),
                        _type='text/javascript')
    wrapper.components.extend([
        input_latlng,
        DIV(_id='map', _style='width: 100%; height: 500px'), javascript
    ])
    return wrapper
Esempio n. 8
0
def date_widget(field, value):
    wrapper = DIV()
    input_date = SQLFORM.widgets.date.widget(field, value)
    javascript = SCRIPT("""
        jQuery.datetimepicker.setLocale('es');
            $(function () {
                $("#%s").datetimepicker({
                    format: 'd-m-Y',
                    inline: false,
                    timepicker:false,
                });
            });
    """ % input_date['_id'],
                        _type='text/javascript')
    wrapper.components.extend([input_date, javascript])
    return wrapper
Esempio n. 9
0
 def toolbar(self):
     from gluon.html import DIV, SCRIPT, BEAUTIFY, TAG, A
     BUTTON = TAG.button
     admin = URL("admin", "default", "design", extension='html',
                 args=current.request.application)
     from gluon.dal import DAL
     dbstats = []
     dbtables = {}
     infos = DAL.get_instances()
     for k, v in iteritems(infos):
         dbstats.append(TABLE(*[TR(PRE(row[0]), '%.2fms' % (row[1]*1000))
                                for row in v['dbstats']]))
         dbtables[k] = dict(defined=v['dbtables']['defined'] or '[no defined tables]',
                            lazy=v['dbtables']['lazy'] or '[no lazy tables]')
     u = web2py_uuid()
     backtotop = A('Back to top', _href="#totop-%s" % u)
     # Convert lazy request.vars from property to Storage so they
     # will be displayed in the toolbar.
     request = copy.copy(current.request)
     request.update(vars=current.request.vars,
                    get_vars=current.request.get_vars,
                    post_vars=current.request.post_vars)
     return DIV(
         BUTTON('design', _onclick="document.location='%s'" % admin),
         BUTTON('request',
                _onclick="jQuery('#request-%s').slideToggle()" % u),
         BUTTON('response',
                _onclick="jQuery('#response-%s').slideToggle()" % u),
         BUTTON('session',
                _onclick="jQuery('#session-%s').slideToggle()" % u),
         BUTTON('db tables',
                _onclick="jQuery('#db-tables-%s').slideToggle()" % u),
         BUTTON('db stats',
                _onclick="jQuery('#db-stats-%s').slideToggle()" % u),
         DIV(BEAUTIFY(request), backtotop,
             _class="w2p-toolbar-hidden", _id="request-%s" % u),
         DIV(BEAUTIFY(current.session), backtotop,
             _class="w2p-toolbar-hidden", _id="session-%s" % u),
         DIV(BEAUTIFY(current.response), backtotop,
             _class="w2p-toolbar-hidden", _id="response-%s" % u),
         DIV(BEAUTIFY(dbtables), backtotop,
             _class="w2p-toolbar-hidden", _id="db-tables-%s" % u),
         DIV(BEAUTIFY(dbstats), backtotop,
             _class="w2p-toolbar-hidden", _id="db-stats-%s" % u),
         SCRIPT("jQuery('.w2p-toolbar-hidden').hide()"),
         _id="totop-%s" % u
     )
Esempio n. 10
0
    def checkForm(self, table):
        formnamemodal = "formmodal_%s" % self.key
        form = SQLFORM(table,
                       formname=formnamemodal,
                       _class="form-horizontal",
                       formstyle='bootstrap-modal',
                       fields=self.fields,
                       kwargs=self.kwargs)
        if self.script:
            form.append(SCRIPT(self.script))
        if form.process().accepted:
            command = "jQuery('#%s').modal('hide');" % (self.modal_id)
            command += self.cmd
            self.response.flash = self.flash
            self.response.js = command
        elif form.errors:
            self.response.flash = self.errormsg

        return form
Esempio n. 11
0
def fast_tz_detector():
    current.response.files.append(URL('static', 'plugin_timezone/jstz.min.js'))
    ##//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js
    script = """
jQuery(document).on('plugin_timezone.fast_tz_detector', function (e) {
    var tz = jstz.determine();
    if (typeof (tz) !== 'undefined') {
        var name = tz.name()
        jQuery.post('%s', {timezone : name});
    }
});
jQuery(document).ready(function () {
    jQuery(this).trigger('plugin_timezone.fast_tz_detector');
});
""" % URL()
    if current.request.post_vars.timezone:
        if current.request.post_vars.timezone in TZDICT:
            if not current.session.plugin_timezone_tz:
                current.session.plugin_timezone_tz = current.request.post_vars.timezone

    return SCRIPT(script)
Esempio n. 12
0
def pagination(request, curr_host):
    # Pagination! Send it the db, request and current host record, get back
    # a dictionary to put into the view.
    # TODO: Remove db, request and session for current.globalenv

    db = current.globalenv['db']
    cache = current.globalenv['cache']
    session = current.globalenv['session']

    from gluon.html import OPTION, SELECT, FORM, A, INPUT, SCRIPT

    hostlist = []
    hostprev = "#"
    hostnext = "#"
    hostselected = 0
    hostnextstyle = hostprevstyle = ""
    hostprevtitle = hostnexttitle = ""
    hostindex = 1
    # Create more filters here
    if request.vars.filterconfirmed is not None:
        session.hostfilterconfirmed = request.vars.filterconfirmed

    if session.hostfilterconfirmed == 'Unconfirmed [H]osts':
        query = (db.t_hosts)
    else:
        query = (db.t_hosts.f_confirmed == False)

    if session.hostfilter:
        hostfilter = session.hostfilter[0]
        if hostfilter is not None:
            if hostfilter[0] == "userid":
                query &= (db.t_hosts.f_engineer == hostfilter[1])
            elif hostfilter[0] == "assetgroup":
                query &= (db.t_hosts.f_asset_group.contains(hostfilter[1]))
            elif hostfilter[0] == "range":
                query &= (db.t_hosts.f_ipv4.contains(hostfilter[1]))

    for h_rec in db(query).select():
        hostlist.append(OPTION(host_title_maker(h_rec), _value=h_rec.id))
        if hostselected != 0 and hostnext == "#":
            hostnext = h_rec.id
            hostnexttitle = "Go to " + host_title_maker(h_rec)
        if h_rec.id == curr_host.id:
            hostselected = hostindex
        if hostselected == 0:
            hostprev = h_rec.id
            hostprevtitle = "Go to " + host_title_maker(h_rec)
        hostindex = hostindex + 1

    if hostprev == "#":
        hostprevstyle = "display:none"
    if hostnext == "#":
        hostnextstyle = "display:none"

    pagination = {}
    pagination['previous'] = A("(p)",
                               _id="prevhostlink",
                               _class="button",
                               _href=hostprev,
                               _style=hostprevstyle,
                               _title=hostprevtitle)
    pagination['next'] = A("(n)",
                           _id="nexthostlink",
                           _class="button",
                           _href=hostnext,
                           _style=hostnextstyle,
                           _title=hostnexttitle)
    pagination['form'] = FORM(
        SELECT(hostlist,
               value=request.args(0),
               _class="chosen-select",
               _id="host_select",
               _name="host_select",
               _onchange="window.location.href=$('#host_select').val()",
               **{'_data-placeholder': 'Choose a host'}),
        SCRIPT('$("#host_select").select2({width: "80%"});'),
    )
    pagination['host_number'] = "( %d/%d )" % (hostselected, len(hostlist))

    return pagination
Esempio n. 13
0
def LOAD(c=None,
         f='index',
         args=None,
         vars=None,
         extension=None,
         target=None,
         ajax=False,
         ajax_trap=False,
         url=None,
         user_signature=False,
         timeout=None,
         times=1,
         content='loading...',
         post_vars=Storage(),
         **attr):
    """  LOADs a component into the action's document

    Args:
        c(str): controller
        f(str): function
        args(tuple or list): arguments
        vars(dict): vars
        extension(str): extension
        target(str): id of the target
        ajax(bool): True to enable AJAX bahaviour
        ajax_trap(bool): True if `ajax` is set to `True`, traps
            both links and forms "inside" the target
        url(str): overrides `c`,`f`,`args` and `vars`
        user_signature(bool): adds hmac signature to all links
            with a key that is different for every user
        timeout(int): in milliseconds, specifies the time to wait before
            starting the request or the frequency if times is greater than
            1 or "infinity"
        times(integer or str): how many times the component will be requested
            "infinity" or "continuous" are accepted to reload indefinitely the
            component
    """
    from gluon.html import TAG, DIV, URL, SCRIPT, XML
    if args is None:
        args = []
    vars = Storage(vars or {})
    target = target or 'c' + str(random.random())[2:]
    attr['_id'] = target
    request = current.request
    if '.' in f:
        f, extension = f.rsplit('.', 1)
    if url or ajax:
        url = url or URL(request.application,
                         c,
                         f,
                         r=request,
                         args=args,
                         vars=vars,
                         extension=extension,
                         user_signature=user_signature)
        # timing options
        if isinstance(times, basestring):
            if times.upper() in ("INFINITY", "CONTINUOUS"):
                times = "Infinity"
            else:
                raise TypeError("Unsupported times argument %s" % times)
        elif isinstance(times, int):
            if times <= 0:
                raise ValueError(
                    "Times argument must be greater than zero, 'Infinity' or None"
                )
        else:
            raise TypeError("Unsupported times argument type %s" % type(times))
        if timeout is not None:
            if not isinstance(timeout, integer_types):
                raise ValueError("Timeout argument must be an integer or None")
            elif timeout <= 0:
                raise ValueError(
                    "Timeout argument must be greater than zero or None")
            statement = "$.web2py.component('%s','%s', %s, %s);" \
                % (url, target, timeout, times)
            attr['_data-w2p_timeout'] = timeout
            attr['_data-w2p_times'] = times
        else:
            statement = "$.web2py.component('%s','%s');" % (url, target)
        attr['_data-w2p_remote'] = url
        if target is not None:
            return DIV(content, **attr)

    else:
        if not isinstance(args, (list, tuple)):
            args = [args]
        c = c or request.controller
        other_request = Storage(request)
        other_request['env'] = Storage(request.env)
        other_request.controller = c
        other_request.function = f
        other_request.extension = extension or request.extension
        other_request.args = List(args)
        other_request.vars = vars
        other_request.get_vars = vars
        other_request.post_vars = post_vars
        other_response = Response()
        other_request.env.path_info = '/' + \
            '/'.join([request.application, c, f] +
                     [str(a) for a in other_request.args])
        other_request.env.query_string = \
            vars and URL(vars=vars).split('?')[1] or ''
        other_request.env.http_web2py_component_location = \
            request.env.path_info
        other_request.cid = target
        other_request.env.http_web2py_component_element = target
        other_request.restful = types.MethodType(request.restful.__func__,
                                                 other_request)
        # A bit nasty but needed to use LOAD on action decorates with @request.restful()
        other_response.view = '%s/%s.%s' % (c, f, other_request.extension)

        other_environment = copy.copy(current.globalenv)  # NASTY

        other_response._view_environment = other_environment
        other_response.generic_patterns = \
            copy.copy(current.response.generic_patterns)
        other_environment['request'] = other_request
        other_environment['response'] = other_response

        ## some magic here because current are thread-locals

        original_request, current.request = current.request, other_request
        original_response, current.response = current.response, other_response
        page = run_controller_in(c, f, other_environment)
        if isinstance(page, dict):
            other_response._vars = page
            other_response._view_environment.update(page)
            page = run_view_in(other_response._view_environment)

        current.request, current.response = original_request, original_response
        js = None
        if ajax_trap:
            link = URL(request.application,
                       c,
                       f,
                       r=request,
                       args=args,
                       vars=vars,
                       extension=extension,
                       user_signature=user_signature)
            js = "$.web2py.trap_form('%s','%s');" % (link, target)
        script = js and SCRIPT(js, _type="text/javascript") or ''
        return TAG[''](DIV(XML(page), **attr), script)
Esempio n. 14
0
def formstyle_bootstrap_modal(form, fields, **kwargs):
    """"
    Bootstrap format modal form layout
    """
    span = kwargs.get('span') or 'span8'
    select_attributes = kwargs.get('select_attributes', '')
    form.add_class('form-horizontal')
    parent = FIELDSET()
    for id, label, controls, help in fields:
        _controls = DIV(controls, _class='controls')
        # submit unflag by default
        _submit = False

        if isinstance(controls, INPUT):
            controls.add_class(span)
            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(span)

        if isinstance(controls, SELECT):
            controls.add_class(span)

        if isinstance(controls, TEXTAREA):
            controls.add_class(span)

        if isinstance(label, LABEL):
            label['_class'] = 'control-label'
            if help:
                label.append(
                    I(_class="icon-question-sign",
                      _rel="tooltip",
                      **{'_data-content': help}))

        if _submit:
            # submit button has unwrapped label and controls, different class
            parent.append(
                DIV(label,
                    BUTTON("Close",
                           _class="btn",
                           **{
                               '_data-dismiss': 'modal',
                               '_aria-hidden': True
                           }),
                    controls,
                    _class='modal-footer',
                    _id=id))
            # unflag submit (possible side effect)
            _submit = False
        else:
            # unwrapped label
            _class = 'control-group'
            parent.append(DIV(label, _controls, _class=_class, _id=id))

    # append tooltip and chosen field attributes
    if 'id' not in form.attributes:
        form.attributes['_id'] = "%s-id" % (str(form.table))
    script_data = """$(document).ready(function() {{
    $("[rel=tooltip]").popover({{
        placement: 'right',
        trigger: 'hover',
    }});
    $('#{0:s} select').select2({{{1:s}}});
    {2:s}
}});""".format(form.attributes['_id'], select_attributes,
               kwargs.get('script', ''))
    parent.append(SCRIPT(script_data))
    return parent
    def __call__(self, field, value):

        mylogger.debug(message='current.request.vars:%s' %
                       current.request.vars)
        mylogger.debug(message='field._tablename:%s' % (str(field._tablename)))
        mylogger.debug(message='field:%s' % (str(field)))
        mylogger.debug(message='field.name:%s' % (str(field.name)))
        mylogger.debug(message='field.type:%s' % (str(field.type)))
        mylogger.debug(message='field.requires:%s' % (str(field.requires)))
        mylogger.debug(message='type(value):%s' % (str(type(value))))
        mylogger.debug(message='value:%s' % (str(value)))

        if current.request and current.request['function']:
            function = current.request['function']
        function_configuration = self.configuration[
            '*'] if self.configuration.keys().count(
                '*') > 0 else self.configuration[
                    function] if function in self.configuration.keys() else ''

        # query parameter not used yet...
        if 'query' in function_configuration:
            query = function_configuration['query'].as_json()
        else:
            query = None
        if 'disable_validate' in function_configuration:
            disable_validate = function_configuration['disable_validate']
        else:
            disable_validate = False
        if 'add_in_db' in function_configuration:
            add_in_db = function_configuration['add_in_db']
        else:
            add_in_db = False
        if 'multiple' in function_configuration:
            multiple = function_configuration['multiple']
        else:
            multiple = False
        if 'submit_on_select' in function_configuration:
            submit_on_select = function_configuration['submit_on_select']
        else:
            submit_on_select = False
        max_nb_item = 20
        if 'max_nb_item' in function_configuration:
            max_nb_item = function_configuration['max_nb_item']
        func_lambda = ''
        if 'func_lambda' in function_configuration:
            func_lambda = function_configuration['func_lambda']
        # use this option for no required fields only, to force the user to confirm that the field is empty
        if 'confirm_empty' in function_configuration:
            confirm_empty = function_configuration['confirm_empty']
        else:
            confirm_empty = current.request.vars[
                'confirm_empty_%s' % field.
                name] == 'on' if 'confirm_empty_%s' % field.name in current.request.vars else False

        is_not_a_reference = (field._tablename == self.ref_field._tablename)

        disabled = '_disabled' in self.attributes.keys()
        mylogger.debug(message='add_in_db:%s' % (str(add_in_db)))
        mylogger.debug(message='multiple:%s' % (str(multiple)))
        mylogger.debug(message='disabled:%s' % (str(disabled)))
        mylogger.debug(message='max_nb_item:%s' % (str(max_nb_item)))
        mylogger.debug(message='is_not_a_reference:%s' %
                       (str(is_not_a_reference)))

        if (value) and (type(value) is StringType) and (value == '0'):
            nb_item = 0
        elif (value) and (type(value) is StringType) and (value == '|0|'):
            nb_item = 0
        elif (value) and (type(value) is ListType) and (value[0] == 0):
            nb_item = 0
        elif (value) and (type(value) is ListType) and (value[0] == '|0|'):
            nb_item = 0
        elif (value) and (type(value) is ListType):
            nb_item = len(value)
        elif value and value != '':
            nb_item = 1
        else:
            nb_item = 0

        if value and not type(value) is ListType and value != '':
            value = [value]

        mylogger.debug(message='nb_item:%s' % (str(nb_item)))

        #
        # basic widget structure
        #
        checkboxes_form = DIV()
        suggestions_form = DIV(
            _id='%s_suggestions' % (self.uid),
            _class='CHIMITHEQUE_MULTIPLE_widget_suggestions')
        message_form = DIV(_id='%s_message' % (self.uid),
                           _class='CHIMITHEQUE_MULTIPLE_widget_message',
                           _style='display: none;')

        search_input_form = DIV(INPUT(_name='%s_search' % self.uid,
                                      _type='text',
                                      _title='%s_search' % self.uid),
                                suggestions_form,
                                _id='%s_search' % (self.uid),
                                _class='search_input_form')

        #
        # adding a confirm empty checkbox if needed
        #
        if confirm_empty:

            confirm_empty_form = DIV(
                INPUT(_name='confirm_empty_%s' % field.name,
                      _id='confirm_empty_%s' % field.name,
                      _type='checkbox',
                      _title=self.text_confirm_empty_form_field,
                      _class='CHIMITHEQUE_MULTIPLE_widget_confirm_empty',
                      _onclick='''$('div[id=%(uid)s]').empty();

                                         if ($('input[type=checkbox][name=confirm_empty_%(field_name)s]').is(':checked')) {
                                             $('div[id=%(uid)s]').append('<span id="%(field_name)s_span_no_selected"></span>');
                                         }
                                         else {
                                             $('div[id=%(uid)s]').append('<span id="%(field_name)s_span_no_selected">%(no_item_selected)s</span>');
                                         }
                             ''' % {
                          'uid': self.uid,
                          'field_name': field.name,
                          'no_item_selected': self.text_no_item_selected
                      }))

            confirm_empty_form.append(
                IMG(_src=self.image_disable_url,
                    _alt='disable',
                    _id='%s_disable' % self.uid,
                    _title=self.text_confirm_empty_form_field))
        else:
            confirm_empty_form = DIV()

        #
        # building the AJAX query parameters
        #
        _ajax_parameters = {
            'uid': self.uid,
            'multiple': multiple,
            'disable_validate': disable_validate,
            'add_in_db': add_in_db,
            'field_tablename': field._tablename,
            'ref_field_tablename': self.ref_field._tablename,
            'ref_field_name': self.ref_field.name,
            'max_nb_item': max_nb_item,
            'max_item_length': self.max_item_length,
            'lambda': func_lambda,
            'query': query,
            'text_close_list': str(self.text_close_list),
            'text_submit': str(self.text_submit),
            'image_select_url': self.image_select_url,
            'submit_on_select': submit_on_select
        }
        ajax_parameters = json.dumps(_ajax_parameters)

        #
        # adding the "add" image
        #
        if not disabled and add_in_db:

            search_input_form.append(
                IMG(_src=self.image_insert_url,
                    _alt='submit',
                    _id='%s_add' % self.uid,
                    _title=self.text_submit,
                    _style='visibility: hidden;',
                    _class='CHIMITHEQUE_MULTIPLE_widget_addindb',
                    _onclick='''
                                            // adding the search parameter to the JSON object
                                            ajax_parameters = %(ajax_parameters)s;
                                            ajax_parameters["search"] = $('input[name=%(uid)s_search]').val();
                                            var ret = $.ajax({
                                                       type: "POST",
                                                       url: "/%(application)s/chimitheque_multiple_widget/item_add",
                                                       data: JSON.stringify(ajax_parameters),
                                                       dataType: "json",
                                                       contentType: "application/json; charset=utf-8",
                                                       async: false
                                                     }).done(function(data) {
                                                            var _action = data['action'];
                                                            var _id = data['id'];
                                                            var _val = data['val'];
                                                            var _encval = data['encval'];

                                                            var funcCall = "addReplaceCheckBox%(uid)s" + "('" + _action + "','" + _id + "','" + _val + "','" + _encval + "')";
                                                            eval(funcCall);

                                                            $('img#%(uid)s_add').attr('style', 'visibility: hidden;');
                                                        });
                                                    ''' % {
                        'uid': self.uid,
                        'application': current.request.application,
                        'ajax_parameters': ajax_parameters
                    }))

        #
        # adding the selected items DIV
        #
        if nb_item == 0:

            if 'confirm_empty_%s' % field.name in current.request.vars:
                checkboxes_form.append(SPAN())
            else:
                checkboxes_form.append(
                    SPAN(XML(self.text_no_item_selected),
                         _id='%s_span_no_selected' % field.name))
            hidden_box_form = DIV(
                INPUT(_name='%s' % field.name,
                      _id='%s_hidden' % field.name,
                      _type='checkbox',
                      _value='',
                      _style='visibility: hidden; height: 0px;',
                      _checked='checked',
                      requires=field.requires))
        else:
            hidden_box_form = DIV()

            #
            # prepopulating the form
            #
            for i in range(0, nb_item):

                mylogger.debug(message='i:%i' % (i))

                prepop_value_id = None
                prepop_value_label = None

                if is_not_a_reference:
                    # just populating with the value passed in parameter
                    mylogger.debug(message='case 1')
                    prepop_value_id = value[i]
                    prepop_value_label = value[i]
                else:
                    # the parameter value is an id in the reference table, then querying the table
                    mylogger.debug(message='case 2')
                    prepop_value = current.db(
                        current.db['%s' % self.ref_field._tablename]['id'] == (
                            value[i])).select().first()
                    if prepop_value is not None:
                        prepop_value_label = current.db[
                            '%s' %
                            self.ref_field._tablename]._format(prepop_value)
                        prepop_value_id = value[i]

                mylogger.debug(message='prepop_value_id:%s' % prepop_value_id)
                mylogger.debug(message='prepop_value_label:%s' %
                               prepop_value_label)

                if prepop_value_id:
                    #
                    # adding the checkboxes or radio for the selected items
                    #
                    if multiple:
                        _input = INPUT(
                            _name='%s' % field.name,
                            _id='%s' % field.name,
                            _type='checkbox',
                            _class='CHIMITHEQUE_MULTIPLE_widget_selected',
                            _encvalue=self.uid,
                            _value=prepop_value_id,
                            value=True,
                            requires=field.requires)
                    else:
                        if is_not_a_reference:
                            _input = INPUT(
                                _name='%s' % field.name,
                                _id='%s' % field.name,
                                _type='radio',
                                _class='CHIMITHEQUE_MULTIPLE_widget_selected',
                                _encvalue=self.uid,
                                _value=
                                prepop_value_label,  # or prepop_value_id, don't mind...
                                value=
                                prepop_value_label,  # or prepop_value_id, don't mind...
                                requires=field.requires)
                        else:
                            _input = INPUT(
                                _name='%s' % field.name,
                                _id='%s' % field.name,
                                _type='radio',
                                _class='CHIMITHEQUE_MULTIPLE_widget_selected',
                                _encvalue=self.uid,
                                _value=prepop_value_id,
                                value=prepop_value_id,
                                requires=field.requires)
                    #
                    # then the delete selected item image
                    #
                    if not disabled and not multiple:

                        img_del = IMG(_src=self.image_delete_url,
                                      _alt=self.text_delete,
                                      _title=self.text_delete,
                                      _onclick='deleteItem%s();' % self.uid,
                                      _style='float: left;')

                    else:

                        img_del = SPAN()

                    #
                    # then the label
                    #
                    checkboxes_form.append(
                        DIV(_input,
                            img_del,
                            XML('%s' % prepop_value_label),
                            _class='CHIMITHEQUE_MULTIPLE_widget_selected'))

                else:
                    # TODO: code identical to line 232...

                    if 'confirm_empty_%s' % field.name in current.request.vars:
                        checkboxes_form.append(SPAN())
                    else:
                        checkboxes_form.append(
                            SPAN(XML(self.text_no_item_selected),
                                 _id='%s_span_no_selected' % field.name))
                    hidden_box_form = DIV(
                        INPUT(_name='%s' % field.name,
                              _id='%s_hidden' % field.name,
                              _type='checkbox',
                              _value='',
                              _style='visibility: hidden; height: 0px;',
                              _checked='checked',
                              requires=field.requires))

        #
        # building the final form
        #
        final_form = DIV(
            DIV(
                DIV(checkboxes_form,
                    _id='%s' % self.uid,
                    _class='%s_%s' %
                    (self.ref_field._tablename, self.ref_field.name)),
                **self.attributes))

        if not disabled:
            final_form.insert(0, confirm_empty_form)
            final_form.insert(0, search_input_form)

        # hidden field to export the uid for the pages
        uid_field = INPUT(_name='uid_%s' % field.name,
                          _type='hidden',
                          value='%s' % self.uid,
                          style='visibility: hidden; height: 0px;')

        return DIV(final_form,
                   uid_field,
                   hidden_box_form,
                   message_form,
                   SCRIPT(
                       """
                            function disableAddButton%(uid)s() {
                                $('#%(uid)s_add').attr('style', 'visibility: hidden;');

                            }

                            function displayMessage%(uid)s(message) {
                                $('#%(uid)s_message span').remove();
                                $('#%(uid)s_message').append('<span class="error">' + message + '</span>');

                            }

                            function deleteItem%(uid)s() {
                                $('#%(uid)s').find('div[class=CHIMITHEQUE_MULTIPLE_widget_selected]').remove();

                                console.log($('input[name=%(field_name)s]').length);
                                /* enabling the hidden field if needed */
                                if ($('input[name=%(field_name)s]').length <= 1) {
                                    console.log("input name '%(field_name)s' was the last element");
                                    $('input[id=%(field_name)s_hidden]').removeAttr('disabled');
                                    $('div[id=%(uid)s]').append('<span id="%(field_name)s_span_no_selected">%(no_item_selected)s</span>');
                                }
                                else {
                                    console.log("input name '%(field_name)s' was not the last element");
                                }
                            }

                            function addReplaceCheckBox%(uid)s(action, id, val, encval) {
                                    console.log(arguments.callee.name);
                                    console.log('action:' + action);
                                    console.log('id:' + id);
                                    console.log('val:' + val);
                                    console.log('encval:' + encval);

                                    /* base64 decoding the string */
                                    val = Base64.decode(val);

                                    /* disabling the hidden field */
                                    $('input[id=%(field_name)s_hidden]').attr('disabled','true');
                                    $('span[id=%(field_name)s_span_no_selected]').remove();

                                    if ($('#%(uid)s').find('input[value="'+id+'"][encvalue='+encval+']').length != 0) {
                                        alert('%(text_item_already_selected)s');
                                    }
                                    else {
                                        var newDiv = $('<div class="CHIMITHEQUE_MULTIPLE_widget_selected"/>');
                                        var newDel = $('<img/>').attr({
                                            'src': '%(image_delete_url)s',
                                            'alt': '%(image_delete_alt)s',
                                            'title': '%(image_delete_title)s',
                                            'onclick': 'deleteItem%(uid)s();'
                                        });
                                        var newElem = $('<input/>').attr({
                                            'id': '%(field_name)s',
                                            'type': '%(type)s',
                                            'checked': 'checked',
                                            'name': '%(field_name)s',
                                            'value': id,
                                            'class': 'CHIMITHEQUE_MULTIPLE_widget_selected',
                                            'encvalue': encval,
                                        });
                                        if (action == 'replace') {
                                            newDiv.append(newDel);
                                        }
                                        newDiv.append(newElem);
                                        newDiv.append(val);
                                        if (action == 'replace') {
                                            $('#%(uid)s div').remove();
                                        }
                                        $('#%(uid)s').append(newDiv);
                                    }
                                    $('input[name=%(uid)s_search]').val('');

                                    $('#' + encval + '_suggestions div').remove();

                            }

                            function autocomplete%(uid)s() {
                                   $elem = $('input[type=text][name=%(uid)s_search]')
                                   var inputLength = $elem.val().length;
                                   if (inputLength >= %(minchar)s) {
                                        // adding the search parameter to the JSON object
                                        ajax_parameters = %(ajax_parameters)s;
                                        ajax_parameters["search"] = $elem.val();
                                        var ret = $.ajax({
                                                   type: "POST",
                                                   url: "/%(application)s/chimitheque_multiple_widget/item_selector",
                                                   data: JSON.stringify(ajax_parameters),
                                                   dataType: "json",
                                                   contentType: "application/json; charset=utf-8",
                                                   async: false
                                                 }).responseText;

                                        $('#%(uid)s_suggestions > *').remove();
                                        $('#%(uid)s_message').show();
                                        $('#%(uid)s_message').text('');
                                        if (ret.substr(0, 5) == 'ERROR') {
                                            $('#%(uid)s_message').text(ret);
                                            $('#%(uid)s_add').attr('style', 'visibility: hidden;');
                                        }else if (ret.substr(0, 4) == 'INDB'){
                                            $('#%(uid)s_add').attr('style', 'visibility: hidden;');
                                            $('#%(uid)s_suggestions').append(ret);
                                        }else if (ret.substr(0, 4) == 'NONE'){
                                            $('#%(uid)s_add').attr('style', 'visibility: visible;');
                                        }
                                        else {
                                            $('#%(uid)s_add').attr('style', 'visibility: visible;');
                                            $('#%(uid)s_suggestions').append(ret);
                                        }
                                   }
                            }

                            $(document).ready(function() {

                                jQuery('input[type=text][name=%(uid)s_search]').bind('paste', function(e) {
                                    setTimeout(function() {
                                        autocomplete%(uid)s();
                                    }, 0);
                                });

                                timer = 0;
                                jQuery('input[type=text][name=%(uid)s_search]').bind('keypress click paste input',function() {
                                        if (timer) {
                                            clearTimeout(timer);
                                        }
                                        timer = setTimeout(autocomplete%(uid)s, 400);                                  
                                });

                            });
                          """ % {
                           'disable_validate': disable_validate,
                           'add_in_db': add_in_db,
                           'multiple': multiple,
                           'uid': self.uid,
                           'field_tablename': field._tablename,
                           'field_name': field.name,
                           'field_label': field.label,
                           'ref_field_tablename': self.ref_field._tablename,
                           'ref_field_name': self.ref_field.name,
                           'minchar': self.minchar,
                           'image_delete_url': self.image_delete_url,
                           'image_delete_alt': self.text_delete,
                           'image_delete_title': self.text_delete,
                           'type': 'checkbox' if multiple else 'radio',
                           'max_nb_item': max_nb_item,
                           'max_item_length': self.max_item_length,
                           'lambda': func_lambda,
                           'image_delete_small': self.image_delete_url,
                           'text_item_already_selected':
                           self.text_item_already_selected,
                           'no_item_selected': self.text_no_item_selected,
                           'application': current.request.application,
                           'ajax_parameters': ajax_parameters
                       }),
                   _class='CHIMITHEQUE_MULTIPLE_widget')