Пример #1
0
def on_card_did_render(
    output: TemplateRenderOutput, ctx: TemplateRenderContext
) -> None:
    output.question_text = render_latex(
        output.question_text, ctx.note_type(), ctx.col()
    )
    output.answer_text = render_latex(output.answer_text, ctx.note_type(), ctx.col())
Пример #2
0
def on_card_did_render(text: Tuple[str, str],
                       ctx: TemplateRenderContext) -> Tuple[str, str]:
    qtext, atext = text

    qtext = render_latex(qtext, ctx.note_type(), ctx.col())
    atext = render_latex(atext, ctx.note_type(), ctx.col())

    return (qtext, atext)
Пример #3
0
def on_field_filter(text, field, filter, context: TemplateRenderContext):
    if filter != "clickable" or field != "Tags":
        return text

    kbd = """
<kbd onclick="ct_click('{tag}')" ondblclick="ct_dblclick('{tag}', '{deck}')">
  {tag}
</kbd>
"""

    return "".join([
        kbd.format(tag=tag, deck=context.fields()["Deck"])
        for tag in context.fields()["Tags"].split()
    ])
Пример #4
0
def on_field_filter(text, field, filter, context: TemplateRenderContext):
    if filter != 'clickable' or field != 'Tags':
        return text

    kbd = """
<kbd onclick="ct_click('{tag}')" ondblclick="ct_dblclick('{tag}', '{deck}')">
  {tag}
</kbd>
"""

    return ''.join([
        kbd.format(tag=tag, deck=context.fields()['Deck'])
        for tag in context.fields()['Tags'].split()
    ])
Пример #5
0
def hanzi_context(
    txt: str, field_name: str, filter_name: str, context: TemplateRenderContext,
) -> str:
    if not filter_name.startswith("hanzi_context"):
        # not our filter, return string unchanged
        return txt
    '''
    For use on a Hanzi field.
    Return a list of all the other Hanzi synonyms, with the common characters hidden,
    to allow the user to identify the correct hanzi from a note.
    '''
    other_hanzi = []
    for k, v in context.iteritems():
        if re.match(r'Hanzi.*', k, flags=re.IGNORECASE) and v != txt :
            other_hanzi += [k]
    if len(other_hanzi)<1:
        return ""
    other_hanzi.sort()
    other_hanzi_values = []
    for v in other_hanzi:
        value = stripHTML(re.sub(r, r'\1', no_sound(context[v])))
        if len(value)>0:
            other_hanzi_values += [value]
    if len(other_hanzi_values)<1:
        return ""
    def concat(a, b):
        return a + " / " + b
    context_string = reduce(concat, other_hanzi_values)
    for h in txt:
        if  h >= u'\u4e00' and h <= u'\u9fff':
            context_string = re.sub(h, " _ ", context_string)
    context_string = re.sub("  ", " ", context_string)
    return context_string
Пример #6
0
def on_edit_filter(text, field, filter, context: TemplateRenderContext):
    if filter != "edit":
        return text

    if not safe_to_edit(text):
        return text

    config = mw.addonManager.getConfig(__name__)
    card = context.card()
    nid = card.nid if card is not None else ""
    text = """<%s contenteditable="true" data-field="%s" data-nid="%s">%s</%s>""" % (
        config['tag'], field, nid, text, config['tag'])
    text += """<script>"""
    text += """
            $("[contenteditable=true][data-field='%s']").blur(function() {
                pycmd("ankisave#" + $(this).data("field") + "#" + $(this).data("nid") + "#" + $(this).html());
            });
        """ % field
    if config['tag'] == "span":
        text += """
            $("[contenteditable=true][data-field='%s']").keydown(function(evt) {
                if (evt.keyCode == 8) {
                    evt.stopPropagation();
                }
            });
        """ % field
    text += """
            $("[contenteditable=true][data-field='%s']").focus(function() {
                pycmd("ankisave!speedfocus#");
            });
        """ % field
    text += """</script>"""
    return text
Пример #7
0
def on_field_filter(text, field, filter, context: TemplateRenderContext):
    if filter != 'clickable':
        return text
    if field == "Tags":
        kbd = """
        <kbd onclick="ct_click('{fieldcontent}', '{fieldname}')">
        {fieldcontent}
        </kbd>
        """
        return ''.join([
            kbd.format(fieldname=field[:-1], fieldcontent=fieldcontent)
            for fieldcontent in context.fields()['Tags'].split()
        ])
    kbd = """
<button class="xbutton" onclick="ct_click('{fieldcontent}', '{fieldname}')"><span id = "button-{fieldname}">※</span></button>{fieldcontent}  
"""

    return kbd.format(fieldname=field, fieldcontent=context.fields()[field])
Пример #8
0
def on_card_did_render(output: TemplateRenderOutput,
                       context: TemplateRenderContext):
    # let's uppercase the characters of the front text
    output.question_text = output.question_text.upper()

    # if the note is tagged "easy", show the answer in green
    # otherwise, in red
    if context.note().has_tag("easy"):
        colour = "green"
    else:
        colour = "red"

    output.answer_text += f"<style>.card {{ color: {colour}; }}</style>"
def on_field_filter(text: str, field: str, filter: str,
                    context: TemplateRenderContext) -> str:
    if not filter.startswith("info-"):
        return text

    # generate fields if not yet generated
    if "info_fields" not in context.extra_state:
        context.extra_state["info_fields"] = get_all_fields(context)
    info_fields: Dict[str, Any] = context.extra_state["info_fields"]

    # extract the requested field
    info, field = filter.split("-", maxsplit=1)

    return str(info_fields.get(field, f"Unknown field: {field}"))
Пример #10
0
 def ephemeral_card_for_rendering(self) -> Card:
     card = Card(self.col)
     card.ord = self.ord
     card.did = 1
     template = copy.copy(self.current_template())
     # may differ in cloze case
     template["ord"] = card.ord
     output = TemplateRenderContext.from_card_layout(
         self.note,
         card,
         notetype=self.model,
         template=template,
         fill_empty=self.fill_empty_action_toggled,
     ).render()
     card.set_render_output(output)
     return card
Пример #11
0
    def build_export_context(self):
        print(f"Exporting {self.deck_name} deck")
        for card in get_cards(self.collection, self.deck_name):
            note = self.collection.getNote(card.nid)
            self.css_fragments.append(
                self.collection.models.get(note.mid)['css'])

            rendering = TemplateRenderContext.from_existing_card(
                card, False).render()

            answer_text, images = extract_image_names(rendering.answer_text)
            self.images += images
            self.card_fragments.append(
                self.get_card_fragment(answer_text, card, note))

        self.collection.close()

        print(f"Exporting {len(self.card_fragments)} cards")
Пример #12
0
    def _renderQA(self,
                  data: QAData,
                  qfmt: Optional[str] = None,
                  afmt: Optional[str] = None) -> Dict[str, Union[str, int]]:
        # extract info from data
        split_fields = splitFields(data[6])
        card_ord = data[4]
        model = self.models.get(data[2])
        if model["type"] == MODEL_STD:
            template = model["tmpls"][data[4]]
        else:
            template = model["tmpls"][0]
        flag = data[7]
        deck_id = data[3]
        card_id = data[0]
        tags = data[5]
        qfmt = qfmt or template["qfmt"]
        afmt = afmt or template["afmt"]

        # create map of field names -> field content
        fields: Dict[str, str] = {}
        for (name, (idx, conf)) in list(self.models.fieldMap(model).items()):
            fields[name] = split_fields[idx]

        # add special fields
        fields["Tags"] = tags.strip()
        fields["Type"] = model["name"]
        fields["Deck"] = self.decks.name(deck_id)
        fields["Subdeck"] = fields["Deck"].split("::")[-1]
        fields["Card"] = template["name"]
        fields["CardFlag"] = self._flagNameFromCardFlags(flag)
        fields["c%d" % (card_ord + 1)] = "1"

        # legacy hook
        fields = runFilter("mungeFields", fields, model, data, self)

        ctx = TemplateRenderContext(self, data, fields)

        # render fields. if any custom filters are encountered,
        # the field_filter hook will be called.
        try:
            qtext, atext = render_card(self, qfmt, afmt, ctx)
        except anki.rsbackend.BackendException as e:
            errmsg = _("Card template has a problem:") + f"<br>{e}"
            qtext = errmsg
            atext = errmsg

        # avoid showing the user a confusing blank card if they've
        # forgotten to add a cloze deletion
        if model["type"] == MODEL_CLOZE:
            if not self.models._availClozeOrds(model, data[6], False):
                qtext = (qtext + "<p>" + _(
                    "Please edit this note and add some cloze deletions. (%s)")
                         % ("<a href=%s#cloze>%s</a>" %
                            (HELP_SITE, _("help"))))

        # allow add-ons to modify the generated result
        (qtext, atext) = hooks.card_did_render((qtext, atext), ctx)

        # legacy hook
        qtext = runFilter("mungeQA", qtext, "q", fields, model, data, self)
        atext = runFilter("mungeQA", atext, "a", fields, model, data, self)

        return dict(q=qtext, a=atext, id=card_id)
Пример #13
0
def get_all_fields(context: TemplateRenderContext) -> Dict[str, Any]:
    addInfo: Dict[str, Any] = {}
    card = context.card()

    # note: card will no longer be none, and this if statement can be removed
    if card is not None:
        r = mw.reviewer
        d = mw.col
        cs = CardStats(d, r.card)

        if card.odid:
            conf = d.decks.confForDid(card.odid)
        else:
            conf = d.decks.confForDid(card.did)

        (first, last, cnt, total) = mw.col.db.first(
            "select min(id), max(id), count(), sum(time)/1000 from revlog where cid = :id",
            id=card.id,
        )

        if cnt:
            addInfo["FirstReview"] = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(first / 1000)
            )
            addInfo["LastReview"] = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(last / 1000)
            )

            # https://docs.python.org/2/library/datetime.html  #todo
            addInfo["TimeAvg"] = timefn(total / float(cnt))
            addInfo["TimeTotal"] = timefn(total)

            cOverdueIvl = valueForOverdue(card.odid, card.queue, card.type, card.due, d)
            if cOverdueIvl:
                addInfo["overdue_fmt"] = (
                    str(cOverdueIvl) + " day" + ("s" if cOverdueIvl > 1 else "")
                )
                addInfo["overdue_days"] = str(cOverdueIvl)

        addInfo["external_file_link"] = external_file_link(card, context.note_type())

        addInfo["Ord"] = card.ord
        addInfo["Did"] = card.did
        addInfo["Due"] = card.due
        addInfo["Id"] = card.id
        addInfo["Ivl"] = card.ivl
        addInfo["Queue"] = card.queue
        addInfo["Reviews"] = card.reps
        addInfo["Lapses"] = card.lapses
        addInfo["Type"] = card.type
        addInfo["Nid"] = card.nid
        addInfo["Mod"] = time.strftime("%Y-%m-%d", time.localtime(card.mod))
        addInfo["Usn"] = card.usn
        addInfo["Factor"] = card.factor
        addInfo["Ease"] = int(card.factor / 10)

        addInfo["Review?"] = "Review" if card.type == 2 else ""
        addInfo["New?"] = "New" if card.type == 0 else ""
        addInfo["Learning?"] = "Learning" if card.type == 1 else ""
        addInfo["TodayLearning?"] = (
            "Learning" if card.type == 1 and card.queue == 1 else ""
        )
        addInfo["DayLearning?"] = (
            "Learning" if card.type == 1 and card.queue == 3 else ""
        )

        addInfo["Young"] = "Young" if card.type == 2 and card.ivl < 21 else ""
        addInfo["Mature"] = "Mature" if card.type == 2 and card.ivl > 20 else ""

        if gc("make_deck_options_available", False):
            addInfo["Options_Group_ID"] = conf["id"]
            addInfo["Options_Group_Name"] = conf["name"]
            addInfo["Ignore_answer_times_longer_than"] = conf["maxTaken"]
            addInfo["Show_answer_time"] = conf["timer"]
            addInfo["Auto_play_audio"] = conf["autoplay"]
            addInfo["When_answer_shown_replay_q"] = conf["replayq"]
            addInfo["is_filtered_deck"] = conf["dyn"]
            addInfo["deck_usn"] = conf["usn"]
            addInfo["deck_mod_time"] = conf["mod"]
            addInfo["new__steps_in_minutes"] = conf["new"]["delays"]
            addInfo["new__order_of_new_cards"] = conf["new"]["order"]
            addInfo["new__cards_per_day"] = conf["new"]["perDay"]
            addInfo["graduating_interval"] = conf["new"]["ints"][0]
            addInfo["easy_interval"] = conf["new"]["ints"][1]
            addInfo["Starting_ease"] = int(conf["new"]["initialFactor"] / 10)
            addInfo["bury_related_new_cards"] = conf["new"]["bury"]
            addInfo["MaxiumReviewsPerDay"] = conf["rev"]["perDay"]
            addInfo["EasyBonus"] = int(100 * conf["rev"]["ease4"])
            addInfo["IntervalModifier"] = int(100 * conf["rev"]["ivlFct"])
            addInfo["MaximumInterval"] = conf["rev"]["maxIvl"]
            addInfo["bur_related_reviews_until_next_day"] = conf["rev"]["bury"]
            addInfo["lapse_learning_steps"] = conf["lapse"]["delays"]
            addInfo["lapse_new_ivl"] = int(100 * conf["lapse"]["mult"])
            addInfo["lapse_min_ivl"] = conf["lapse"]["minInt"]
            addInfo["lapse_leech_threshold"] = conf["lapse"]["leechFails"]
            addInfo["lapse_leech_action"] = conf["lapse"]["leechAction"]
            addInfo["Date_Created"] = time.strftime(
                "%Y-%m-%d %H:%M:%S", time.localtime(card.nid / 1000)
            )

        # add your additional fields here

    # for debugging quickly
    tt = " <table>" + "\n"
    for k in sorted(addInfo.keys()):
        tt += '<tr><td align="left">%s </td><td align="left">  %s  </td></tr> +\n' % (
            k,
            addInfo[k],
        )
    tt += " </table>" + "\n"
    addInfo["allfields"] = tt

    return addInfo
Пример #14
0
def note_creation(ctx: TemplateRenderContext) -> str:
    # convert millisecond timestamp to seconds
    note_creation_unix_timestamp = ctx.note().id // 1000
    # convert timestamp to a human years-months-days
    return time.strftime("%Y-%m-%d", time.localtime(note_creation_unix_timestamp))
Пример #15
0
def card_interval(ctx: TemplateRenderContext) -> str:
    return str(ctx.card().ivl)
Пример #16
0
def on_card_did_render(output: TemplateRenderOutput, context: TemplateRenderContext):

    #TODO lvl == 0; review == 0 -> show word translation
    # f = open("/Users/ihor/Library/Application Support/Anki2/addons21/2055492100/log.txt", "a")
    # f.write(str(context.card()))
    # f.write("\n")
    # f.write(str(context.note()))
    # f.write("\n")
    # f.write(str(context.fields()))
    # f.write("\n")
    # f.write(str(context.fields()))
    # f.write("\n")
    # f.write(str(context.fields()["translation"]))
    # f.write("\n")
    # f.write(str(output))
    # f.write("\n")
    # f.close()
    # word {
    # debug {

    # output.question_text += f"<style>#debug {{ display: block; }}</style>"
    #
    # if context.card().did == gc("deckId") and context.card().ivl < 5 and context.card().reps > 5:
    #     output.question_text += f"<style>#word {{ color: red; }}</style>"
    #lapses=0

    # HIGHLIGHT EASY CARDS
    if context.card().did == gc("deckId") and context.card().lapses < 2 and context.card().reps > 6:
        # output.question_text += f"<style>.easy {{ display: block !important; }}</style>"
        output.question_text += f"<style>body {{ background-color: #7cedff21 !important; }}</style>"

    # HIDE GIF FOR CARDS WITH SOME PROGRESS
    if context.card().did == gc("deckId") and context.card().reps > 10 and context.card().ivl <= 10:
        output.question_text += f"<style>#gif {{ display: none; }}</style>"

    # SHOW TRANSLATION FOR NEW CARDS
    if context.card().did == gc("deckId") and context.card().ivl == 0 and context.card().reps == 0:
        output.question_text += f"<style>.hint {{ display: block; }}</style>"

    #FILL BLANK FOR MORE MATURE CARDS
    if context.card().did == gc("filteredDeckId") and context.card().ivl > 5:
        output.question_text += f"<style>#context, #word {{ display: none; }}</style>"''
        output.question_text += f"<style>#fill-blank-block, .hint.word, #gif {{ display: block; }}</style>"''
        # add original clip audio to back
        output.answer_av_tags = [output.question_av_tags[0]]
        # clear front
        output.question_av_tags = []

    if (context.card().did == gc("deckId") or context.card().did == 1606067545027) and context.card().ivl > 10:
        output.question_text += f"<style>#gif, #context {{ display: none; }}</style>"
        output.question_av_tags = [output.answer_av_tags[0]]