mirror of https://github.com/zulip/zulip.git
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:
parent
271cfd4d7a
commit
6fce1d7834
|
@ -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>
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
<p>
|
||||
Cheers,
|
||||
<br></br>
|
||||
<br />
|
||||
The Zulip Team
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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\' }}">'],
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue