Commit e2cc437c496b059418a461d0b3cfb54fbf33623b
1 parent
0e84be58
Exists in
master
and in
5 other branches
passado as opções de editar, deletar e criar uma enquete para modal que são cham…
…ados no topico #116, #117, #77, #115
Showing
13 changed files
with
210 additions
and
69 deletions
Show diff stats
courses/templates/subject/form_view_teacher.html
1 | -{% load static i18n list_topic_foruns %} | |
1 | +{% load static i18n list_topic_foruns%} | |
2 | 2 | |
3 | 3 | {% block javascript %} |
4 | 4 | <script type="text/javascript" src="{% static 'js/forum.js' %}"></script> |
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | <ul> |
55 | 55 | <li><i class="material-icons">description</i> <a href="#" data-toggle="modal" data-target="#ActivityModal">Activitie 1</a></li> |
56 | 56 | <li><i class="material-icons">list</i> <a href="#" data-toggle="modal" data-target="#forumModal">Forum</a></li> |
57 | + {% list_topic_poll request topic %} | |
57 | 58 | </ul> |
58 | 59 | |
59 | 60 | |
... | ... | @@ -426,7 +427,7 @@ |
426 | 427 | </div> |
427 | 428 | <div class="modal-body"> |
428 | 429 | <form class="form-horizontal"> |
429 | - | |
430 | + | |
430 | 431 | <fieldset> |
431 | 432 | <legend>Atividade Proposta</legend> |
432 | 433 | <div class="form-group is-empty"> |
... | ... | @@ -660,4 +661,4 @@ |
660 | 661 | </div> |
661 | 662 | </div> |
662 | 663 | </div> |
663 | -</div> | |
664 | 664 | \ No newline at end of file |
665 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,12 @@ |
1 | +{% load static i18n %} | |
2 | + | |
3 | +<script src="{% static 'js/modals_requisitions.js'%}"></script> | |
4 | +<script src="{% static 'js/modal_poll.js'%}"></script> | |
5 | + | |
6 | +{% for poll in polls %} | |
7 | + <li id="poll_{{poll.slug}}"><i class="material-icons">poll</i> <a href="javascript:get('{% url 'course:poll:update_poll' poll.slug %}','#poll','#modal_poll');">{{ poll.name }}</a><a href="javascript:get('{% url 'course:poll:delete_poll' poll.slug %}','#poll','#modal_poll');"><span class="glyphicon glyphicon-remove"></span></a></li> | |
8 | +{% endfor %} | |
9 | +<button class="btn btn-primary btn-raised" onclick="javascript:get('{% url 'course:poll:create_poll' topic.slug%}','#poll','#modal_poll');">{% trans '+ Create Poll' %}</button> | |
10 | +<div class="row" id="modal_poll"> | |
11 | + | |
12 | +</div> | ... | ... |
courses/templates/topic/index.html
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | {% else %} |
13 | 13 | <li class="active">{{ topic.name }}</li> |
14 | 14 | {% endif %} |
15 | - | |
15 | + | |
16 | 16 | </ol> |
17 | 17 | {% endblock %} |
18 | 18 | |
... | ... | @@ -103,7 +103,7 @@ |
103 | 103 | <div class="panel-body"> |
104 | 104 | <div class="row"> |
105 | 105 | <div class="col-md-4"> |
106 | - <i class="fa fa-file-archive-o fa-lg" aria-hidden="true">Atividade.doc</i> | |
106 | + <i class="fa fa-file-archive-o fa-lg" aria-hidden="true">Atividade.doc</i> | |
107 | 107 | </div> |
108 | 108 | {% if user|has_role:'professor, system_admin' %} |
109 | 109 | <div class="col-md-4"> |
... | ... | @@ -148,4 +148,23 @@ |
148 | 148 | |
149 | 149 | </div> |
150 | 150 | </div> |
151 | + | |
152 | +<button id="poll_teste">poll</button> | |
153 | +<script type="text/javascript"> | |
154 | + $("#poll_teste").click(function(){ | |
155 | + if($('#poll').length){ | |
156 | + $('#poll').modal('show'); | |
157 | + } else { | |
158 | + var url = "{% url 'course:poll:create_poll' topic.slug%}"; | |
159 | + // alert(url); | |
160 | + $.get(url, function(data){ | |
161 | + $("#poll_t").append(data); | |
162 | + $('#poll').modal('show'); | |
163 | + }); | |
164 | + } | |
165 | + }); | |
166 | +</script> | |
167 | + | |
168 | +<div class="row" id="poll_t"> | |
169 | +</div> | |
151 | 170 | {% endblock %} | ... | ... |
courses/templatetags/list_topic_foruns.py
1 | 1 | from django import template |
2 | 2 | |
3 | 3 | from forum.models import Forum |
4 | - | |
4 | +from poll.models import Poll | |
5 | 5 | register = template.Library() |
6 | 6 | |
7 | 7 | """ |
... | ... | @@ -16,4 +16,15 @@ def list_topic_foruns(request, topic): |
16 | 16 | |
17 | 17 | context['foruns'] = Forum.objects.filter(topic = topic) |
18 | 18 | |
19 | - return context | |
20 | 19 | \ No newline at end of file |
20 | + return context | |
21 | + | |
22 | +@register.inclusion_tag('subject/poll_item_actions.html') | |
23 | +def list_topic_poll(request, topic): | |
24 | + context = { | |
25 | + 'request': request, | |
26 | + } | |
27 | + | |
28 | + context['polls'] = Poll.objects.filter(topic = topic) | |
29 | + context['topic'] = topic | |
30 | + | |
31 | + return context | ... | ... |
... | ... | @@ -0,0 +1,42 @@ |
1 | +//controles do modal | |
2 | +$(window).ready(function() { // utilizado para abrir o modal quando tiver tido algum erro no preenchimento do formulario | |
3 | + if($('.not_submited').length){ | |
4 | + $('#poll').modal('show'); | |
5 | + } | |
6 | +}); | |
7 | +var Answer = { | |
8 | + init: function(url) { // utilizado para adicionar um novo campo de resposta | |
9 | + $.get(url, function(data){ | |
10 | + $("#form").append(data); | |
11 | + var cont = 1; | |
12 | + $("#form div div div input").each(function(){ | |
13 | + $(this).attr('name',cont++); | |
14 | + }); | |
15 | + }); | |
16 | + } | |
17 | +}; | |
18 | + | |
19 | +var Submite = { | |
20 | + post: function(url,dados){ | |
21 | + $('#poll').modal('hide'); | |
22 | + $.post(url,dados, function(data){ | |
23 | + }).fail(function(data){ | |
24 | + $("div.modal-backdrop.fade.in").remove(); | |
25 | + $("#modal_poll").empty(); | |
26 | + $("#modal_poll").append(data.responseText); | |
27 | + }); | |
28 | + } | |
29 | + , | |
30 | + remove: function(url,dados, id_li_link){ | |
31 | + $('#poll').modal('hide'); | |
32 | + $.post(url,dados, function(data){ | |
33 | + $(id_li_link).remove(); | |
34 | + $("#modal_poll").empty(); | |
35 | + $("div.modal-backdrop.fade.in").remove(); | |
36 | + }).fail(function(){ | |
37 | + $("#modal_poll").empty(); | |
38 | + $("#modal_poll").append(data); | |
39 | + $('#poll').modal('show'); | |
40 | + }); | |
41 | + } | |
42 | +} | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +function get(url, id_modal, id_div_modal){ | |
2 | + $.get(url, function(data){ | |
3 | + if($(id_modal).length){ | |
4 | + $(id_div_modal).empty(); | |
5 | + $(id_div_modal).append(data); | |
6 | + } else { | |
7 | + $(id_div_modal).append(data); | |
8 | + } | |
9 | + $(id_modal).modal('show'); | |
10 | + }); | |
11 | +} | |
12 | + | |
13 | +// function remove(url, id_li_link){ | |
14 | +// $.post(url, function(data){ | |
15 | +// $(id_li_link).remove(); | |
16 | +// }).fail(function(data){ | |
17 | +// alert("Error ao excluir a enquete"); | |
18 | +// alert(data); | |
19 | +// }); | |
20 | +// } | ... | ... |
... | ... | @@ -0,0 +1,11 @@ |
1 | +//deve ser importado apenas depois do html | |
2 | +$( "#form" ).sortable({ // utilizado para fazer a re-organização das respostas | |
3 | + delay: 100, | |
4 | + distance: 5, | |
5 | + update: function( event, ui ) { | |
6 | + var cont = 1; | |
7 | + $("#form div div div input").each(function(){ | |
8 | + $(this).attr('name',cont++); | |
9 | + }); | |
10 | + }, | |
11 | +}); | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | + | |
2 | +{% load i18n %} | |
3 | + | |
4 | +<div class="row form-group"> | |
5 | + <div class="col-md-1"> | |
6 | + </br> | |
7 | + <label><span class="glyphicon glyphicon-move"></span></label> | |
8 | + </div> | |
9 | + <div class="col-md-10"> | |
10 | + <div class="has-success is-empty"> | |
11 | + <input type="text" name="1" class="form-control" placeholder="{% trans 'Answer' %}"> | |
12 | + <span class="help-block">{% trans "Possible answer for the question" %}</span> | |
13 | + </div> | |
14 | + </div> | |
15 | + <div class="col-md-1"> | |
16 | + </br> | |
17 | + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label> | |
18 | + </div> | |
19 | +</div> | ... | ... |
poll/templates/poll/create.html
1 | -{% extends "topic/index.html" %} | |
1 | +{# {% extends "topic/index.html" %} #} | |
2 | 2 | |
3 | 3 | {% load i18n widget_tweaks dict_access static%} |
4 | 4 | |
5 | -{% block style %} | |
5 | +{# {% block style %} #} | |
6 | 6 | <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> |
7 | -{% endblock %} | |
7 | + <script src="{% static 'js/modal_poll.js' %}"></script> | |
8 | 8 | |
9 | -{% block content %} | |
9 | +{# {% endblock %} #} | |
10 | + | |
11 | +{# {% block content %} #} | |
10 | 12 | <!-- Modal (remember to change the ids!!!) --> |
11 | 13 | <div class="modal fade" id="poll" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> |
12 | 14 | <div class="modal-dialog" role="document"> |
... | ... | @@ -56,7 +58,7 @@ |
56 | 58 | <form id="form" class="" action="" method="post"> |
57 | 59 | {% csrf_token %} |
58 | 60 | {% for key in keys %} |
59 | - <div class="row form-group"> | |
61 | + <div class="row form-group {% if form.has_error %} has-error {% endif %}"> | |
60 | 62 | <div class="col-md-1"> |
61 | 63 | </br> |
62 | 64 | <label><span class="glyphicon glyphicon-move"></span></label> |
... | ... | @@ -73,7 +75,7 @@ |
73 | 75 | </div> |
74 | 76 | </div> |
75 | 77 | {% empty %} |
76 | - <div class="row form-group"> | |
78 | + <div class="row form-group {% if form.has_error %} has-error {% endif %}"> | |
77 | 79 | <div class="col-md-1"> |
78 | 80 | </br> |
79 | 81 | <label><span class="glyphicon glyphicon-move"></span></label> |
... | ... | @@ -94,10 +96,10 @@ |
94 | 96 | </br> |
95 | 97 | </div> |
96 | 98 | <button type="button" id="add" class="btn btn-primary btn-block btn-sm">add</button> |
97 | - <div class="row form-group"> | |
99 | + <div class="row form-group {% if form.has_error %} has-error {% endif %}"> | |
98 | 100 | <label for="{{ form.limit_date.auto_id }}">{{ form.limit_date.label }}</label> |
99 | - {% render_field form.limit_date class="form-control" form="form"%} | |
100 | - {# <input form="form" class="form-control" type="date" name="{{form.limit_date.name}}" {% if form.limit_date.value != None %}value="{% if form.limit_date.value.year %}{{form.limit_date.value|date:'Y-m-d'}}{% else %}{{form.limit_date.value}}{% endif %}"{% endif %}>#} | |
101 | + {# {% render_field form.limit_date class="form-control" form="form"%} #} | |
102 | + <input form="form" class="form-control" type="date" name="{{form.limit_date.name}}" {% if form.limit_date.value != None %}value="{% if form.limit_date.value.year %}{{form.limit_date.value|date:'Y-m-d'}}{% else %}{{form.limit_date.value}}{% endif %}"{% endif %}> | |
101 | 103 | {% if form.limit_date.errors %} |
102 | 104 | <div class="not_submited"> |
103 | 105 | </br> |
... | ... | @@ -115,11 +117,11 @@ |
115 | 117 | {% endif %} |
116 | 118 | </div> |
117 | 119 | |
118 | - <div class="row form-group"> | |
120 | + <div class="row form-group {% if form.has_error %} has-error {% endif %}"> | |
119 | 121 | <label for="{{ form.students.auto_id }}">{{ form.students.label }}</label> |
120 | 122 | {% render_field form.students class="form-control" form="form"%} |
121 | 123 | </div> |
122 | - <div class="row form-group"> | |
124 | + <div class="row form-group {% if form.has_error %} has-error {% endif %}"> | |
123 | 125 | <div class="checkbox"> |
124 | 126 | <label> |
125 | 127 | {% render_field form.all_students class="form-control" form="form" %}<span class="checkbox-material"><span class="check"></span></span> {{form.all_students.label }} |
... | ... | @@ -159,48 +161,21 @@ |
159 | 161 | </div> |
160 | 162 | </div> |
161 | 163 | </div> |
164 | +<script src="{% static 'js/sortable_poll.js' %}"> | |
165 | +// Este js tem que ficar aqui se não o sortable não vai funcionar | |
166 | +</script> | |
167 | +{% block script_poll %} | |
162 | 168 | <script type="text/javascript"> |
163 | -// Este js tem que ficar aqui se não a tag "trans" não vai funcionar | |
164 | -$(window).ready(function() { // utilizado para abrir o modal quando tiver tido algum erro no preenchimento do formulario | |
165 | - if($('.not_submited').length){ | |
166 | - $('#poll').modal('show'); | |
167 | - } | |
168 | -}); | |
169 | -$( "#form" ).sortable({ // utilizado para fazer a re-organização das respostas | |
170 | - delay: 100, | |
171 | - distance: 5, | |
172 | - update: function( event, ui ) { | |
173 | - var cont = 1; | |
174 | - $("#form div div div input").each(function(){ | |
175 | - $(this).attr('name',cont++); | |
176 | - }); | |
177 | - }, | |
178 | -}); | |
179 | -name = 2; | |
180 | -$("#add").click(function() { // utilizado para adicionar um novo campo de resposta | |
181 | - //Obs: não funcionar se estiver importado no head, só funciona se estiver no final do arquivo | |
182 | - $("#form").append('\ | |
183 | - <div class="row form-group">\ | |
184 | - <div class="col-md-1">\ | |
185 | - </br>\ | |
186 | - <label><span class="glyphicon glyphicon-move"></span></label>\ | |
187 | - </div>\ | |
188 | - <div class="col-md-10">\ | |
189 | - <div class="has-success is-empty">\ | |
190 | - <input type="text" name="1" class="form-control" placeholder="{% trans "Answer" %}">\ | |
191 | - <span class="help-block">{% trans "Possible answer for the question" %}</span>\ | |
192 | - </div>\ | |
193 | - </div>\ | |
194 | - <div class="col-md-1">\ | |
195 | - </br>\ | |
196 | - <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>\ | |
197 | - </div>\ | |
198 | - </div>'); | |
199 | - var cont = 1; | |
200 | - $("#form div div div input").each(function(){ | |
201 | - $(this).attr('name',cont++); | |
169 | +// Este js tem que ficar aqui se não o button add não vai funcionar | |
170 | + $("#add").click(function (){ | |
171 | + Answer.init('{% url "course:poll:answer_poll" %}'); | |
172 | + }); | |
173 | + | |
174 | + $("#form").submit(function(event) { | |
175 | + Submite.post("{% url 'course:poll:create_poll' topic.slug %}",$(this).serialize()); | |
176 | + event.preventDefault(); | |
202 | 177 | }); |
203 | -}); | |
204 | 178 | </script> |
205 | -<a href="" data-toggle="modal" data-target="#poll">modal</a> | |
206 | -{% endblock content %} | |
179 | +{% endblock script_poll %} | |
180 | +{# <a href="" data-toggle="modal" data-target="#poll">modal</a> #} | |
181 | +{# {% endblock content %} #} | ... | ... |
poll/templates/poll/remove.html
1 | 1 | {% extends "poll/create.html" %} |
2 | 2 | |
3 | -{% load i18n %} | |
3 | +{% load i18n static%} | |
4 | 4 | |
5 | 5 | {% block title_poll %} |
6 | 6 | <!-- Put your title here!!! --> |
... | ... | @@ -8,14 +8,19 @@ |
8 | 8 | {% endblock title_poll %} |
9 | 9 | |
10 | 10 | {% block content_poll %} |
11 | +<script src="{% static 'js/modal_poll.js' %}"></script> | |
11 | 12 | <!-- Put ONLY your content here!!! --> |
12 | -<form action="" method="post"> | |
13 | +<form id="delete_form" action="" method="post"> | |
13 | 14 | {% csrf_token %} |
14 | - <h2>{% trans 'Are you sure you want to delete the subject' %} "{{poll}}"?</h2> | |
15 | - <input type="submit" class="btn btn-raised btn-success btn-lg" value="{% trans 'Yes' %}" /> | |
16 | - <a href="" class="btn btn-raised btn-danger btn-lg">{% trans 'No' %}</a> | |
15 | + <p>{% trans 'Are you sure you want to delete the subject' %} "{{poll.name}}"?</p> | |
17 | 16 | </form> |
18 | 17 | {% endblock content_poll %} |
19 | - | |
20 | 18 | {% block button_save %} |
19 | +<button type="submite" id="button" form="delete_form" class="btn btn-primary btn-raised">{% trans "Delete" %}</button> | |
20 | +<script> | |
21 | + $("#delete_form").submit(function(event) { | |
22 | + Submite.remove("{% url 'course:poll:delete_poll' poll.slug %}",$(this).serialize(),"#poll_{{poll.slug}}"); | |
23 | + event.preventDefault(); | |
24 | + }); | |
25 | +</script> | |
21 | 26 | {% endblock button_save %} | ... | ... |
poll/templates/poll/update.html
... | ... | @@ -11,3 +11,17 @@ |
11 | 11 | <!-- Put curtom buttons here!!! --> |
12 | 12 | <button type="submite" id="button" form="form" class="btn btn-primary btn-raised">{% trans "Update" %}</button> |
13 | 13 | {% endblock button_save %} |
14 | + | |
15 | +{% block script_poll %} | |
16 | +<script type="text/javascript"> | |
17 | +// Este js tem que ficar aqui se não o button add não vai funcionar | |
18 | + $("#add").click(function (){ | |
19 | + Answer.init('{% url "course:poll:answer_poll" %}'); | |
20 | + }); | |
21 | + | |
22 | + $("#form").submit(function(event) { | |
23 | + Submite.post("{% url 'course:poll:update_poll' poll.slug %}",$(this).serialize()); | |
24 | + event.preventDefault(); | |
25 | + }); | |
26 | +</script> | |
27 | +{% endblock script_poll %} | ... | ... |
poll/urls.py
... | ... | @@ -7,5 +7,5 @@ urlpatterns = [ |
7 | 7 | url(r'^create/(?P<slug>[\w\-_]+)/$', views.CreatePoll.as_view(), name='create_poll'), # topic slug |
8 | 8 | url(r'^update/(?P<slug>[\w\-_]+)/$', views.UpdatePoll.as_view(), name='update_poll'), # poll slug |
9 | 9 | url(r'^delete/(?P<slug>[\w\-_]+)/$', views.DeletePoll.as_view(), name='delete_poll'), # poll |
10 | - | |
10 | + url(r'^answer/$', views.AnswerPoll.as_view(), name='answer_poll'), # poll | |
11 | 11 | ] | ... | ... |
poll/views.py
... | ... | @@ -80,7 +80,6 @@ class CreatePoll(LoginRequiredMixin,HasRoleMixin,generic.CreateView): |
80 | 80 | form_class = PollForm |
81 | 81 | context_object_name = 'poll' |
82 | 82 | template_name = 'poll/create.html' |
83 | - success_url = reverse_lazy('core:home') | |
84 | 83 | |
85 | 84 | def form_invalid(self, form,**kwargs): |
86 | 85 | context = super(CreatePoll, self).form_invalid(form) |
... | ... | @@ -92,6 +91,10 @@ class CreatePoll(LoginRequiredMixin,HasRoleMixin,generic.CreateView): |
92 | 91 | keys = sorted(answers) |
93 | 92 | context.context_data['answers'] = answers |
94 | 93 | context.context_data['keys'] = keys |
94 | + context.context_data['form'] = form | |
95 | + context.status_code = 400 | |
96 | + print (context) | |
97 | + # return self.render_to_response(context, status = 400) | |
95 | 98 | return context |
96 | 99 | |
97 | 100 | def form_valid(self, form): |
... | ... | @@ -105,11 +108,12 @@ class CreatePoll(LoginRequiredMixin,HasRoleMixin,generic.CreateView): |
105 | 108 | answer = Answer(answer=self.request.POST[key],order=key,poll=self.object) |
106 | 109 | answer.save() |
107 | 110 | |
108 | - return super(CreatePoll, self).form_valid(form) | |
111 | + return self.render_to_response(self.get_context_data(form = form), status = 200) | |
109 | 112 | |
110 | 113 | def get_context_data(self, **kwargs): |
111 | 114 | context = super(CreatePoll, self).get_context_data(**kwargs) |
112 | 115 | topic = get_object_or_404(Topic, slug = self.kwargs.get('slug')) |
116 | + context["topic"] = topic | |
113 | 117 | context['course'] = topic.subject.course |
114 | 118 | context['subject'] = topic.subject |
115 | 119 | context['subjects'] = topic.subject.course.subjects.all() |
... | ... | @@ -145,6 +149,8 @@ class UpdatePoll(LoginRequiredMixin,HasRoleMixin,generic.UpdateView): |
145 | 149 | keys = sorted(answers) |
146 | 150 | context.context_data['answers'] = answers |
147 | 151 | context.context_data['keys'] = keys |
152 | + context.context_data['form'] = form | |
153 | + context.status_code = 400 | |
148 | 154 | return context |
149 | 155 | |
150 | 156 | def form_valid(self, form): |
... | ... | @@ -164,6 +170,7 @@ class UpdatePoll(LoginRequiredMixin,HasRoleMixin,generic.UpdateView): |
164 | 170 | def get_context_data(self, **kwargs): |
165 | 171 | context = super(UpdatePoll, self).get_context_data(**kwargs) |
166 | 172 | poll = self.object |
173 | + context['topic'] = poll.topic | |
167 | 174 | context['course'] = poll.topic.subject.course |
168 | 175 | context['subject'] = poll.topic.subject |
169 | 176 | context['subjects'] = poll.topic.subject.course.subjects.all() |
... | ... | @@ -199,6 +206,7 @@ class DeletePoll(LoginRequiredMixin, HasRoleMixin, generic.DeleteView): |
199 | 206 | context['course'] = self.object.topic.subject.course |
200 | 207 | context['subject'] = self.object.topic.subject |
201 | 208 | context['poll'] = self.object |
209 | + context["topic"] = self.object.topic | |
202 | 210 | context['subjects'] = self.object.topic.subject.course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user])) |
203 | 211 | if (has_role(self.request.user,'system_admin')): |
204 | 212 | context['subjects'] = self.object.topic.subject.course.subjects.all() |
... | ... | @@ -206,3 +214,7 @@ class DeletePoll(LoginRequiredMixin, HasRoleMixin, generic.DeleteView): |
206 | 214 | |
207 | 215 | def get_success_url(self): |
208 | 216 | return reverse_lazy('course:view_topic', kwargs={'slug' : self.object.topic.slug}) |
217 | + | |
218 | + | |
219 | +class AnswerPoll(generic.TemplateView): | |
220 | + template_name = 'poll/answer.html' | ... | ... |