def makeCaption(self, label, entries, rule=False): """Produce the caption for a section of navigation items. Parameters ---------- label: string Points to a key in web.yaml, under `captions`, where the full text of the caption can be founnd. entries: iterable of (path, string(html)) The path is used to determine whether this entry is active; the string is the formatted html of the entry. rule: boolean Whether there should be a rule before the first entry. Returns ------- string(html) """ if not entries: return E refPath = self.path paths = {path for (path, rep) in entries} reps = [rep for (path, rep) in entries] active = any(refPath.startswith(f"""/{p}/""") for p in paths) navClass = " active" if active else E atts = dict(cls=f"nav {navClass}") if rule: atts[N.addClass] = " ruleabove" entriesRep = H.div(reps, cls="sidebarsec") return H.details(label, entriesRep, label, **atts)
def wrap(self): """Wrap it all up.""" context = self.context auth = context.auth eppn = G(auth.user, N.eppn) if auth.authenticated() else N.public eppnRep = H.span(eppn, cls="mono") (identityRep, accessRep) = auth.credentials() login = (E if auth.authenticated() else ( auth.wrapTestUsers() if auth.isDevel else H. a(G(LOGIN, N.text), G(LOGIN, N.url), cls="button small loginout"))) logout = (H.join([ H.a(G(LOGOUT, N.text), G(LOGOUT, N.url), cls="button small loginout"), H.a( G(SLOGOUT, N.text), G(SLOGOUT, N.url), cls="button small loginout", title=G(SLOGOUT, N.title), ), ]) if auth.authenticated() else E) techdoc = (H.a( G(TECH, N.text), G(TECH, N.url), target=N._blank, cls="button medium help", title=G(TECH, N.title), )) userhelp = (H.a( G(HELP, N.text), G(HELP, N.url), target=N._blank, cls="button medium help", title=G(HELP, N.title), )) return H.div( [ H.div( [ H.icon(N.devel) if auth.isDevel else E, H.details(identityRep, eppnRep, "usereppn", cls="user"), H.div(accessRep, cls="access"), login, logout, ], cls="headlinestart", ), H.div( [ techdoc, userhelp, ], cls="headlineend", ), H.img( G(LOGO, N.src), href=G(LOGO, N.url), target=N._blank, title=G(LOGO, N.text), imgAtts=dict(height=G(LOGO, N.height)), id="logo", ), ], cls="headline", )
def wrap(self, openEid, action=None): """Wrap the list of records into HTML. action | selection --- | --- `my` | records that the current user has created or is an editor of `our` | records that the current user can edit, assess, review, or select `assess` | records that the current user is assessing `assign` | records that the current office user must assign to reviewers `reviewer` | records that the current user is reviewing `reviewdone` | records that the current user has reviewed `select` | records that the current national coordinator user can select Permissions will be checked before executing one of these list actions. See `control.table.Table.mayList`. !!! caution "Workflow restrictions" There might be additional restrictions on individual records due to workflow. Some records may not be readable. They will be filtered out. !!! note Whether records are presented in an opened or closed state depends onn how the user has last left them. This information is stored in `localStorage` inn the browser. However, if the last action was the creation of a nnew record, we want to open the list with the new record open and scrolled to, so that the usercan start filling in the blank record straightaway. Parameters ---------- openEid: ObjectId The id of a record that must forcibly be opened. action: string, optional, `None` If present, a specific record selection will be presented, otherwise all records go to the interface. Returns ------- string(html) """ if not self.mayList(action=action): return None context = self.context db = context.db table = self.table uid = self.uid countryId = self.countryId titleSortkey = self.titleSortkey (itemSingular, itemPlural) = self.itemLabels params = (dict(my=uid) if action == N.my else dict( our=countryId) if action == N.our else dict( my=uid) if action == N.assess else dict( assign=True) if action == N. assign else dict(review=uid) if action == N.review else dict( review=uid) if action == N.reviewdone else dict( selectable=countryId) if action == N.select else {}) if request.args: params.update(request.args) records = db.getList(table, titleSortkey, select=self.isMainTable, **params) insertButton = self.insertButton() if self.withInsert(action) else E sep = NBSP if insertButton else E if action == N.assess: records = [ record for record in records if self.stage(record, N.assessment) in ASSESSMENT_STAGES and self.stage(record, N.review, kind=N.final) not in {N.reviewAccept, N.reviewReject} and uid in self.creators(record, N.assessment) ] if action == N.review: records = [ record for record in records if not self.myFinished(uid, record) ] if action == N.reviewdone: records = [ record for record in records if self.myFinished(uid, record) ] recordsHtml = [] sensitive = table in SENSITIVE_TABLES for record in records: if not sensitive or self.readable(record) is not False: recordsHtml.append( H.details( self.title(record), H.div(ELLIPS), f"""{table}/{G(record, N._id)}""", fetchurl= f"""/api/{table}/{N.item}/{G(record, N._id)}""", urltitle=E, urlextra=E, **self.forceOpen(G(record, N._id), openEid), )) nRecords = len(recordsHtml) itemLabel = itemSingular if nRecords == 1 else itemPlural nRepCmt = f"""<!-- mainN~{nRecords}~{itemLabel} -->""" nRep = nRepCmt + H.span(f"""{nRecords} {itemLabel}""", cls="stats") return H.div( [H.span([insertButton, sep, nRep])] + recordsHtml, cls=f"table {table}", )
def wrap( self, inner=True, wrapMethod=None, expanded=1, withProv=True, hideMasters=False, showTable=None, showEid=None, extraCls=E, ): """Wrap the record into HTML. A record can be displayed in several states: expanded | effect --- | --- `-1` | only a title with a control to get the full details `0` | full details, no control to collapse/expand `1` | full details, with a control to collapse to the title !!! note When a record in state `1` or `-1` is sent to the client, only the material that is displayed is sent. When the user clicks on the expand/collapse control, the other part is fetched from the server *at that very moment*. So collapsing/expanding can be used to refresh the view on a record if things have happened. !!! caution The triggering of the fetch actions for expanded/collapsed material is done by the Javascript in `index.js`. A single function does it all, and it is sensitive to the exact attributes of the summary and the detail. If you tamper with this code, you might end up with an infinite loop of expanding and collapsing. !!! hint Pay extra attension to the attribute `fat`! When it is present, it is an indication that the expanded material is already on the client, and that it does not have to be fetched. !!! note There are several ways to customise the effect of `wrap` for specific tables. Start with writing a derived class for that table with `Record` as base class. * write an alternative for `Record.body`, e.g. `control.cust.review_record.ReviewR.bodyCompact`, and initialize the `Record` with `(bodyMethod='compact')`. Just specify the part of the name after `body` as string starting with a lower case. * override `Record.body`. This app does not do this currently. * use a custom `wrap` function, by defining it in your derived class, e.g. `control.cust.score_record.ScoreR.wrapHelp`. Use it by calling `Record.wrap(wrapMethod=scoreObj.wrapHelp)`. Parameters ---------- inner: boolean, optional `True` Whether to add the CSS class `inner` to the outer `<div>` of the result. wrapMethod: function, optional `None` The method to compose the result out of all its components. Typically defined in a derived class. If passed, this function will be called to deliver the result. Otherwise, `wrap` does the composition itself. expanded: {-1, 0, 1} Whether to expand the record. See the table above. withProv: boolean, optional `True` Include a display of the provenance fields. hideMasters: boolean, optional `False` Whether to hide the master fields. If they are not hidden, they will be presented as hyperlinks to the master record. extraCls: string, optional `''` An extra class to add to the outer `<div>`. Returns ------- string(html) """ table = self.table eid = self.eid record = self.record provSpecs = self.prov valid = self.valid withDetails = self.withDetails withRefresh = table in REFRESH_TABLES func = getattr(self, wrapMethod, None) if wrapMethod else None if func: return func() bodyMethod = self.bodyMethod urlExtra = f"""?method={bodyMethod}""" if bodyMethod else E fetchUrl = f"""/api/{table}/{N.item}/{eid}""" itemKey = f"""{table}/{G(record, N._id)}""" theTitle = self.title() if expanded == -1: return H.details( theTitle, H.div(ELLIPS), itemKey, fetchurl=fetchUrl, urlextra=urlExtra, urltitle=E, ) bodyFunc = (getattr(self, f"""{N.body}{cap1(bodyMethod)}""", self.body) if bodyMethod else self.body) myMasters = G(MASTERS, table, default=[]) deleteButton = self.deleteButton() innerCls = " inner" if inner else E warningCls = E if valid else " warning " provenance = (H.div( H.detailx( (N.prov, N.dismiss), H.div([self.field(field).wrap() for field in provSpecs], cls="prov"), f"""{table}/{G(record, N._id)}/{N.prov}""", openAtts=dict( cls="button small", title="Provenance and editors of this record", ), closeAtts=dict(cls="button small", title="Hide provenance"), cls="prov", ), cls="provx", ) if withProv else E) main = H.div( [ deleteButton, H.div( H.join( bodyFunc(myMasters=myMasters, hideMasters=hideMasters)), cls=f"{table.lower()}", ), *provenance, ], cls=f"record{innerCls} {extraCls} {warningCls}", ) rButton = H.iconr(itemKey, "#main", msg=table) if withRefresh else E details = (self.DetailsClass(self).wrap( showTable=showTable, showEid=showEid) if withDetails else E) return (H.details( rButton + theTitle, H.div(main + details), itemKey, fetchurl=fetchUrl, urlextra=urlExtra, urltitle="""/title""", fat=ONE, forceopen=ONE, open=True, ) if expanded == 1 else H.div(main + details))