0003-cells-if-a-cell-is-invalid-display-it-38009.patch
combo/data/models.py | ||
---|---|---|
550 | 550 | |
551 | 551 |
invalid_reason_code = models.CharField(max_length=100, blank=True, null=True, editable=False) |
552 | 552 |
invalid_since = models.DateTimeField(blank=True, null=True, editable=False) |
553 |
invalid_reason_codes = {} |
|
553 | 554 | |
554 | 555 |
default_form_class = None |
555 | 556 |
manager_form_factory_kwargs = {} |
... | ... | |
724 | 725 |
def get_extra_manager_context(self): |
725 | 726 |
return {} |
726 | 727 | |
728 |
def mark_as_invalid(self, reason_code, force=True, save=True): |
|
729 |
if not force and self.invalid_since is not None: |
|
730 |
# don't overwrite invalid reason already set |
|
731 |
return |
|
732 | ||
733 |
if self.invalid_reason_code == reason_code: |
|
734 |
# don't overwrite invalid_since if same reason already set |
|
735 |
return |
|
736 | ||
737 |
self.invalid_reason_code = reason_code |
|
738 |
self.invalid_since = now() |
|
739 | ||
740 |
if save: |
|
741 |
self.save(update_fields=['invalid_reason_code', 'invalid_since']) |
|
742 | ||
743 |
def mark_as_valid(self, save=True): |
|
744 |
if self.invalid_reason_code is None and self.invalid_since is None: |
|
745 |
# don't heart DB |
|
746 |
return |
|
747 | ||
748 |
self.invalid_reason_code = None |
|
749 |
self.invalid_since = None |
|
750 |
if save: |
|
751 |
self.save(update_fields=['invalid_reason_code', 'invalid_since']) |
|
752 | ||
753 |
def get_invalid_reason(self): |
|
754 |
if not self.invalid_since: |
|
755 |
return None |
|
756 |
return self.invalid_reason_codes.get( |
|
757 |
self.invalid_reason_code, self.invalid_reason_code) |
|
758 | ||
727 | 759 |
def is_visible(self, user=None): |
728 | 760 |
if self.invalid_since and self.invalid_since < now() - datetime.timedelta(days=2): |
729 | 761 |
return False |
combo/manager/static/css/combo.manager.css | ||
---|---|---|
80 | 80 |
} |
81 | 81 | |
82 | 82 |
div.cell h3 span.additional-label, |
83 |
div.cell h3 span.invalid, |
|
83 | 84 |
div.cell h3 span.visibility-summary, |
84 | 85 |
div.page span.visibility-summary { |
85 | 86 |
font-size: 80%; |
... | ... | |
111 | 112 |
max-width: 30%; |
112 | 113 |
} |
113 | 114 | |
115 |
div.cell h3 span.invalid { |
|
116 |
color: red; |
|
117 |
} |
|
118 | ||
114 | 119 |
div.cell-list div h3:after { |
115 | 120 |
font-family: FontAwesome; |
116 | 121 |
content: "\f107"; /* angle-down */ |
combo/manager/static/js/combo.manager.js | ||
---|---|---|
212 | 212 |
$.getJSON($form.data('label-url'), |
213 | 213 |
function(data) { |
214 | 214 |
$form.parents('div.cell').find('.additional-label i').text(data['label']); |
215 |
if (data['invalid_reason']) { |
|
216 |
$form.parents('div.cell').find('.invalid').text('/!\\ ' + data['invalid_reason']); |
|
217 |
} else { |
|
218 |
$form.parents('div.cell').find('.invalid').text(''); |
|
219 |
} |
|
215 | 220 |
} |
216 | 221 |
); |
217 | 222 |
} |
combo/manager/templates/combo/page_view.html | ||
---|---|---|
146 | 146 |
<span class="group1"> |
147 | 147 |
{{ cell.get_label }} |
148 | 148 |
{% if cell.slug %} [{{cell.slug}}] {% endif %} |
149 |
{% if cell.extra_css_class %} |
|
150 |
<span class="extra-css-class">[{{ cell.extra_css_class }}]</span> |
|
151 |
{% endif %} |
|
152 |
<span class="additional-label">
|
|
153 |
<i>{{cell.get_additional_label|default_if_none:""}}</i></span>
|
|
149 |
{% if cell.extra_css_class %}
|
|
150 |
<span class="extra-css-class">[{{ cell.extra_css_class }}]</span>
|
|
151 |
{% endif %}
|
|
152 |
<span class="additional-label"><i>{{cell.get_additional_label|default_if_none:""}}</i></span>
|
|
153 |
<span class="invalid">{% if cell.invalid_since %}/!\ {{ cell.get_invalid_reason }}{% endif %}</span>
|
|
154 | 154 |
</span> |
155 | 155 |
{% if not cell.public %} |
156 | 156 |
<span class="visibility-summary |
combo/manager/views.py | ||
---|---|---|
568 | 568 |
def page_get_additional_label(request, page_pk, cell_reference): |
569 | 569 |
cell = CellBase.get_cell(cell_reference, page_id=page_pk) |
570 | 570 |
response = HttpResponse(content_type='application/json') |
571 |
json.dump({'label': force_text(cell.get_additional_label()) or ''}, response) |
|
571 |
json.dump({ |
|
572 |
'label': force_text(cell.get_additional_label()) or '', |
|
573 |
'invalid_reason': force_text(cell.get_invalid_reason()) if cell.invalid_since else '' |
|
574 |
}, response) |
|
572 | 575 |
return response |
573 | 576 | |
574 | 577 |
tests/test_manager.py | ||
---|---|---|
153 | 153 |
assert Page.objects.all()[0].exclude_from_navigation is False |
154 | 154 | |
155 | 155 | |
156 |
def test_edit_page_cell_invalid_placeholder(app, admin_user): |
|
157 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
|
158 |
cell = TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=1) |
|
159 |
cell.mark_as_invalid('foo_bar_reason') |
|
160 |
old_reason = cell.invalid_reason_code |
|
161 |
old_date = cell.invalid_since |
|
162 | ||
163 |
app = login(app) |
|
164 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
165 |
assert '<span class="invalid">/!\\ foo_bar_reason</span>' in resp.text |
|
166 | ||
167 |
cell.mark_as_invalid('another_foo_bar_reason', force=False) |
|
168 |
assert old_reason == cell.invalid_reason_code |
|
169 |
assert old_date == cell.invalid_since |
|
170 | ||
171 |
cell.mark_as_invalid('another_foo_bar_reason') |
|
172 |
assert cell.invalid_reason_code == 'another_foo_bar_reason' |
|
173 |
assert old_date < cell.invalid_since |
|
174 | ||
175 |
cell.mark_as_valid() |
|
176 |
resp = app.get('/manage/pages/%s/' % page.pk) |
|
177 |
assert '<span class="invalid">/!\\ foo_bar_reason</span>' not in resp.text |
|
178 | ||
179 | ||
156 | 180 |
def test_edit_page_optional_placeholder(app, admin_user): |
157 | 181 |
Page.objects.all().delete() |
158 | 182 |
page = Page.objects.create(title='One', slug='one', template_name='standard') |
159 |
- |