template_parser: Add parsing support for self closing tags as per HTML5.

In this commit we add support for some tags which are also called
void-elements according to
http://w3c.github.io/html/syntax.html#void-elements to be parsed by
our template parser and get tagged as singleton_html_tags.

Fixes: #8387.
This commit is contained in:
Aditya Bansal 2018-02-16 02:46:40 +05:30 committed by showell
parent 271cfd4d7a
commit 6fce1d7834
9 changed files with 46 additions and 18 deletions

View File

@ -7,7 +7,7 @@
<p class="hotspot-description">{{description}}</p>
</div>
<div class="hotspot-popover-bottom">
<img class="hotspot-img" alt=_("hotspot illustration") src="{{img}}"></img>
<img class="hotspot-img" alt=_("hotspot illustration") src="{{img}}">
<button class="hotspot-confirm">{{t 'Got it!' }}</button>
</div>
</div>

View File

@ -1,7 +1,7 @@
{{#with realm_domain}}
<tr>
<td class="domain">{{domain}}</td>
<td><input type="checkbox" class="allow-subdomains" {{#if allow_subdomains}}checked{{/if}}></input></td>
<td><input type="checkbox" class="allow-subdomains" {{#if allow_subdomains}}checked{{/if}}></td>
<td><button class="button btn-danger small rounded delete_realm_domain">{{t "Remove" }}</button></td>
</tr>
{{/with}}

View File

@ -11,7 +11,7 @@
<div class="settings-section-title">{{t "Add new default stream" }}</div>
<div class="inline-block" id="default_stream_inputs">
<label for="default_stream_name">{{t "Stream name" }}</label>
<input class="create_default_stream" type="text" placeholder="{{t "Stream name" }}" name="stream_name" autocomplete="off" aria-label="{{t "Stream name" }}"></input>
<input class="create_default_stream" type="text" placeholder="{{t "Stream name" }}" name="stream_name" autocomplete="off" aria-label="{{t "Stream name" }}">
</div>
<div class="inline-block">
<button type="submit" id="do_submit_stream" class="button rounded sea-green">{{t "Add stream" }}</button>

View File

@ -14,8 +14,8 @@
</tbody>
<tfoot>
<tr id="add-realm-domain-widget">
<td><input type="text" class="new-realm-domain" placeholder="acme.com"></input></td>
<td><input type="checkbox" class="new-realm-domain-allow-subdomains"></input></td>
<td><input type="text" class="new-realm-domain" placeholder="acme.com"></td>
<td><input type="checkbox" class="new-realm-domain-allow-subdomains"></td>
<td><button type="button" class="button sea-green small rounded" id="submit-add-realm-domain">{{t "Add" }}</button></td>
</tr>
</tfoot>

View File

@ -49,7 +49,7 @@
<p>
Cheers,
<br></br>
<br />
The Zulip Team
</p>
{% endblock %}

View File

@ -517,49 +517,49 @@
<div class="integration-icons">
<a href="/integrations/doc/travis">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/travis.svg" alt="{{ _('Travis logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/travis.svg" alt="{{ _('Travis logo') }}">
<h3 class="integration-name">Travis CI</h3>
<p class="integration-description">See build results immediately</p>
</div>
</a>
<a href="/integrations/doc/github">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/github.svg" alt="{{ _('Github logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/github.svg" alt="{{ _('Github logo') }}">
<h3 class="integration-name">Github</h3>
<p class="integration-description">Track issues and pull requests</p>
</div>
</a>
<a href="/integrations/doc/heroku">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/heroku.svg" alt="{{ _('Heroku logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/heroku.svg" alt="{{ _('Heroku logo') }}">
<h3 class="integration-name">Heroku</h3>
<p class="integration-description">Keep up with deployments</p>
</div>
</a>
<a href="/integrations/doc/zendesk">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/zendesk.svg" alt="{{ _('Zendesk logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/zendesk.svg" alt="{{ _('Zendesk logo') }}">
<h3 class="integration-name">Zendesk</h3>
<p class="integration-description">Receive support tickets and updates</p>
</div>
</a>
<a href="/integrations/doc/jira">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/jira.svg" alt="{{ _('JIRA logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/jira.svg" alt="{{ _('JIRA logo') }}">
<h3 class="integration-name">JIRA</h3>
<p class="integration-description">Monitor project bugs and issues</p>
</div>
</a>
<a href="/integrations/doc/sentry">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/sentry.svg" alt="{{ _('Sentry logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/sentry.svg" alt="{{ _('Sentry logo') }}">
<h3 class="integration-name">Sentry</h3>
<p class="integration-description">See real-time error tracking</p>
</div>
</a>
<a href="/integrations/doc/pagerduty" class="hide-1">
<div class="group">
<img class="integration-logo" src="/static/images/integrations/logos/pagerduty.svg" alt="{{ _('Pagerduty logo') }}"></img>
<img class="integration-logo" src="/static/images/integrations/logos/pagerduty.svg" alt="{{ _('Pagerduty logo') }}">
<h3 class="integration-name">Pagerduty</h3>
<p class="integration-description">Connect to your monitoring systems</p>
</div>

View File

@ -1,4 +1,4 @@
from typing import Callable, List, Optional
from typing import Callable, List, Optional, Text
class TemplateParserException(Exception):
def __init__(self, message):
@ -112,7 +112,7 @@ def tokenize(text):
if is_special_html_tag(s, tag):
kind = 'html_special'
elif s.endswith('/>'):
elif is_self_closing_html_tag(s, tag):
kind = 'html_singleton'
else:
kind = 'html_start'
@ -272,6 +272,24 @@ def is_special_html_tag(s, tag):
# type: (str, str) -> bool
return tag in ['link', 'meta', '!DOCTYPE']
def is_self_closing_html_tag(s: Text, tag: Text) -> bool:
self_closing_tag = tag in [
'area',
'base',
'br',
'col',
'embed',
'hr',
'img',
'input',
'param',
'source',
'track',
'wbr',
]
singleton_tag = s.endswith('/>')
return self_closing_tag or singleton_tag
def is_django_block_tag(tag):
# type: (str) -> bool
return tag in [

View File

@ -515,7 +515,7 @@ def build_custom_checkers(by_lang):
'exclude_line': [('templates/zerver/register.html', 'placeholder="acme"'),
('templates/zerver/register.html', 'placeholder="Acme or Aκμή"'),
('static/templates/settings/realm-domains-modal.handlebars',
'<td><input type="text" class="new-realm-domain" placeholder="acme.com"></input></td>'),
'<td><input type="text" class="new-realm-domain" placeholder="acme.com"></td>'),
("static/templates/user-groups-admin.handlebars",
'<input type="text" name="name" id="user_group_name" placeholder="hamletcharacters" />')],
'exclude': set(["static/templates/settings/emoji-settings-admin.handlebars",
@ -523,11 +523,11 @@ def build_custom_checkers(by_lang):
"static/templates/settings/bot-settings.handlebars",
"templates/zerver/email_log.html"]),
'good_lines': ['<input class="stream-list-filter" type="text" placeholder="{{ _(\'Search streams\') }}" />'],
'bad_lines': ['<input placeholder="foo"></input>']},
'bad_lines': ['<input placeholder="foo">']},
{'pattern': "placeholder='[^{]",
'description': "`placeholder` value should be translatable.",
'good_lines': ['<input class="stream-list-filter" type="text" placeholder="{{ _(\'Search streams\') }}" />'],
'bad_lines': ["<input placeholder='foo'></input>"]},
'bad_lines': ["<input placeholder='foo'>"]},
{'pattern': "aria-label='[^{]",
'description': "`aria-label` value should be translatable.",
'good_lines': ['<button type="button" class="close close-alert-word-status" aria-label="{{t \'Close\' }}">'],

View File

@ -225,6 +225,16 @@ class ParserTest(unittest.TestCase):
self.assertEqual(token.kind, 'html_singleton')
self.assertEqual(token.tag, 'br')
tag = '<input>bla'
token = tokenize(tag)[0]
self.assertEqual(token.kind, 'html_singleton')
self.assertEqual(token.tag, 'input')
tag = '<input />bla'
token = tokenize(tag)[0]
self.assertEqual(token.kind, 'html_singleton')
self.assertEqual(token.tag, 'input')
tag = '</a>bla'
token = tokenize(tag)[0]
self.assertEqual(token.kind, 'html_end')