def from_card(cls, card: Card) -> "CardInfo": return cls( card.id, question=strip_html(card.question()), answer=strip_html(card.answer()), due=card.due, reviews=get_card_reviews(card.id), )
def typeAnsAnswerFilter(self, buf: str) -> str: if not self.typeCorrect: return re.sub(self.typeAnsPat, "", buf) origSize = len(buf) buf = buf.replace("<hr id=answer>", "") hadHR = len(buf) != origSize # munge correct value cor = self.mw.col.media.strip(self.typeCorrect) cor = re.sub("(\n|<br ?/?>|</?div>)+", " ", cor) cor = strip_html(cor) # ensure we don't chomp multiple whitespace cor = cor.replace(" ", " ") cor = html.unescape(cor) cor = cor.replace("\xa0", " ") cor = cor.strip() given = self.typedAnswer # compare with typed answer res = self.correct(given, cor, showBad=False) # and update the type answer area def repl(match: Match) -> str: # can't pass a string in directly, and can't use re.escape as it # escapes too much s = """ <span style="font-family: '{}'; font-size: {}px">{}</span>""".format( self.typeFont, self.typeSize, res, ) if hadHR: # a hack to ensure the q/a separator falls before the answer # comparison when user is using {{FrontSide}} s = f"<hr id=answer>{s}" return s return re.sub(self.typeAnsPat, repl, buf)
def stripHTML(self, text: str) -> str: # very basic conversion to text s = text s = re.sub(r"(?i)<(br ?/?|div|p)>", " ", s) s = re.sub(r"\[sound:[^]]+\]", "", s) s = strip_html(s) s = re.sub(r"[ \n\t]+", " ", s) s = s.strip() return s
def get_reschedule_message(reschedule: Reschedule): question = strip_html(reschedule.sibling.question()) today = get_today() interval = reschedule.sibling.ivl return ( f"Sibling: {question} (interval: <b>{interval}</b> days)<br>" f"Rescheduling: <b>{reschedule.old_absolute_due - today}</b> → " f"<span style='color: crimson'><b>{reschedule.new_absolute_due - today}</b></span> " f"days after today")
def test_templates(): col = getEmptyCol() m = col.models.current() mm = col.models t = mm.new_template("Reverse") t["qfmt"] = "{{Back}}" t["afmt"] = "{{Front}}" mm.add_template(m, t) mm.save(m) note = col.newNote() note["Front"] = "1" note["Back"] = "2" col.addNote(note) assert col.card_count() == 2 (c, c2) = note.cards() # first card should have first ord assert c.ord == 0 assert c2.ord == 1 # switch templates col.models.reposition_template(m, c.template(), 1) col.models.update(m) c.load() c2.load() assert c.ord == 1 assert c2.ord == 0 # removing a template should delete its cards col.models.remove_template(m, m["tmpls"][0]) col.models.update(m) assert col.card_count() == 1 # and should have updated the other cards' ordinals c = note.cards()[0] assert c.ord == 0 assert strip_html(c.question()) == "1" # it shouldn't be possible to orphan notes by removing templates t = mm.new_template("template name") t["qfmt"] = "{{Front}}2" mm.add_template(m, t) col.models.remove_template(m, m["tmpls"][0]) col.models.update(m) assert ( col.db.scalar( "select count() from cards where nid not in (select id from notes)" ) == 0 )