Created
August 16, 2019 10:07
-
-
Save Juddd/590d7154368b89dc0df8adefbc7ab02b to your computer and use it in GitHub Desktop.
Add-on for Anki 2.1 to supplement the Mini Format Pack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from anki.hooks import addHook | |
import os.path | |
import json | |
import re | |
def escape_html_chars(s): | |
html_escape_table = { | |
"&": "&", | |
'"': """, | |
"'": "'", | |
">": ">", | |
"<": "<", | |
"\n":"<br>" | |
} | |
result = "".join(html_escape_table.get(c, c) for c in s) | |
return result | |
def wrap_in_tags(editor, tag, class_name=None): | |
""" | |
Wrap selected text in a tag, optionally giving it a class. | |
""" | |
selection = editor.web.selectedText() | |
if not selection: | |
return | |
selection = escape_html_chars(selection) | |
# print("before1:",repr(selection)) | |
# selection = selection.replace("\n", "<br>") | |
# print("after1:", repr(selection)) | |
tag_string_begin = ("<{0} class='{1}'>".format(tag, class_name) if | |
class_name else "<{0}>".format(tag)) | |
tag_string_end = "</{0}>".format(tag) | |
html = editor.note.fields[editor.currentField] | |
if "<li><br /></li>" in html: | |
# an empty list means trouble, because somehow Anki will also make the | |
# line in which we want to put a <code> tag a list if we continue | |
replacement = tag_string_begin + selection + tag_string_end | |
editor.web.eval("document.execCommand('insertHTML', false, %s);" | |
% json.dumps(replacement)) | |
editor.web.setFocus() | |
field=editor.currentField | |
editor.web.eval("focusField(%d);" % field) | |
def cb(): | |
html_after = editor.note.fields[field] | |
if html_after != html: | |
# you're in luck! | |
return | |
else: | |
# nothing happened :( this is a quirk that has to do with <code> tags following <div> tags | |
return | |
editor.saveNow(cb) | |
# Due to a bug in Anki or BeautifulSoup, we cannot use a simple | |
# wrap operation like with <a>. So this is a very hackish way of making | |
# sure that a <code> tag may precede or follow a <div> and that the tag | |
# won't eat the character immediately preceding or following it | |
pattern = "@%*!" | |
len_p = len(pattern) | |
# first, wrap the selection up in a pattern that the user is unlikely | |
# to use in its own cards | |
editor.web.eval("wrap('{0}', '{1}')".format(pattern, pattern[::-1])) | |
# focus the field, so that changes are saved | |
# this causes the cursor to go to the end of the field | |
editor.web.setFocus() | |
field = editor.currentField | |
editor.web.eval("focusField(%d);" % field) | |
# print("selection:", repr(selection)) | |
# if tag == "blockquote": | |
# selection = selection.replace("\n", "<br>") | |
def cb1(): | |
html = editor.note.fields[field] | |
begin = html.find(pattern) | |
end = html.find(pattern[::-1], begin) | |
html = (html[:begin] + tag_string_begin + selection + tag_string_end + | |
html[end + len_p:]) | |
# if tag == "blockquote": | |
# html.replace() | |
# delete the current HTML and replace it by our new & improved one | |
editor.note.fields[field] = html | |
# reload the note: this is needed on OS X, because it will otherwise | |
# falsely show that the formatting of the element at the start of | |
# the HTML has spread across the entire note | |
editor.loadNote() | |
# focus the field, so that changes are saved | |
editor.web.setFocus() | |
editor.web.eval("focusField(%d);" % field) | |
editor.saveNow(cb1) | |
def cb2(): | |
editor.web.setFocus() | |
editor.web.eval("focusField(%d);" % field) | |
editor.saveNow(cb2) | |
def delete_tag(editor,pre_fix,post_fix): | |
selection = editor.web.selectedText() | |
if not selection: | |
return | |
selection = escape_html_chars(selection) | |
pattern = "@%*!" | |
html = editor.note.fields[editor.currentField] | |
if "<li><br /></li>" in html: | |
# an empty list means trouble, because somehow Anki will also make the | |
# line in which we want to put a <code> tag a list if we continue | |
replacement = pattern + selection + pattern[::-1] | |
editor.web.eval("document.execCommand('insertHTML', false, %s);" | |
% json.dumps(replacement)) | |
editor.web.setFocus() | |
field = editor.currentField | |
editor.web.eval("focusField(%d);" % field) | |
def cb(): | |
html_after = editor.note.fields[field] | |
if html_after != html: | |
# you're in luck! | |
return | |
else: | |
# nothing happened :( this is a quirk that has to do with <code> tags following <div> tags | |
return | |
editor.saveNow(cb) | |
editor.web.eval("wrap('{0}', '{1}')".format(pattern, pattern[::-1])) | |
# focus the field, so that changes are saved | |
# this causes the cursor to go to the end of the field | |
editor.web.setFocus() | |
field = editor.currentField | |
editor.web.eval("focusField(%d);" % field) | |
def cb1(): | |
html = editor.note.fields[field] | |
# print("before:",html) | |
# print("first:",f'{pre_fix}{re.escape(pattern)}') | |
# print("second:",f'{re.escape(pattern[::-1])}{post_fix}') | |
# print("delete_before:",html) | |
#删除pattern[::-1]后面的<br> | |
html = re.sub(f'(?<={re.escape(pattern[::-1])})(<br>)+','',html) | |
html = re.sub(f'{pre_fix}{re.escape(pattern)}','',html) | |
html = re.sub(f'{re.escape(pattern[::-1])}{post_fix}','',html) | |
# html = html.replace(pre_fix+pattern,'').replace(pattern[::-1]+post_fix,'') | |
# print("delete_after:", html) | |
# delete the current HTML and replace it by our new & improved one | |
editor.note.fields[field] = html | |
# reload the note: this is needed on OS X, because it will otherwise | |
# falsely show that the formatting of the element at the start of | |
# the HTML has spread across the entire note | |
editor.loadNote() | |
# focus the field, so that changes are saved | |
editor.web.setFocus() | |
editor.web.eval("focusField(%d);" % field) | |
editor.saveNow(cb1) | |
def cb2(): | |
editor.web.setFocus() | |
editor.web.eval("focusField(%d);" % field) | |
editor.saveNow(cb2) | |
def wrap_pre(editor): | |
wrap_in_tags(editor,"pre","myCodeClass") | |
def wrap_code(editor): | |
wrap_in_tags(editor,"code","myCodeClass") | |
def wrap_blockquote(editor): | |
wrap_in_tags(editor,"blockquote") | |
def wrap_kbd(editor): | |
wrap_in_tags(editor, "kbd") | |
def delete_pre(editor): | |
delete_tag(editor,'<pre.+?','</pre>') | |
def delete_blockquote(editor): | |
delete_tag(editor, '<blockquote>', '</blockquote>') | |
def addMyButton(buttons, editor): | |
editor._links['button_wrap_pre'] = wrap_pre | |
editor._links['button_wrap_code'] = wrap_code | |
editor._links['button_wrap_blockquote'] = wrap_blockquote | |
editor._links['button_delete_pre'] = delete_pre | |
editor._links['button_delete_blockquote'] = delete_blockquote | |
editor._links['button_wrap_kbd'] = wrap_kbd | |
[buttons.remove(i) for i in buttons if "Insert code block (ctrl+.)" in i] | |
return buttons + [editor._addButton(os.path.join(os.path.dirname(__file__),"icons\\pre.png"),"button_wrap_pre","Add pre tag for selected text"), | |
editor._addButton(os.path.join(os.path.dirname(__file__), "icons\\delete_pre.png"),"button_delete_pre", "Delete pre tag for selected text"), | |
editor._addButton(os.path.join(os.path.dirname(__file__),"icons\\code.png"), "button_wrap_code", "Add inline tag for selected text"), | |
editor._addButton(os.path.join(os.path.dirname(__file__),"icons\\blockquote.png"), "button_wrap_blockquote", "Add blockquote tag for selected text"), | |
editor._addButton(os.path.join(os.path.dirname(__file__),"icons\\delete_blockquote.png"), "button_delete_blockquote", "Delete blockquote tag for selected text"), | |
editor._addButton(os.path.join(os.path.dirname(__file__),"icons\\keyboard.png"), "button_wrap_kbd", "Add kbd tag for selected text")] | |
addHook("setupEditorButtons", addMyButton) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment