| @@ -460,7 +460,7 @@ class Tokenizer(object): | |||
| self._handle_tag_close_open(data, tokens.TagCloseOpen) | |||
| self._context = contexts.TAG_BODY | |||
| if is_single_only(self._stack[1].text): | |||
| return self._handle_single_only_tag() | |||
| return self._handle_single_only_tag_end() | |||
| if is_parsable(self._stack[1].text): | |||
| return self._parse(push=False) | |||
| return self._handle_blacklisted_tag() | |||
| @@ -598,12 +598,26 @@ class Tokenizer(object): | |||
| self._emit(tokens.TagCloseClose()) | |||
| return self._pop() | |||
| def _handle_single_only_tag(self): | |||
| def _handle_invalid_tag_start(self): | |||
| """Handle the (possible) start of an implicitly closing single tag.""" | |||
| reset = self._head + 1 | |||
| self._head += 2 | |||
| try: | |||
| if not is_single_only(self.tag_splitter.split(self._read())[0]): | |||
| raise BadRoute() | |||
| tag = self._really_parse_tag() | |||
| except BadRoute: | |||
| self._head = reset | |||
| self._emit_text("</") | |||
| else: | |||
| tag[0].invalid = True # Set flag of TagOpenOpen | |||
| self._emit_all(tag) | |||
| def _handle_single_only_tag_end(self): | |||
| """Handle the end of an implicitly closing single-only HTML tag.""" | |||
| padding = self._stack.pop().padding | |||
| token = tokens.TagCloseSelfclose(padding=padding, implicit=True) | |||
| self._stack.append(token) | |||
| self._head -= 1 | |||
| self._emit(tokens.TagCloseSelfclose(padding=padding, implicit=True)) | |||
| self._head -= 1 # Offset displacement done by _handle_tag_close_open | |||
| return self._pop() | |||
| def _handle_single_tag_end(self): | |||
| @@ -691,13 +705,14 @@ class Tokenizer(object): | |||
| unsafe = (contexts.TEMPLATE_NAME | contexts.WIKILINK_TITLE | | |||
| contexts.TEMPLATE_PARAM_KEY | contexts.ARGUMENT_NAME | | |||
| contexts.TAG_CLOSE) | |||
| double_unsafe = (contexts.TEMPLATE_PARAM_KEY | contexts.TAG_CLOSE) | |||
| if push: | |||
| self._push(context) | |||
| while True: | |||
| this = self._read() | |||
| if self._context & unsafe: | |||
| if not self._verify_safe(this): | |||
| if self._context & double_fail: | |||
| if self._context & double_unsafe: | |||
| self._pop() | |||
| self._fail_route() | |||
| if this not in self.MARKERS: | |||
| @@ -755,8 +770,11 @@ class Tokenizer(object): | |||
| self._parse_comment() | |||
| else: | |||
| self._emit_text(this) | |||
| elif this == "<" and next == "/" and self._context & contexts.TAG_BODY: | |||
| self._handle_tag_open_close() | |||
| elif this == "<" and next == "/" and self._read(2) is not self.END: | |||
| if self._context & contexts.TAG_BODY: | |||
| self._handle_tag_open_close() | |||
| else: | |||
| self._handle_invalid_tag_start() | |||
| elif this == "<": | |||
| if not self._context & contexts.TAG_CLOSE and self._can_recurse(): | |||
| self._parse_tag() | |||
| @@ -498,7 +498,7 @@ output: [Text(text="foo</li>bar"), TemplateOpen(), Text(text="baz"), TemplateClo | |||
| name: single_only_open_close | |||
| label: a tag that can only be single; both an open and a close tag | |||
| input: "foo<br>bar{{baz}}</br>" | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True), Text(text="br"), TagCloseSelfclose(padding="", implicit=True), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose(), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding="")] | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True), Text(text="br"), TagCloseSelfclose(padding="", implicit=True), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose(), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding="", implicit=True)] | |||
| --- | |||
| @@ -519,11 +519,11 @@ output: [Text(text="foo"), TagOpenOpen(showtag=True), Text(text="br"), TagCloseS | |||
| name: single_only_close | |||
| label: a tag that can only be single; just a close tag | |||
| input: "foo</br>bar{{baz}}" | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding=""), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose()] | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding="", implicit=True), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose()] | |||
| --- | |||
| name: single_only_double | |||
| label: a tag that can only be single; a tag with backslashes at the beginning and end | |||
| input: "foo</br/>bar{{baz}}" | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding="", implicit=True), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose()] | |||
| output: [Text(text="foo"), TagOpenOpen(showtag=True, invalid=True), Text(text="br"), TagCloseSelfclose(padding=""), Text(text="bar"), TemplateOpen(), Text(text="baz"), TemplateClose()] | |||