def bodyCompact(self, **kwargs):
        critId = self.critId
        critRecord = self.critRecord
        perm = self.perm

        critData = critRecord.record
        actual = G(critData, N.actual, default=False)
        msg = E if actual else G(MESSAGES, N.legacyCriterion)

        critKey = f"""{N.criteria}/{critId}/help"""
        (infoShow, infoHide, infoBody) = H.detailx(
            (N.info, N.dismiss),
            critRecord.wrapHelp(),
            critKey,
            openAtts=dict(cls="button small",
                          title="Explanation and scoring guide"),
            closeAtts=dict(cls="button small",
                           title="Hide criteria explanation"),
        )

        score = H.div(self.field(N.score).wrap(asEdit=G(perm, N.isEdit)))
        evidence = H.div(self.field(N.evidence).wrap(asEdit=G(perm, N.isEdit)))
        entry = H.div([
            H.div(H.he(msg), cls="heavy") if msg else E,
            infoShow,
            infoHide,
            infoBody,
            score,
            evidence,
        ], )

        return entry
Esempio n. 2
0
def presentScore(score, eid, derivation=True):
    """Presents the result of a score computation.

    It shows the overall score, but it can also expand a derivation of the
    overall score.

    Parameters
    ----------
    score: dict
        Quantities relevant to the score and its derivation
    eid: ObjectId
        Id of the assessment of which the score has been taken.
        Only used to give the score presentation a unique identifier on the
        interface, so that the derivation can be collapsed and expanded
        in the presence of other score presentations.
    derivation: boolean, optional `True`
        If `False`, the derivation will be suppressed.
    """

    overall = G(score, N.overall, default=0)
    relevantScore = G(score, N.relevantScore, default=0)
    relevantMax = G(score, N.relevantMax, default=0)
    relevantN = G(score, N.relevantN, default=0)
    allMax = G(score, N.allMax, default=0)
    allN = G(score, N.allN, default=0)
    irrelevantN = allN - relevantN

    fullScore = H.span(
        f"Score {overall}%",
        title="overall score of this assessment",
        cls="ass-score",
    )
    if not derivation:
        return fullScore

    scoreMaterial = H.div(
        [
            H.div(
                [
                    H.p(f"""This assessment scores {relevantScore} points."""),
                    H.p(f"""For this type of contribution there is a total of
                          {allMax} points, divided over {allN} criteria.
                      """),
                    (H.p(f"""However,
                              {irrelevantN}
                              rule{" is " if irrelevantN == 1 else "s are"}
                              not applicable to this contribution,
                              which leaves the total amount to
                              {relevantMax} points,
                              divided over {relevantN} criteria.
                          """) if irrelevantN else E),
                    H.p(f"""The total score is expressed as a percentage:
                          the fraction of {relevantScore} scored points
                          with respect to {relevantMax} scorable points:
                          {overall}%.
                      """),
                ],
                cls="ass-score-deriv",
            ),
        ],
        cls="ass-score-box",
    )

    scoreWidget = H.detailx(
        (N.calc, N.dismiss),
        scoreMaterial,
        f"""{N.assessment}/{eid}/scorebox""",
        openAtts=dict(cls="button small", title="Show derivation"),
        closeAtts=dict(cls="button small", title="Hide derivation"),
    )
    return (fullScore, *scoreWidget)
Esempio n. 3
0
    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))