1from __future__ import absolute_import, division, unicode_literals 2 3from . import base 4 5 6class Filter(base.Filter): 7 """Injects ``<meta charset=ENCODING>`` tag into head of document""" 8 def __init__(self, source, encoding): 9 """Creates a Filter 10 11 :arg source: the source token stream 12 13 :arg encoding: the encoding to set 14 15 """ 16 base.Filter.__init__(self, source) 17 self.encoding = encoding 18 19 def __iter__(self): 20 state = "pre_head" 21 meta_found = (self.encoding is None) 22 pending = [] 23 24 for token in base.Filter.__iter__(self): 25 type = token["type"] 26 if type == "StartTag": 27 if token["name"].lower() == "head": 28 state = "in_head" 29 30 elif type == "EmptyTag": 31 if token["name"].lower() == "meta": 32 # replace charset with actual encoding 33 has_http_equiv_content_type = False 34 for (namespace, name), value in token["data"].items(): 35 if namespace is not None: 36 continue 37 elif name.lower() == 'charset': 38 token["data"][(namespace, name)] = self.encoding 39 meta_found = True 40 break 41 elif name == 'http-equiv' and value.lower() == 'content-type': 42 has_http_equiv_content_type = True 43 else: 44 if has_http_equiv_content_type and (None, "content") in token["data"]: 45 token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding 46 meta_found = True 47 48 elif token["name"].lower() == "head" and not meta_found: 49 # insert meta into empty head 50 yield {"type": "StartTag", "name": "head", 51 "data": token["data"]} 52 yield {"type": "EmptyTag", "name": "meta", 53 "data": {(None, "charset"): self.encoding}} 54 yield {"type": "EndTag", "name": "head"} 55 meta_found = True 56 continue 57 58 elif type == "EndTag": 59 if token["name"].lower() == "head" and pending: 60 # insert meta into head (if necessary) and flush pending queue 61 yield pending.pop(0) 62 if not meta_found: 63 yield {"type": "EmptyTag", "name": "meta", 64 "data": {(None, "charset"): self.encoding}} 65 while pending: 66 yield pending.pop(0) 67 meta_found = True 68 state = "post_head" 69 70 if state == "in_head": 71 pending.append(token) 72 else: 73 yield token 74