-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathiconfonts.py
239 lines (181 loc) · 8.25 KB
/
iconfonts.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
"""
IconFonts Extension for Python-Markdown
========================================
Version: 2.1
Description:
Use this extension to display icon font icons in python markdown. Just add the css necessary for your font and add this extension.
Features:
- Support FontAwesome or Bootstrap 3/Glyphicons or both at the same time!
- Allow users to specify additional modifiers, like 'fa-2x' from FontAwesome
- Force users to use pre-defined classes to style their icons instead of
allowing them to specify styles themselves
- Allow users to specify additional classes, like 'red'
Syntax:
- Accepts a-z, A-Z, 0-9, _ (underscore), and - (hypen)
- Uses HTML Entity like syntax
&icon-html5;
&icon-css3;
&icon-my-icon;
&icon-html5:2x;
&icon-quote:3x,muted;
&icon-spinner:large,spin;
Example Markdown:
I love &icon-html5; and &icon-css3;
&icon-spinner:large,spin; Sorry we have to load...
&icon-spinner:large,spin:red; Sorry we have to load...
Output:
I love <i aria-hidden="true" class="icon-html5"></i> and <i aria-hidden="true" class="icon-css3"></i>
<i aria-hidden="true" class="icon-spinner icon-large icon-spin"></i> Sorry we have to load...
<i aria-hidden="true" class="icon-spinner icon-large icon-spin red"></i> Sorry we have to load...
Installation:
Just drop it in the extensions folder of the markdown package. (markdown/extensions).
Also check out: https://pythonhosted.org/Markdown/extensions/index.html
Usage/Setup:
Default Prefix is "icon-":
In a Django Template:
{{ textmd|markdown:"safe,iconfonts" }}
In Python:
>>> text = '&icon-html5;'
>>> md = markdown.Markdown(extensions=['iconfonts'])
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="icon-html5"></i>'
Use a custom Prefix:
In a Django Template:
{{ textmd|markdown:"safe,iconfonts(prefix=mypref-)" }}
In Python:
>>> text = '&mypref-html5;'
>>> md = markdown.Markdown(extensions=['iconfonts(prefix=mypref-)'])
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="mypref-html5"></i>'
Use no prefix (just in case you couldn't figure it out :P):
In a Django Template:
{{ textmd|markdown:"safe,iconfonts(prefix=)" }}
In Python:
>>> text = '&html5;'
>>> md = markdown.Markdown(extensions=['iconfonts(prefix=)'])
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="html5"></i>'
Use the base option which allows for Bootstrap 3 and FontAwesome 4:
In Python:
>>> text = '&fa-html5;'
>>> md = markdown.Markdown(extensions=['iconfonts(prefix=fa-, base=fa)'])
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="fa icon-html5"></i>'
>>> text = '&glyphicon-remove;'
>>> md = markdown.Markdown(extensions=['iconfonts(prefix=glyphicon-, base=glyphicon)'])
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="glyphicon glyphicon-remove"></i>'
Or support both Bootstrap 3/Glyphicons and FontAwesome 4 at the same time:
In Python:
>>> text = '&fa-html5; &glyphicon-remove;''
>>> md = markdown.Markdown(extensions=['iconfonts'],
>>> extension_configs={
>>> 'fa': 'fa',
>>> 'glyphicon': 'glyphicon',
>>> })
>>> converted_text = md.convert(text)
'<i aria-hidden="true" class="fa fa-html5"></i>'
'<i aria-hidden="true" class="glyphicon glyphicon-remove"></i>'
Copyright 2014 [Eric Eastwood](http://ericeastwood.com/)
Use it in any personal or commercial project you want.
"""
import markdown
import re
class IconFontsExtension(markdown.Extension):
""" IconFonts Extension for Python-Markdown. """
def __init__(self, *args, **kwargs):
# define default configs
self.config = {
'prefix': ['icon-', "Custom class prefix."],
'base': ['', "Base class added to each icon"],
'prefix_base_pairs': [{}, "Prefix/base pairs"],
}
# Override defaults with user settings
# This is legacy code for versions older than 2.5.1.
if len(args):
for key, value in args[0]:
# convert strings to booleans
if value == 'True':
value = True
if value == 'False':
value = False
if value == 'None':
value = None
self.setConfig(key, value)
# Override defaults with user settings
# This is not legacy code but is used instead of the super call below because we have to support the legacy version
if hasattr(self, 'setConfigs'):
self.setConfigs(kwargs)
# We can use this instead of the legacy for loop to set the config above
#super(IconFontsExtension, self).__init__(*args, **kwargs)
def add_inline(self, md, name, klass, re, config):
pattern = klass(re, md, config)
md.inlinePatterns.add(name, pattern, "<reference")
def extendMarkdown(self, md, md_globals):
config = self.getConfigs()
#print("config" + str(config))
# Change prefix to what they had the in the config
# Capture "&icon-namehere;" or "&icon-namehere:2x;" or "&icon-namehere:2x,muted;"
# https://www.debuggex.com/r/weK9ehGY0HG6uKrg
prefix = config['prefix']
icon_regex_start = r'&'
icon_regex_end = r'(?P<name>[a-zA-Z0-9-]+)(:(?P<mod>[a-zA-Z0-9-]+(,[a-zA-Z0-9-]+)*)?(:(?P<user_mod>[a-zA-Z0-9-]+(,[a-zA-Z0-9-]+)*)?)?)?;'
# ^---------------------^^ ^ ^--------------^ ^ ^ ^ ^--------------^ ^ ^ ^
# | +-------------------------------------+ | +------------------------------------------+ | |
# | +----------------------------------------------+ |
# +------------------------------------------------------------------------------------------+
# This is the full regex we use. Only reason we have pieces above is to easily change the prefix to something custom
icon_regex = ''.join([icon_regex_start, prefix, icon_regex_end])
# Register the global one
self.add_inline(md, 'iconfonts', IconFontsPattern, icon_regex, config)
# Register each of the pairings
for _prefix, _base in config['prefix_base_pairs'].items():
_prefix_base = _prefix if _prefix[-1] != '-' else _prefix[:-1]
icon_regex = ''.join([icon_regex_start, _prefix, icon_regex_end])
self.add_inline(
md, 'iconfonts_{}'.format(_prefix_base),
IconFontsPattern, icon_regex,
{'prefix': _prefix, 'base': _base})
class IconFontsPattern(markdown.inlinepatterns.Pattern):
def __init__(self, pattern, md, config):
# Pass the patterna and markdown instance
super(IconFontsPattern, self).__init__(pattern, md)
self.config = config
""" Return a <i> element with the necessary classes"""
def handleMatch(self, match):
# The dictionary keys come from named capture groups in the regex
match_dict = match.groupdict()
# Create the <i> element
el = markdown.util.etree.Element("i")
base = self.config['base']
prefix = self.config['prefix']
icon_class_name = match_dict.get("name")
# Mods are modifier classes. The syntax in the markdown is:
# "&icon-namehere:2x;" and with multiple "&icon-spinner:2x,spin;"
mod_classes_string = ""
if match_dict.get("mod"):
# Make a string with each modifier like: "fa-2x fa-spin"
mod_classes_string = ' '.join('{}{}'.format(prefix, c) for c in match_dict.get("mod").split(",") if c)
# User mods are modifier classes that shouldn't be prefixed with
# prefix. The syntax in the markdown is:
# "&icon-namehere::red;" and with multiple "&icon-spinner::red,bold;"
user_mod_classes_string = ""
if match_dict.get("user_mod"):
# Make a string with each modifier like "red bold"
user_mod_classes_string = ' '.join(uc for uc in match_dict.get("user_mod").split(",") if uc)
if prefix != '':
icon_class = '{}{}'.format(prefix, icon_class_name)
else:
icon_class = icon_class_name
# Add the icon classes to the <i> element
classes = '{} {} {} {}'.format(base, icon_class, mod_classes_string, user_mod_classes_string)
# Clean up classes
classes = classes.strip()
classes = re.sub(r'\s{2,}', ' ', classes)
el.set('class', classes)
# This is for accessibility and text-to-speech browsers so they don't try to read it
el.set('aria-hidden', 'true')
return el
# http://pythonhosted.org/Markdown/extensions/api.html#makeextension
def makeExtension(*args, **kwargs):
return IconFontsExtension(*args, **kwargs)