o e7@sdZddlmZddlmZddlmZddlZddlmZm Z m Z ddl m Z ddl mZd d lmZmZd d lmZmZmZmZmZmZmZd d lmZgd ZdZddZe dGddZdHddZ dHddZ!dHddZ"ddZ#ddZ$ddZ%d d!Z&d"d#Z'd$d%Z(d&d'Z)d(d)Z*d*d+Z+d,d-Z,dHd.d/Z-e d0d1Z.d2d3Z/d4dZ0dId6d7Z1Gd8d9d9e2Z3dJd;d<Z4d=d>d?DZ5e6d@dA7e5dBZ8GdCdDdDeZ9dEdFZ:dS)KzmVarious utility functions and classes that support common presentation tasks such as grouping or pagination. ) JSONEncoder)datetime)ceilN) Undefined contextfilterevalcontextfilter)make_attrgetter) TracError) to_utimestamputc)FragmentMarkupclasseshtml_attribute soft_unicodestylestag)javascript_quote)captioned_buttonr first_lastgroupistextprepared_paginatepaginate Paginatorrc CsT|jjttttttd|jjt t t t t ttd|jjtttttttttd dS)zgAugment a Jinja2 environment with filters, tests and global functions defined in this module. )flatten groupattrhtmlattrmaxmixtrim) greaterthangreaterthanorequallessthanlessthanorequal not_equaltonot_intext) rrrrr separatedrrto_jsonN)filtersupdateflatten_filtergroupattr_filterhtmlattr_filter max_filter min_filter trim_filtertestsis_greaterthanis_greaterthanorequal is_lessthanis_lessthanorequalis_not_equalto is_not_inrglobalsrrrrr)rrr*)jenvr<8/usr/lib/python3/dist-packages/trac/util/presentation.py jinja2_update&s8  r>TcCs|sdSt|tr |nt|}g}t|D]}||}t|t|tr$dn|}|dur4|d||fqd|}|rB|rBd|}|jrIt|}|S)aCreate an SGML/XML attribute string based on the items in a dict. If the dict itself is `none` or `undefined`, it returns the empty string. ``d`` can also be an iterable or a mapping, in which case it will be converted to a ``dict``. All values that are neither `none` nor `undefined` are automatically escaped. For HTML attributes like `'checked'` and `'selected'`, a truth value will be converted to the key value itself. For others it will be `'true'` or `'on'`. For `'class'`, the `classes` processing will be applied. Example: .. sourcecode:: html+jinja ... Results in something like this: .. sourcecode:: html As you can see it automatically prepends a space in front of the item if the filter returned something unless the second parameter is false. Adapted from Jinja2's builtin ``do_xmlattr`` filter. Nz%s="%s" ) isinstancedictsortedrrappendjoin autoescaper) _eval_ctxd autospaceattrskeyvalrvr<r<r=r/Ks ,  r/cCt|rt|S|S)z(Returns the max value from the sequence.)lenrseqdefaultr<r<r=r0r0cCrN)z(Returns the min value from the sequence.)rOminrPr<r<r=r1rSr1cCst||S)z|Strip leading and trailing whitespace or other specified character. Adapted from Jinja2's builtin ``trim`` filter. )rstrip)valuewhatr<r<r=r2sr2cCsg}|D]}||q|S)z"Combine incoming sequences in one.)extend)rVrQsr<r<r=r-s r-cCs||kSNr<abr<r<r=r8r8cCs||kSrZr<r[r<r<r=r4r^r4cCs||kSrZr<r[r<r<r=r5r^r5cCs||kSrZr<r[r<r<r=r6r^r6cCs||kSrZr<r[r<r<r=r7r^r7cCs||vSrZr<r[r<r<r=is_inr^r_cCs||vSrZr<r[r<r<r=r9r^r9cCs|jdr|Sd||fS)zEReturn symbol and text or only symbol, according to user preferences.zui.use_symbolsz%s %s)sessionget)reqsymbolr(r<r<r=rs rcCst|dk|t|dkdS)aYGenerate ``first`` or ``last`` or both, according to the position `idx` in sequence `seq`. In Jinja2 templates, rather use: .. sourcecode:: html+jinja
  • This is less error prone, as the sequence remains implicit and therefore can't be wrong. rr )firstlast)rrO)idxrQr<r<r=rsrccsg}|D]9}|o || }|r'|r'|dg|t|7}t|V|dd=|||s4t||kr>t|V|dd=q|rS|dg|t|7}t|VdSdS)adCombines the elements produced by the given iterable so that every `n` items are returned as a tuple. >>> items = [1, 2, 3, 4] >>> for item in group(items, 2): ... print(item) (1, 2) (3, 4) The last tuple is padded with `None` values if its' length is smaller than `num`. >>> items = [1, 2, 3, 4, 5] >>> for item in group(items, 2): ... print(item) (1, 2) (3, 4) (5, None) The optional `predicate` parameter can be used to flag elements that should not be packed together with other items. Only those elements where the predicate function returns True are grouped with other elements, otherwise they are returned as a tuple of length 1: >>> items = [1, 2, 3, 4] >>> for item in group(items, 2, lambda x: x != 3): ... print(item) (1, 2) (3,) (4, None) N)rOtuplerD)iterablenum predicatebufitemflushr<r<r=rs"      rcsdtj|zdddfddWn ty&tYnwt||fddS)z/Similar to `group`, but as an attribute filter.rr Ncsj|SrZ) environment call_testrl)rGargskwargsnamer<r= s z"groupattr_filter..cs |SrZr<rp) attr_getter test_funcr<r=rts )rrn LookupErrorboolr)rGrhriattrrqrrr<)rGrqrurrrsrvr=r.s   r.cCst|to t|t S)z>`True` for text (`str` and `bytes`), but `False` for `Markup`.)rAstrr)r(r<r<r=rsrcCs,|dkrd}n ttt||}|||fS)Nrr )intrfloat)items num_items max_per_page num_pagesr<r<r=rs  c Cs|sd}||}||}d}t|dr+t|}|r+||kr+ddlm}t|d|dz|||}Wn9tylg}d}t|D]\}} ||krP|krWnn|| |dura||kranqB|durj|d}Ynw||tt t ||fS) aSimple generic pagination. Given an iterable, this function returns: * the slice of objects on the requested page, * the total number of items, and * the total number of pages. The `items` parameter can be a list, tuple, or iterator: >>> items = list(range(12)) >>> items [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] >>> paginate(items) ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2) >>> paginate(items, page=1) ([10, 11], 12, 2) >>> paginate(iter(items)) ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2) >>> paginate(iter(items), page=1) ([10, 11], 12, 2) This function also works with generators: >>> def generate(): ... for idx in range(12): ... yield idx >>> paginate(generate()) ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 12, 2) >>> paginate(generate(), page=1) ([10, 11], 12, 2) The `max_per_page` parameter can be used to set the number of items that should be displayed per page: >>> items = list(range(12)) >>> paginate(items, page=0, max_per_page=6) ([0, 1, 2, 3, 4, 5], 12, 2) >>> paginate(items, page=1, max_per_page=6) ([6, 7, 8, 9, 10, 11], 12, 2) :raises TracError: if `page` is out of the range of the paginated results. rN__len___zPage %(page)s is out of range.pager ) hasattrrOtrac.util.translationrr TypeError enumeraterDr{rr|) r}rrstartstopcountrretvalrfrlr<r<r=rs4,     rc@speZdZdZdddZddZd d Zd d Zd dZe ddZ e ddZ e ddZ dddZ ddZdS)rzPagination controllerrrNcCsx|sd}|durt|||\}}}n t|||\}}}||}||_||_||_||_||_||t|f|_d|_ dS)NrT) rrrrr}r~rrOspan show_index)selfr}rrr~roffsetr<r<r=__init__ms  zPaginator.__init__cC t|jSrZ)iterr}rr<r<r=__iter__ zPaginator.__iter__cCrrZrOr}rr<r<r=rrzPaginator.__len__cCst|jdkSNrrrr<r<r= __nonzero__zPaginator.__nonzero__cCs||j|<dSrZ)r})rrfrVr<r<r= __setitem__rzPaginator.__setitem__cC |jdkSNr )rrr<r<r=has_more_pages zPaginator.has_more_pagescCs|jd|jkSr)rrrr<r<r= has_next_pageszPaginator.has_next_pagecCrrrrr<r<r=has_previous_pagerzPaginator.has_previous_page cCs|js ttddSd}ttt|j|j}|jd}||d}||d|dd}||kr5|}||kr;|}tt||dS)Nr ) rlistranger{rr|r~rr)rpage_index_countmin_pagemax_page current_page start_pageend_pager<r<r=get_shown_pagess    zPaginator.get_shown_pagescCsVddlm}|j\}}|j}|d|kr|d||dS|d|jdd|jd|dS)Nrrr z%(last)d of %(total)d)retotalz!%(start)d - %(stop)d of %(total)d)rrr)rrrr~)rrrrrr<r<r=displayed_itemss   zPaginator.displayed_items)rrN)r)__name__ __module__ __qualname____doc__rrrrrpropertyrrrrrr<r<r<r=rjs      r,ccsRt|}zt|}Wn tyYdSw|D] }||fV|}q||fVdS)aYield `(item, sep)` tuples, one for each element in `items`. The separator after the last item is specified by the `last` parameter, which defaults to `None`. (Since 1.1.3) >>> list(separated([1, 2])) [(1, ','), (2, None)] >>> list(separated([1])) [(1, None)] >>> list(separated('abc', ':')) [('a', ':'), ('b', ':'), ('c', None)] >>> list(separated((1, 2, 3), sep=';', last='.')) [(1, ';'), (2, ';'), (3, '.')] N)rnext StopIteration)r}seprenextvalir<r<r=r)s   r)cCsi|] }|dt|qS)z\u%04x)ord).0cr<r<r= srz&<>[r?]c@seZdZddZdS)TracJSONEncodercCsZt|trdSt|trt|jr|S|jtdSt|tr'dtt |St ||S)Nr?)tzinfoz"%s") rArrr rreplacer r rrzrrR)ror<r<r=rRs    zTracJSONEncoder.defaultN)rrrrRr<r<r<r=rs rcCs&dd}tddd|}t||S)zEncode `value` to JSON.cSst|dSr) _js_quoter)matchr<r<r=rrzto_json..replaceT)r:) sort_keys separators)rencode _js_quote_resub)rVrr(r<r<r=r*s r*)TrZ)rr)rN);rjsonrrmathrrejinja2rrrjinja2.filtersr trac.corer datefmtr r htmlr rrrrrrr(r__all__ __no_apidoc__r>r/r0r1r2r-r8r4r5r6r7r_r9rrrr.rrrobjectrr)rcompilerErrr*r<r<r<r=sR     $ %  >    0   K J