def __call__(self, md): ns = namespace(md)[0] md._push(InstanceDict(ns, md)) message = render_blocks(self.section, md) md._pop(1) return message
def __call__(self, md): # In which language, if any? lang = self.lang if lang is not None and type(lang) is not str: lang = lang.eval(md) # Get the message!! ns = namespace(md)[0] md._push(InstanceDict(ns, md)) message = render_blocks(self.section, md) md._pop(1) # Interpret the message as verbatim or not if not self.verbatim: message = ' '.join([x.strip() for x in message.split()]) # Search in a specific catalog if self.catalog is None: gettext = md.getitem('gettext', 0) else: gettext = md.getitem(self.catalog, 0).gettext translation = gettext(message, lang) # Variable substitution if self.data is not None: data = self.data.eval(md) translation = translation % data return translation
def render(self, md): expr = self.expr if isinstance(expr, str): v = md[expr] else: v = expr(md) if not self.mapping: if isinstance(v, tuple) and len(v) == 1: v = v[0] v = InstanceDict(v, md) if self.only: _md = md md = TemplateDict() if hasattr(_md, 'guarded_getattr'): md.guarded_getattr = _md.guarded_getattr if hasattr(_md, 'guarded_getitem'): md.guarded_getitem = _md.guarded_getitem md._push(v) try: return render_blocks(self.section, md, encoding=self.encoding) finally: md._pop(1)
def get_items(node, branches_expr=args['branches_expr'], md=md): md._push(InstanceDict(node, md)) items = branches_expr(md) md._pop() return items
def test_getitem(self): # The acquisition chain of the object a got method is bound to # does not contain the InstanceDict instance itself. # This is a test for the fix of the regression described in # https://github.com/zopefoundation/Zope/issues/292 from DocumentTemplate.DT_Util import InstanceDict import Acquisition class Item(Acquisition.Implicit): """Class modelling the here necessary parts of OFS.SimpleItem.""" def __init__(self, id): self.id = id def __repr__(self): return '<Item id={0.id!r}>'.format(self) def method1(self): pass inst = Item('a').__of__(Item('b')) i_dict = InstanceDict(inst, {}, getattr) for element in Acquisition.aq_chain(i_dict['method1'].__self__): self.assertNotIsInstance(element, InstanceDict)
def expr_match(ob, ed): e, md, push, pop = ed push(InstanceDict(ob, md)) r = 0 try: r = e.eval(md) finally: pop() return r
def test_getitem_2(self): # It does not break the acquisition chain of stored objects. from DocumentTemplate.DT_Util import InstanceDict main = Item('main') main.sub = Item('sub') side = Item('side') side.here = Item('here') path = side.here.__of__(main) i_dict = InstanceDict(path, {}, getattr) self.assertEqual(main.sub, i_dict['sub'])
def test_getitem(self): # The acquisition chain of the object a got method is bound to # does not contain the InstanceDict instance itself. # This is a test for the fix of the regression described in # https://github.com/zopefoundation/Zope/issues/292 from DocumentTemplate.DT_Util import InstanceDict inst = Item('a').__of__(Item('b')) i_dict = InstanceDict(inst, {}, getattr) for element in Acquisition.aq_chain(i_dict['method1'].__self__): self.assertNotIsInstance(element, InstanceDict)
def call_with_ns(f, ns, arg=1): td = Rtd() # prefer 'context' to 'here'; fall back to 'None' this = ns.get('context', ns.get('here')) td.this = this request = ns.get('request', {}) td._push(request) td._push(InstanceDict(td.this, td)) td._push(ns) try: if arg==2: return f(None, td) else: return f(td) finally: td._pop(3)
def render_try_except(self, md): result = '' # first we try to render the first block try: result = render_blocks(self.section, md) except DTReturn: raise except: # but an error occurs.. save the info. t, v = sys.exc_info()[:2] if type(t) == type(''): errname = t else: errname = t.__name__ handler = self.find_handler(t) if handler is None: # we didn't find a handler, so reraise the error raise # found the handler block, now render it try: f = StringIO() traceback.print_exc(100, f) error_tb = f.getvalue() ns = namespace(md, error_type=errname, error_value=v, error_tb=error_tb)[0] md._push(InstanceDict(ns, md)) return render_blocks(handler, md) finally: md._pop(1) else: # No errors have occured, render the optional else block if (self.elseBlock is None): return result else: return result + render_blocks(self.elseBlock, md)
def tpRenderTABLE( self, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level=0, args=None, try_call_attr=try_call_attr, encoding=None, ): "Render a tree as a table" encoding = encoding or 'latin-1' exp = 0 if level >= 0: urlattr = args['url'] if urlattr and hasattr(self, urlattr): tpUrl = try_call_attr(self, urlattr) url = (url and ('%s/%s' % (url, tpUrl))) or tpUrl root_url = root_url or tpUrl ptreeData = add_with_prefix(treeData, 'tree', args.get('prefix')) ptreeData['tree-item-url'] = url ptreeData['tree-level'] = level ptreeData['tree-item-expanded'] = 0 output = data.append items = None if ('assume_children' in args and args['assume_children'] and substate is not state): # We should not compute children unless we have to. # See if we've been asked to expand our children. for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break if not exp: items = 1 get = md.guarded_getattr if get is None: get = getattr if items is None: if 'branches' in args and hasattr(self, args['branches']): items = get(self, args['branches']) items = items() elif 'branches_expr' in args: items = args['branches_expr'](md) if not items and 'leaves' in args: items = 1 if items and items != 1: getitem = getattr(md, 'guarded_getitem', None) if getitem is not None: unauth = [] for index in range(len(items)): try: getitem(items, index) except ValidationError: unauth.append(index) if unauth: if 'skip_unauthorized' in args and args['skip_unauthorized']: items = list(items) unauth.reverse() for index in unauth: del items[index] else: raise ValidationError(unauth) if 'sort' in args: # Faster/less mem in-place sort if isinstance(items, tuple): items = list(items) sort = args['sort'] size = range(len(items)) for i in size: v = items[i] k = getattr(v, sort) try: k = k() except Exception: pass items[i] = (k, v) items.sort() for i in size: items[i] = items[i][1] if 'reverse' in args: items = list(items) # Copy the list items.reverse() if isinstance(id, six.binary_type): diff.append(id.decode(encoding)) else: diff.append(id) _td_colspan = '<td colspan="%s" style="white-space: nowrap"></td>' _td_single = '<td width="16" style="white-space: nowrap"></td>' sub = None if substate is state: output('<table cellspacing="0">\n') sub = substate[0] exp = items else: # Add prefix output('<tr>\n') # Add +/- icon if items: if level: if level > 3: output(_td_colspan % (level - 1)) elif level > 1: output(_td_single * (level - 1)) output(_td_single) output('\n') output('<td width="16" valign="top" style="white-space: nowrap">') for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break s = encode_str(compress(json.dumps(diff))) # bytes in ASCII enc. # For rendering the encoded state string in a URL under Python 3, # we must lose the "b" prefix by decoding if six.PY3: s = s.decode('ASCII') # Propagate extra args through tree. if 'urlparam' in args: param = args['urlparam'] param = "%s&" % param else: param = "" if exp: ptreeData['tree-item-expanded'] = 1 icon = ('<i title="Collapse..."' ' class="fas fa-caret-down text-muted"></i>') output('<a name="%s" href="%s?%stree-c=%s#%s">%s</a>' % (id, root_url, param, s, id, icon)) else: icon = ('<i title="Expand..."' ' class="fas fa-caret-right text-muted"></i>') output('<a name="%s" href="%s?%stree-e=%s#%s">%s</a>' % (id, root_url, param, s, id, icon)) output('</td>\n') else: if level > 2: output(_td_colspan % level) elif level > 0: output(_td_single * level) output(_td_single) output('\n') # add item text dataspan = colspan - level output('<td%s%s valign="top" align="left">' % ((dataspan > 1 and (' colspan="%s"' % dataspan) or ''), ('nowrap' in args and args['nowrap'] and ' style="white-space: nowrap"' or ''))) output(render_blocks(section, md, encoding=encoding)) output('</td>\n</tr>\n') if exp: level = level + 1 dataspan = colspan - level if level > 2: h = _td_colspan % level elif level > 0: h = _td_single * level else: h = '' if 'header' in args: doc = args['header'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: output( doc( None, md, standard_html_header=( '<tr>%s' '<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) if items == 1: # leaves if 'leaves' in args: doc = args['leaves'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header= ('<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) finally: md._pop(1) elif 'expand' in args: doc = args['expand'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header=( '<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) finally: md._pop(1) else: __traceback_info__ = sub, args, state, substate ids = {} for item in items: id = extract_id(item, args['id']) if len(sub) == 1: sub.append([]) substate = sub[1] ids[id] = 1 md._push(InstanceDict(item, md)) try: data = tpRenderTABLE(item, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level, args) finally: md._pop() if not sub[1]: del sub[1] ids = ids.__contains__ for i in range(len(substate) - 1, -1): if not ids(substate[i][0]): del substate[i] if 'footer' in args: doc = args['footer'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: output( doc( None, md, standard_html_header=( '<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) del diff[-1] if not diff: output('</table>\n') return data
def __call__(self, client=None, mapping={}, **kw): '''\ Generate a document from a document template. The document will be generated by inserting values into the format string specified when the document template was created. Values are inserted using standard python named string formats. The optional argument 'client' is used to specify a object containing values to be looked up. Values will be looked up using getattr, so inheritence of values is supported. Note that names beginning with '_' will not be looked up from the client. The optional argument, 'mapping' is used to specify a mapping object containing values to be inserted. Values to be inserted may also be specified using keyword arguments. Values will be inserted from one of several sources. The sources, in the order in which they are consulted, are: o Keyword arguments, o The 'client' argument, o The 'mapping' argument, o The keyword arguments provided when the object was created, and o The 'mapping' argument provided when the template was created. ''' # print '============================================================' # print '__called__' # print self.raw # print kw # print client # print mapping # print '============================================================' if mapping is None: mapping = {} if hasattr(mapping, 'taintWrapper'): mapping = mapping.taintWrapper() if not hasattr(self, '_v_cooked'): try: changed = self.__changed__() except: changed = 1 self.cook() if not changed: self.__changed__(0) pushed = None try: # Support Python 1.5.2, but work better in 2.1 if (mapping.__class__ is TemplateDict or isinstance(mapping, TemplateDict)): pushed = 0 except: pass globals = self.globals if pushed is not None: # We were passed a TemplateDict, so we must be a sub-template md = mapping push = md._push if globals: push(self.globals) pushed = pushed + 1 else: md = TemplateDict() push = md._push shared_globals = self.shared_globals if shared_globals: push(shared_globals) if globals: push(globals) if mapping: push(mapping) md.guarded_getattr = self.guarded_getattr md.guarded_getitem = self.guarded_getitem if client is not None: if type(client) == type(()): md.this = client[-1] else: md.this = client pushed = 0 level = md.level if level > 200: raise SystemError, ('infinite recursion in document template') md.level = level + 1 if client is not None: if type(client) == type(()): # if client is a tuple, it represents a "path" of clients # which should be pushed onto the md in order. for ob in client: push(InstanceDict(ob, md)) # Circ. Ref. 8-| pushed = pushed + 1 else: # otherwise its just a normal client object. push(InstanceDict(client, md)) # Circ. Ref. 8-| pushed = pushed + 1 if self._vars: push(self._vars) pushed = pushed + 1 if kw: push(kw) pushed = pushed + 1 try: value = self.ZDocumentTemplate_beforeRender(md, _marker) if value is _marker: try: result = render_blocks(self._v_blocks, md) except DTReturn, v: result = v.v self.ZDocumentTemplate_afterRender(md, result) return result else:
def renderwob(self, md): """RENDER WithOutBatch""" expr = self.expr name = self.__name__ if expr is None: sequence = md[name] cache = {name: sequence} else: sequence = expr(md) cache = None if not sequence: if self.elses: return render_blocks(self.elses, md) return '' if isinstance(sequence, str): raise ValueError('Strings are not allowed as input to the in tag.') # Turn iterable like dict.keys() into a list. sequence = list(sequence) if cache is not None: cache[name] = sequence section = self.section mapping = self.mapping no_push_item = self.no_push_item if self.sort_expr is not None: self.sort = self.sort_expr.eval(md) sequence = self.sort_sequence(sequence, md) elif self.sort is not None: sequence = self.sort_sequence(sequence, md) if self.reverse_expr is not None and self.reverse_expr.eval(md): sequence = self.reverse_sequence(sequence) elif self.reverse is not None: sequence = self.reverse_sequence(sequence) prefix = self.args.get('prefix') vars = sequence_variables(sequence, alt_prefix=prefix) kw = vars.data pkw = add_with_prefix(kw, 'sequence', prefix) for k, v in list(kw.items()): pkw[k] = v kw['mapping'] = mapping l_ = len(sequence) last = l_ - 1 push = md._push pop = md._pop render = render_blocks if cache: push(cache) push(vars) try: result = [] append = result.append guarded_getitem = getattr(md, 'guarded_getitem', None) for index in range(l_): if index == last: pkw['sequence-end'] = 1 if guarded_getitem is not None: try: client = guarded_getitem(sequence, index) except ValidationError as vv: if ('skip_unauthorized' in self.args and self.args['skip_unauthorized']): if index == 1: pkw['sequence-start'] = 0 continue raise ValidationError('(item %s): %s' % (index, vv), sys.exc_info()[2]) else: client = sequence[index] pkw['sequence-index'] = index t = type(client) if t is TupleType and len(client) == 2: client = client[1] if no_push_item: pushed = 0 elif mapping: pushed = 1 push(client) elif t in StringTypes: pushed = 0 else: pushed = 1 push(InstanceDict(client, md)) try: append(render(section, md)) finally: if pushed: pop() if index == 0: pkw['sequence-start'] = 0 result = join_unicode(result) finally: if cache: pop() pop() return result
def renderwb(self, md): expr = self.expr name = self.__name__ if expr is None: sequence = md[name] cache = {name: sequence} else: sequence = expr(md) cache = None if not sequence: if self.elses: return render_blocks(self.elses, md) return '' if isinstance(sequence, str): raise ValueError('Strings are not allowed as input to the in tag.') # Turn iterable like dict.keys() into a list. sequence = list(sequence) if cache is not None: cache[name] = sequence section = self.section params = self.args mapping = self.mapping no_push_item = self.no_push_item if self.sort_expr is not None: self.sort = self.sort_expr.eval(md) sequence = self.sort_sequence(sequence, md) elif self.sort is not None: sequence = self.sort_sequence(sequence, md) if self.reverse_expr is not None and self.reverse_expr.eval(md): sequence = self.reverse_sequence(sequence) elif self.reverse is not None: sequence = self.reverse_sequence(sequence) next = previous = 0 try: start = int_param(params, md, 'start', 0) except Exception: start = 1 end = int_param(params, md, 'end', 0) size = int_param(params, md, 'size', 0) overlap = int_param(params, md, 'overlap', 0) orphan = int_param(params, md, 'orphan', '0') start, end, sz = opt(start, end, size, orphan, sequence) if 'next' in params: next = 1 if 'previous' in params: previous = 1 last = end - 1 first = start - 1 try: query_string = md['QUERY_STRING'] except Exception: query_string = '' prefix = params.get('prefix') vars = sequence_variables(sequence, '?' + query_string, self.start_name_re, prefix) kw = vars.data pkw = add_with_prefix(kw, 'sequence', prefix) for k, v in list(kw.items()): pkw[k] = v pkw['sequence-step-size'] = sz pkw['sequence-step-overlap'] = overlap pkw['sequence-step-start'] = start pkw['sequence-step-end'] = end pkw['sequence-step-start-index'] = start - 1 pkw['sequence-step-end-index'] = end - 1 pkw['sequence-step-orphan'] = orphan kw['mapping'] = mapping push = md._push pop = md._pop render = render_blocks if cache: push(cache) push(vars) try: if previous: if first > 0: pstart, pend, psize = opt(0, first + overlap, sz, orphan, sequence) pkw['previous-sequence'] = 1 pkw['previous-sequence-start-index'] = pstart - 1 pkw['previous-sequence-end-index'] = pend - 1 pkw['previous-sequence-size'] = pend + 1 - pstart result = render(section, md) elif self.elses: result = render(self.elses, md) else: result = '' elif next: try: # The following line is a sneaky way to test whether # there are more items, without actually # computing a length: sequence[end] except IndexError: if self.elses: result = render(self.elses, md) else: result = '' else: pstart, pend, psize = opt(end + 1 - overlap, 0, sz, orphan, sequence) pkw['next-sequence'] = 1 pkw['next-sequence-start-index'] = pstart - 1 pkw['next-sequence-end-index'] = pend - 1 pkw['next-sequence-size'] = pend + 1 - pstart result = render(section, md) else: result = [] append = result.append guarded_getitem = getattr(md, 'guarded_getitem', None) for index in range(first, end): # preset pkw['previous-sequence'] = 0 # now more often defined then previously pkw['next-sequence'] = 0 # if index == first or index == last: # provide batching information if first > 0: pstart, pend, psize = opt(0, first + overlap, sz, orphan, sequence) if index == first: pkw['previous-sequence'] = 1 pkw['previous-sequence-start-index'] = pstart - 1 pkw['previous-sequence-end-index'] = pend - 1 pkw['previous-sequence-size'] = pend + 1 - pstart try: # The following line is a sneaky way to # test whether there are more items, # without actually computing a length: sequence[end] pstart, pend, psize = opt(end + 1 - overlap, 0, sz, orphan, sequence) if index == last: pkw['next-sequence'] = 1 pkw['next-sequence-start-index'] = pstart - 1 pkw['next-sequence-end-index'] = pend - 1 pkw['next-sequence-size'] = pend + 1 - pstart except Exception: pass if index == last: pkw['sequence-end'] = 1 if guarded_getitem is not None: try: client = guarded_getitem(sequence, index) except ValidationError as vv: if ('skip_unauthorized' in params and params['skip_unauthorized']): if index == first: pkw['sequence-start'] = 0 continue raise ValidationError( '(item %s): %s' % (index, vv), sys.exc_info()[2]) else: client = sequence[index] pkw['sequence-index'] = index t = type(client) if t is TupleType and len(client) == 2: client = client[1] if no_push_item: pushed = 0 elif mapping: pushed = 1 push(client) elif t in StringTypes: pushed = 0 else: pushed = 1 push(InstanceDict(client, md)) try: append(render(section, md)) finally: if pushed: pop() if index == first: pkw['sequence-start'] = 0 result = join_unicode(result) finally: if cache: pop() pop() return result
def _exec(self, bound_data, args, kw): # Cook if we haven't already self._cook_check() # Get our caller's namespace, and set up our own. cns = bound_data['caller_namespace'] ns = self._Bindings_ns_class() push = ns._push ns.guarded_getattr = None ns.guarded_getitem = None req = None kw_bind = kw if cns: # Someone called us. push(cns) ns.level = cns.level + 1 ns.this = getattr(cns, 'this', None) # Get their bindings. Copy the request reference # forward, and include older keyword arguments in the # current 'keyword_args' binding. try: last_bound = ns[('current bindings', )] last_req = last_bound.get('REQUEST', None) if last_req: bound_data['REQUEST'] = last_req old_kw = last_bound['keyword_args'] if old_kw: kw_bind = old_kw.copy() kw_bind.update(kw) except Exception: pass else: # We're first, so get the REQUEST. try: req = aq_acquire(self, 'REQUEST') if hasattr(req, 'taintWrapper'): req = req.taintWrapper() except Exception: pass bound_data['REQUEST'] = req ns.this = bound_data['context'] # Bind 'keyword_args' to the complete set of keyword arguments. bound_data['keyword_args'] = kw_bind # Push globals, initialized variables, REQUEST (if any), # and keyword arguments onto the namespace stack for nsitem in (self.globals, self._vars, req, kw): if nsitem: push(nsitem) # Push the 'container' (default), 'context', or nothing. bind_to = self._Bindings_client if bind_to in ('container', 'client'): push(InstanceDict(bound_data[bind_to], ns)) # Push the name bindings, and a reference to grab later. push(bound_data) push({('current bindings', ): bound_data}) security = getSecurityManager() security.addContext(self) try: value = self.ZDocumentTemplate_beforeRender(ns, _marker) if value is _marker: try: result = render_blocks(self._v_blocks, ns) except DTReturn as v: result = v.v except AttributeError: if (type(sys.exc_info()[1]) == InstanceType and sys.exc_value.args[0] == "_v_blocks"): LOG.warn("DTML file '%s' could not be read" % self.raw) raise ValueError( "DTML file error: Check logfile for details") else: raise self.ZDocumentTemplate_afterRender(ns, result) return result else: return value finally: security.removeContext(self) # Clear the namespace, breaking circular references. while len(ns): ns._pop()
def tpRenderTABLE( self, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level=0, args=None, try_call_attr=try_call_attr, ): "Render a tree as a table" have_arg = args.has_key exp = 0 if level >= 0: urlattr = args['url'] if urlattr and hasattr(self, urlattr): tpUrl = try_call_attr(self, urlattr) url = (url and ('%s/%s' % (url, tpUrl))) or tpUrl root_url = root_url or tpUrl ptreeData = add_with_prefix(treeData, 'tree', args.get('prefix')) ptreeData['tree-item-url'] = url ptreeData['tree-level'] = level ptreeData['tree-item-expanded'] = 0 idattr = args['id'] output = data.append items = None if (have_arg('assume_children') and args['assume_children'] and substate is not state): # We should not compute children unless we have to. # See if we've been asked to expand our children. for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break if not exp: items = 1 get = md.guarded_getattr if get is None: get = getattr if items is None: if have_arg('branches') and hasattr(self, args['branches']): items = get(self, args['branches']) items = items() elif have_arg('branches_expr'): items = args['branches_expr'](md) if not items and have_arg('leaves'): items = 1 if items and items != 1: getitem = getattr(md, 'guarded_getitem', None) if getitem is not None: unauth = [] for index in range(len(items)): try: getitem(items, index) except ValidationError: unauth.append(index) if unauth: if have_arg('skip_unauthorized') and args['skip_unauthorized']: items = list(items) unauth.reverse() for index in unauth: del items[index] else: raise ValidationError, unauth if have_arg('sort'): # Faster/less mem in-place sort if type(items) == type(()): items = list(items) sort = args['sort'] size = range(len(items)) for i in size: v = items[i] k = getattr(v, sort) try: k = k() except: pass items[i] = (k, v) items.sort() for i in size: items[i] = items[i][1] if have_arg('reverse'): items = list(items) # Copy the list items.reverse() diff.append(id) _td_colspan = '<td colspan="%s" style="white-space: nowrap"></td>' _td_single = '<td width="16" style="white-space: nowrap"></td>' sub = None if substate is state: output('<table cellspacing="0">\n') sub = substate[0] exp = items else: # Add prefix output('<tr>\n') # Add +/- icon if items: if level: if level > 3: output(_td_colspan % (level - 1)) elif level > 1: output(_td_single * (level - 1)) output(_td_single) output('\n') output('<td width="16" valign="top" style="white-space: nowrap">') for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break #################################### # Mostly inline encode_seq for speed s = compress(json.dumps(diff)) if len(s) > 57: s = encode_str(s) else: s = b2a_base64(s)[:-1] l = s.find('=') if l >= 0: s = s[:l] s = s.translate(tplus) #################################### script = md['BASEPATH1'] # Propagate extra args through tree. if args.has_key('urlparam'): param = args['urlparam'] param = "%s&" % param else: param = "" if exp: ptreeData['tree-item-expanded'] = 1 output('<a name="%s" href="%s?%stree-c=%s#%s">' '<img src="%s/p_/mi" alt="-" border="0" /></a>' % (id, root_url, param, s, id, script)) else: output('<a name="%s" href="%s?%stree-e=%s#%s">' '<img src="%s/p_/pl" alt="+" border="0" /></a>' % (id, root_url, param, s, id, script)) output('</td>\n') else: if level > 2: output(_td_colspan % level) elif level > 0: output(_td_single * level) output(_td_single) output('\n') # add item text dataspan = colspan - level output('<td%s%s valign="top" align="left">' % ((dataspan > 1 and (' colspan="%s"' % dataspan) or ''), (have_arg('nowrap') and args['nowrap'] and ' style="white-space: nowrap"' or ''))) output(render_blocks(section, md)) output('</td>\n</tr>\n') if exp: level = level + 1 dataspan = colspan - level if level > 2: h = _td_colspan % level elif level > 0: h = _td_single * level else: h = '' if have_arg('header'): doc = args['header'] if md.has_key(doc): doc = md.getitem(doc, 0) else: doc = None if doc is not None: output( doc( None, md, standard_html_header=( '<tr>%s' '<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) if items == 1: # leaves if have_arg('leaves'): doc = args['leaves'] if md.has_key(doc): doc = md.getitem(doc, 0) else: doc = None if doc is not None: treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header= ('<tr>%s' '<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) finally: md._pop(1) elif have_arg('expand'): doc = args['expand'] if md.has_key(doc): doc = md.getitem(doc, 0) else: doc = None if doc is not None: treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header= ('<tr>%s<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) finally: md._pop(1) else: __traceback_info__ = sub, args, state, substate ids = {} for item in items: if hasattr(item, idattr): id = try_call_attr(item, idattr) elif hasattr(item, '_p_oid'): id = oid(item) else: id = pyid(item) if len(sub) == 1: sub.append([]) substate = sub[1] ids[id] = 1 md._push(InstanceDict(item, md)) try: data = tpRenderTABLE(item, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level, args) finally: md._pop() if not sub[1]: del sub[1] ids = ids.has_key for i in range(len(substate) - 1, -1): if not ids(substate[i][0]): del substate[i] if have_arg('footer'): doc = args['footer'] if md.has_key(doc): doc = md.getitem(doc, 0) else: doc = None if doc is not None: output( doc( None, md, standard_html_header= ('<tr>%s<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, (dataspan > 1 and (' colspan="%s"' % dataspan) or ''))), standard_html_footer='</td></tr>', )) del diff[-1] if not diff: output('</table>\n') return data
def tpRender(self, md, section, args, try_call_attr=try_call_attr): """Render data organized as a tree. We keep track of open nodes using a cookie. The cookie stored the tree state. State should be a tree represented like: [] # all closed ['eagle'], # eagle is open ['eagle'], ['jeep', [1983, 1985]] # eagle, jeep, 1983 jeep and 1985 jeep where the items are object ids. The state will be pickled to a compressed and base64ed string that gets unencoded, uncompressed, and unpickled on the other side. Note that ids used in state need not be connected to urls, since state manipulation is internal to rendering logic. Note that to make unpickling safe, we use the MiniPickle module, that only creates safe objects """ data = [] idattr = args['id'] if hasattr(self, idattr): id = try_call_attr(self, idattr) elif hasattr(self, '_p_oid'): id = oid(self) else: id = pyid(self) try: # see if we are being run as a sub-document root = md['tree-root-url'] url = md['tree-item-url'] state = md['tree-state'] diff = md['tree-diff'] substate = md['-tree-substate-'] colspan = md['tree-colspan'] level = md['tree-level'] except KeyError: # OK, we are a top-level invocation level = -1 if md.has_key('collapse_all'): state = [id, []], elif md.has_key('expand_all'): have_arg = args.has_key if have_arg('branches'): def get_items(node, branches=args['branches'], md=md): get = md.guarded_getattr if get is None: get = getattr items = get(node, branches) return items() elif have_arg('branches_expr'): def get_items(node, branches_expr=args['branches_expr'], md=md): md._push(InstanceDict(node, md)) items = branches_expr(md) md._pop() return items state = [id, tpValuesIds(self, get_items, args)], else: if md.has_key('tree-s'): state = md['tree-s'] state = decode_seq(state) try: if state[0][0] != id: state = [id, []], except IndexError: state = [id, []], else: state = [id, []], if md.has_key('tree-e'): diff = decode_seq(md['tree-e']) apply_diff(state, diff, 1) if md.has_key('tree-c'): diff = decode_seq(md['tree-c']) apply_diff(state, diff, 0) colspan = tpStateLevel(state) substate = state diff = [] url = '' root = md['URL'] l = root.rfind('/') if l >= 0: root = root[l + 1:] treeData = { 'tree-root-url': root, 'tree-colspan': colspan, 'tree-state': state } prefix = args.get('prefix') if prefix: for k, v in treeData.items(): treeData[prefix + k[4:].replace('-', '_')] = v md._push(InstanceDict(self, md)) md._push(treeData) try: tpRenderTABLE(self, id, root, url, state, substate, diff, data, colspan, section, md, treeData, level, args) finally: md._pop(2) if state is substate and not (args.has_key('single') and args['single']): state = state or ([id], ) state = encode_seq(state) md['RESPONSE'].setCookie('tree-s', state) return ''.join(data)