def _render(self, form, field, renderer): entity = form.edited_entity domid = field.dom_id(form).replace(':', r'\\:') if callable(self.autocomplete_initfunc): data = self.autocomplete_initfunc(form, field) else: data = xml_escape(self._get_url(entity, field)) form._cw.add_onload( u'$("#%s").cwautocomplete(%s, %s);' % (domid, json_dumps(data), json_dumps(self.autocomplete_settings))) return super(AutoCompletionWidget, self)._render(form, field, renderer)
def call(self, rset=None, tab_id=None, jsbind=None, renderer=None, options=None, divid=None, legend=None, colors=None, width=450, height=300, displayfilter=False, mainvar=None, title=None, displayactions=False, actions=None): # Refefine the call() function to allow to pass an rset if self._cw.ie_browser(): self._cw.add_js('excanvas.js') self._cw.add_js(('jquery.jqplot.js', 'cubes.jqplot.js', 'cubes.jqplot.ext.js')) self._cw.add_css('jquery.jqplot.min.css') data, ticks = self.get_data(rset) if legend is None: legend = self.default_legend if divid is None: divid = u'figure%s' % self._cw.varmaker.next() if renderer is None: renderer = self.default_renderer serie_options = {'renderer': self.renderer(self.renderers, renderer)} if options is None: options = self.default_options serie_options['rendererOptions']= options options = {'series': [serie_options], 'legend': legend, 'title': title, } if ticks: self._cw.html_headers.add_onload('ticks = %s' % json_dumps(ticks)) options['axes'] = {'xaxis': {'ticks': JSString('ticks'), 'renderer': JSString('$.jqplot.CategoryAxisRenderer')}} self._cw.add_js('plugins/jqplot.categoryAxisRenderer.min.js') if colors is not None: options['seriesColors'] = colors self.set_custom_options(options) # Allow an onload on tab/pill show js_onload = self.onload % {'id': divid, 'data': json_dumps([data]), 'options': js_dumps(options)} if not tab_id: self._cw.html_headers.add_onload(js_onload) else: self._cw.html_headers.add_onload("""$('a[data-toggle="%s"]').on('shown', function (e) {%s})""" % (tab_id, js_onload)) self.div_holder(divid, width, height) if displayfilter and not 'fromformfilter' in self._cw.form: self.form_filter(divid, mainvar) if displayactions and not 'fromformfilter' in self._cw.form: self.display_actions(divid, actions) # Add a js bind function if jsbind: self._cw.html_headers.add_onload("""$('#%s').bind('jqplotDataClick',%s)""" % (divid, jsbind))
def wdata(self, data): if '_indent' in self._cw.form: indent = int(self._cw.form['_indent']) else: indent = None # python's json.dumps escapes non-ascii characters self.w(json_dumps(data, indent=indent).encode('ascii'))
def wdata(self, udata): """ Mixin class for json views. Handles the following optional request parameters: - '_indent': must be an integer. If found, it is used to pretty print json output. - '_binary': must be an integer. If found, it will decode binary fields. """ # Select indentation if "_indent" in self._cw.form: indent = int(self._cw.form["_indent"]) else: indent = None # Convert binary if requested if "_binary" in self._cw.form: data = [] for row in udata: for index, item in enumerate(row): if isinstance(item, Binary): row[index] = json.loads(item.getvalue()) data.append(row) else: data = udata # Dump in html page self.w(json_dumps(data, indent=indent))
def build_unrelated_select_div(self, entity, rschema, role, is_cell=False, hidden=True): options = [] divid = 'div%s_%s_%s' % (rschema.type, role, entity.eid) selectid = 'select%s_%s_%s' % (rschema.type, role, entity.eid) if rschema.symmetric or role == 'subject': targettypes = rschema.objects(entity.e_schema) etypes = '/'.join( sorted(etype.display_name(self._cw) for etype in targettypes)) else: targettypes = rschema.subjects(entity.e_schema) etypes = '/'.join( sorted(etype.display_name(self._cw) for etype in targettypes)) etypes = uilib.cut( etypes, self._cw.property_value('navigation.short-line-size')) options.append('<option>%s %s</option>' % (self._cw._('select a'), etypes)) options += self._get_select_options(entity, rschema, role) options += self._get_search_options(entity, rschema, role, targettypes) relname, role = self._cw.form.get('relation').rsplit('_', 1) return u"""\ <div class="%s" id="%s"> <select id="%s" onchange="javascript: addPendingInsert(this.options[this.selectedIndex], %s, %s, '%s');"> %s </select> </div> """ % (hidden and 'hidden' or '', divid, selectid, xml_escape(json_dumps(entity.eid)), is_cell and 'true' or 'null', relname, '\n'.join(options))
def _render_fields(self, fields, w, form): if form.parent_form is not None: entity = form.edited_entity values = form.form_previous_values qeid = eid_param('eid', entity.eid) cbsetstate = "setCheckboxesState('eid', %s, 'checked')" % \ xml_escape(json_dumps(entity.eid)) w(u'<tr class="%s">' % (entity.cw_row % 2 and u'even' or u'odd')) # XXX turn this into a widget used on the eid field w(u'<td>%s</td>' % checkbox('eid', entity.eid, checked=qeid in values)) for field in fields: error = form.field_error(field) if error: w(u'<td class="error">') self.render_error(w, error) else: w(u'<td>') if isinstance(field.widget, (fwdgs.Select, fwdgs.CheckBox, fwdgs.Radio)): field.widget.attrs['onchange'] = cbsetstate elif isinstance(field.widget, fwdgs.Input): field.widget.attrs['onkeypress'] = cbsetstate # XXX else w(u'<div>%s</div>' % field.render(form, self)) w(u'</td>\n') w(u'</tr>') else: self._main_display_fields = fields
def render(self, form, field, renderer): stream = [] w = stream.append req = form._cw _ = req._ eid = form.edited_entity.eid w(u'<table id="relatedEntities">') for rschema, role, related in field.relations_table(form): # already linked entities if related: label = rschema.display_name( req, role, context=form.edited_entity.cw_etype) w(u'<tr><th class="labelCol">%s</th>' % label) w(u'<td>') w(u'<ul class="list-unstyled">') for viewparams in related: w(u'<li>%s<span id="span%s" class="%s">%s</span></li>' % (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) if not form.force_display and form.maxrelitems < len(related): link = ( u'<span>[<a ' 'href="javascript: window.location.href+=\'&__force_display=1\'"' '>%s</a>]</span>' % _('view all')) w(u'<li>%s</li>' % link) w(u'</ul>') w(u'</td>') w(u'</tr>') pendings = list(field.restore_pending_inserts(form)) if not pendings: w(u'<tr><th> </th><td> </td></tr>') else: for row in pendings: # soon to be linked to entities w(u'<tr id="tr%s">' % row[1]) w(u'<th>%s</th>' % row[3]) w(u'<td>') w(u'<a class="handle" title="%s" href="%s">[x]</a>' % (_('cancel this insert'), row[2])) w(u'<a id="a%s" class="editionPending" href="%s">%s</a>' % (row[1], row[4], xml_escape(row[5]))) w(u'</td>') w(u'</tr>') w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid) w(u'<th class="labelCol">') w(u'<select id="relationSelector_%s" ' 'onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">' % (eid, xml_escape(json_dumps(eid)))) w(u'<option value="">%s</option>' % _('select a relation')) for i18nrtype, rschema, role in field.relations: # more entities to link to w(u'<option value="%s_%s">%s</option>' % (rschema, role, i18nrtype)) w(u'</select>') w(u'</th>') w(u'<td id="unrelatedDivs_%s"></td>' % eid) w(u'</tr>') w(u'</table>') return '\n'.join(stream)
def toggleable_relation_link(eid, nodeid, label='x'): """return javascript snippet to delete/undelete a relation between two entities """ js = u"javascript: togglePendingDelete('%s', %s);" % ( nodeid, xml_escape(json_dumps(eid))) return u'[<a class="handle" href="%s" id="handle%s">%s</a>]' % (js, nodeid, label)
def response(self, domid, status, args, entity): callback = str(self._cw.form.get('__onsuccess', 'null')) errback = str(self._cw.form.get('__onfailure', 'null')) cbargs = str(self._cw.form.get('__cbargs', 'null')) self._cw.set_content_type('text/html') jsargs = json_dumps((status, args, entity)) return """<script type="text/javascript"> window.parent.handleFormValidationResponse('%s', %s, %s, %s, %s); </script>""" % (domid, callback, errback, jsargs, cbargs)
def serialize(self, content): if self.output_type is None: return content elif self.output_type == 'xhtml': self._cw.set_content_type(self._cw.html_content_type()) return ''.join((u'<div>', content.strip(), u'</div>')) elif self.output_type == 'json': self._cw.set_content_type('application/json') return json_dumps(content) raise RemoteCallFailed('no serializer found for output type %s' % self.output_type)
def _render(self, form, field, renderer): req = form._cw if req.lang != 'en': req.add_js('jquery.ui.datepicker-%s.js' % req.lang) domid = field.dom_id(form, self.suffix) # XXX find a way to understand every format fmt = req.property_value('ui.date-format') picker_fmt = fmt.replace('%Y', 'yy').replace('%m', 'mm').replace('%d', 'dd') max_date = min_date = None if self.min_of: current = getattr(form.edited_entity, self.min_of) if current is not None: max_date = current.strftime(fmt) if self.max_of: current = getattr(form.edited_entity, self.max_of) if current is not None: min_date = current.strftime(fmt) req.add_onload(u'renderJQueryDatePicker("%s", "%s", "%s", %s, %s);' % (domid, req.uiprops['CALENDAR_ICON'], picker_fmt, json_dumps(min_date), json_dumps(max_date))) return self._render_input(form, field)
def add_onload(self): fullcalendar_options = self.fullcalendar_options.copy() fullcalendar_options['events'] = self.get_events() # i18n # js callback to add a tooltip and to put html in event's title js = """ var options = $.fullCalendar.regional('%s', %s); options.eventRender = function(event, $element) { // add a tooltip for each event var div = '<div class="tooltip">'+ event.description+ '</div>'; $element.append(div); // allow to have html tags in event's title $element.find('span.fc-event-title').html($element.find('span.fc-event-title').text()); }; $("#%s").fullCalendar(options); """ #" self._cw.add_onload(js % (self._cw.lang, json_dumps(fullcalendar_options), self.calendar_id))
def lazy_view_holder(self, w, entity, oid, registry='views'): """add a holder and return a URL that may be used to replace this holder by the html generate by the view specified by registry and identifier. Registry defaults to 'views'. """ holderid = '%sHolder' % self.domid w(u'<div id="%s"></div>' % holderid) params = self.cw_extra_kwargs.copy() params.pop('view', None) params.pop('entity', None) form = params.pop('formparams', {}) if entity.has_eid(): eid = entity.eid else: eid = None form['etype'] = entity.cw_etype form['tempEid'] = entity.eid args = [json_dumps(x) for x in (registry, oid, eid, params)] return self._cw.ajax_replace_url(holderid, fname='render', arg=args, **form)
def _build_args(self, entity, rtype, role, formid, reload, action, extradata=None): divid = self._build_divid(rtype, role, entity.eid) event_args = { 'divid': divid, 'eid': entity.eid, 'rtype': rtype, 'formid': formid, 'reload': json_dumps(reload), 'action': action, 'role': role, 'vid': u'' } if extradata: event_args.update(extradata) return event_args
def render(self, form, field, renderer): stream = [] w = stream.append req = form._cw _ = req._ __ = _ entity = form.edited_entity eid = entity.eid etype = entity.e_schema relative_url = '%s' % eid w(u'<div class="accordion form-relation" id="accordion_%s">' % eid) w_num_rel = 0 for label, rschema, role in field.relations: # FIXME should be a more optimized way to get the name of # the target entity. targets = rschema.targets(etype, role) #---- # Agregar ciclo sobre targets #---- for target in targets: if req.vreg.schema.eschema(target).has_perm(req, 'read'): if w_num_rel == 0: w(u'<div class="row-fluid">') w_num_rel = w_num_rel + 1 linkto = '%s:%s:%s' % (rschema, eid, neg_role(role)) link_label = u'%s %s' % (req._('add'), req._(target)) lsearch = u'%s %s' % (req._('search'), req._(target)) relate_entity = ( u'<div class="relate-entity">%(relate_entity)s</div>' % { 'relate_entity': entity.view('autocomplete-edition-view', relation=rschema, role=role, etype_search=target, showname="E") }) search_url = ( '<a href="?__mode=%(role)s:%(eid)s:%(rschema)s:' '%(target)s&vid=search-associate"' 'class="btn btn-micro btn-link">' '%(link_label)s' '</a>' % { 'role': role, 'rschema': rschema, 'eid': eid, 'link_label': lsearch, 'target': target }) add_new = ( '<a href="/add/%(target)s?__linkto=%(linkto)s' '&__redirectpath=%(url)s&__redirectvid=edition "' 'class="btn btn-micro btn-link">' '%(link_label)s' '</a>' % { 'linkto': linkto, 'url': relative_url, 'link_label': link_label, 'target': target }) w( u'<div class="span4"><div class="accordion-group">' u'<div class="accordion-heading container-fluid">' u' <div id="RDR_%(relation_name)s_%(role)s_%(target)s">' u' <a class="accordion-toggle" data-toggle="collapse" ' u' data-parent="# accordion_%(eid)s" ' u' href="#collapse_%(relation_name)s">' u' %(label)s' u' </a>' u' </div>' # </div> de id_RDR.. u' <div id="add-relation-combo">%(search)s %(add_new)s</div>' u'</div>' # </div> de accordion-heading % { 'eid': eid, 'relation_name': rschema, 'target': target, 'label': label, 'search': search_url, 'add_new': add_new, 'role': role, 'relate-entity': relate_entity }) w(u'<div id="collapse_%(relation)s" class="accordion-body collapse in">' u' <div class="accordion-inner">' u' <ul class="thumbnails">%(relate-entity)s' % { 'relation': rschema, 'relate-entity': relate_entity }) #---- # Reemplazar los widgets desordenados de la vid=edition por tablas tipo any_rset #---- if role == "subject": subject_eid = eid target_eid = 'eid-objeto' rql = ('Any X,X WHERE X is %(target)s,Y is %(entity)s,' ' Y %(relate)s X, Y eid %(eid)s ' % { 'relate': rschema, 'target': target, 'entity': etype, 'eid': eid }) else: subject_eid = 'eid-objeto' target_eid = eid rql = ('Any X,X WHERE X is %(target)s,Y is %(entity)s,' ' X %(relate)s Y, Y eid %(eid)s' % { 'relate': rschema, 'target': target, 'entity': etype, 'eid': eid }) rset = form._cw.execute(rql) #---- # Incluir el activador ([x]) de borrado de relaciones en la tabla preentada. # + cellvid redf-del-rel para el activador de borrado # + cellvid pending_del para que las relaciones seleccionadas se marquen visualmente #---- pending_deletes = get_pending_deletes(form._cw, eid) ea_relation = rschema.type param_but = '%s|%s|%s|%s|%s' % ('Y', eid, ea_relation, role, str(pending_deletes)) kwargs = { 'ea_rel_entity': target, 'ea_relation': rschema, 'role': role, 'headers': (' '), 'cellvids': { 0: 'rdef-del-rel', '_0': param_but }, 'limit': 10, 'rdefkwargs': {}, 'title': u'no-widget-title', } w(form._cw.view('w-table', rset, 'null', **kwargs)) #---- w(u' </div>' # </div> de accordion-inner u'</div></div>' # </div> de accordion-body-collapse -- </div> accordion-group u'</div>') # </div> de span4 if w_num_rel == 3: # controlar el cambio de row de los widgets w(u'</div>') w_num_rel = 0 if w_num_rel > 0: w(u'</div>') w(u'</div>' u'</div>') # FIXME try to change this table with a fancy html code. pendings = list(field.restore_pending_inserts(form)) w(u'<table id="relatedEntities">') if not pendings: w(u'<tr><th> </th><td> </td></tr>') else: for row in pendings: # soon to be linked to entities w(u'<tr id="tr%s">' % row[1]) w(u'<th>%s</th>' % row[3]) w(u'<td>') w(u'<a class="handle" title="%s" href="%s">[x]</a>' % (_('cancel this insert'), row[2])) w(u'<a id="a%s" class="editionPending" href="%s">%s</a>' % (row[1], row[4], xml_escape(row[5]))) w(u'</td>') w(u'</tr>') w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid) w(u'<th class="labelCol">') w(u'<select id="relationSelector_%s" tabindex="%s" ' u'onchange="javascript:showMatchingSelect' u'(this.options[this.selectedIndex].value,%s);">' % (eid, req.next_tabindex(), xml_escape(json_dumps(eid)))) w(u'<option value="">%s</option>' % _('select a relation')) for i18nrtype, rschema, role in field.relations: # more entities to link to w(u'<option value="%s_%s">%s</option>' % (rschema, role, i18nrtype)) w(u'</select>') w(u'</th>') w(u'<td id="unrelatedDivs_%s"></td>' % eid) w(u'</tr>') w(u'</table>') return '\n'.join(stream)
def generate_form(self, w, rset, divid, vid, mainvar=None, paginate=False, cssclass='', hiddens=None, **kwargs): """display a form to filter some view's content :param w: Write function :param rset: ResultSet to be filtered :param divid: Dom ID of the div where the rendering of the view is done. :type divid: string :param vid: ID of the view display in the div :type vid: string :param paginate: Is the view paginated? :type paginate: boolean :param cssclass: Additional css classes to put on the form. :type cssclass: string :param hiddens: other hidden parametters to include in the forms. :type hiddens: dict from extra keyword argument """ # XXX Facet.context property hijacks an otherwise well-behaved # vocabulary with its own notions # Hence we whack here to avoid a clash kwargs.pop('context', None) baserql, wdgs = facets(self._cw, rset, context=self.__regid__, mainvar=mainvar, **kwargs) assert wdgs self._cw.add_js(self.needs_js) self._cw.add_css(self.needs_css) self._cw.html_headers.define_var('facetLoadingMsg', self._cw._('facet-loading-msg')) vidargs = {} facetargs = xml_escape(json_dumps([divid, vid, paginate, vidargs])) w(u'<form id="%sForm" class="%s" method="post" action="" ' 'cubicweb:facetargs="%s" >' % (divid, cssclass, facetargs)) w(u'<fieldset>') if hiddens is None: hiddens = {} if mainvar: hiddens['mainvar'] = mainvar filter_hiddens(w, baserql, wdgs, **hiddens) self.layout_widgets(w, self.sorted_widgets(wdgs)) # <Enter> is supposed to submit the form only if there is a single # input:text field. However most browsers will submit the form # on <Enter> anyway if there is an input:submit field. # # see: http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2 # # Firefox 7.0.1 does not submit form on <Enter> if there is more than a # input:text field and not input:submit but does it if there is an # input:submit. # # IE 6 or Firefox 2 behave the same way. w(u'<input type="submit" class="hidden" />') # w(u'</fieldset>\n') w(u'</form>\n')
def ajax_page_url(self, **params): divid = params.setdefault('divid', 'contentmain') params['rql'] = self.cw_rset.printable_rql() return js_href( "$(%s).loadxhtml(AJAX_PREFIX_URL, %s, 'get', 'swap')" % (json_dumps('#' + divid), js.ajaxFuncArgs('view', params)))
def dumps(self): return json_dumps({'reason': self.reason})
def newfunc(*args, **kwargs): value = function(*args, **kwargs) try: return json_dumps(value) except TypeError: return json_dumps(repr(value))