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>')
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))
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
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
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)
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)
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
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
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 )
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
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)
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
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)
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')