general: add a 'base.html' template webservice (#7137)

This commit is contained in:
Frédéric Péters 2015-05-11 09:13:45 +02:00
parent 038d00a6de
commit 4de32236f0
9 changed files with 153 additions and 36 deletions

View File

@ -131,6 +131,7 @@ class WcsCategoryCell(WcsCommonCategoryCell):
class WcsBlurpMixin(object):
is_enabled = classmethod(is_wcs_enabled)
user_dependant = True
def get_blurp_renderer(self, context):
if self.wcs_site:

View File

@ -76,15 +76,19 @@ class Page(models.Model):
self.order = max_order + 1
return super(Page, self).save(*args, **kwargs)
def get_online_url(self):
parts = [self.slug]
def get_parents_and_self(self):
pages = [self]
page = self
while page.parent_id:
page = page.parent
parts.append(page.slug)
pages.append(page)
return reversed(pages)
def get_online_url(self):
parts = [x.slug for x in self.get_parents_and_self()]
if parts == ['index']:
return '/'
return '/' + '/'.join(reversed(parts))
return '/' + '/'.join(parts)
def get_page_of_level(self, level):
'''Return page of given level in the page hierarchy.'''
@ -212,6 +216,7 @@ class CellBase(models.Model):
default_form_class = None
visible = True
user_dependant = False
class Meta:
abstract = True
@ -319,6 +324,10 @@ class CellBase(models.Model):
context.'''
return True
def is_user_dependant(self, context):
'''Return whether the cell content varies from user to user.'''
return self.user_dependant
@register_cell_class
class TextCell(CellBase):

View File

@ -1,14 +1,24 @@
function combo_load_cell(elem, url) {
$.ajax({url: url,
xhrFields: { withCredentials: true },
async: true,
dataType: 'html',
crossDomain: true,
success: function(data) { $(elem).replaceWith(data); },
error: function(error) { console.log(':(', error); }
});
}
$(function() {
$('[data-ajax-cell-refresh]').each(function(idx, elem) {
var $elem = $(elem);
function refresh() {
$elem.find('> div').load($elem.data('ajax-cell-url'));
combo_load_cell($elem.find('> div'), $elem.data('ajax-cell-url'));
}
$elem.timeout_id = setInterval(refresh, $elem.data('ajax-cell-refresh')*1000);
});
$('[data-ajax-cell-must-load]').each(function(idx, elem) {
var $elem = $(elem);
console.log('loading:', $elem.parents('div.cell').data('ajax-cell-url'));
$elem.load($elem.parents('div.cell').data('ajax-cell-url'));
combo_load_cell($elem, $elem.parents('div.cell').data('ajax-cell-url'));
});
});

View File

@ -3,7 +3,7 @@
<ul>
{% for menuitem in menuitems %}
<li class="menu-{{ menuitem.page.slug }} {% if menuitem.selected %}selected{% endif %}"><a
href="{{ menuitem.page.get_online_url }}">{{ menuitem.page.title }}</a>
href="{% page_absolute_url menuitem.page %}">{{ menuitem.page.title }}</a>
{% if depth > 1 %}
{% show_menu current_page=menuitem.page level=-1 depth=depth reduce_depth=True %}
{% endif %}

View File

@ -1,8 +1,11 @@
{% load combo %}
{% for cell in cells %}
<div class="cell {{ cell.css_class_name }} {% if cell.slug %}{{cell.slug}}{% endif %}"
data-ajax-cell-url="{% url 'combo-public-ajax-page-cell' page_pk=page.id cell_reference=cell.get_reference %}"
data-ajax-cell-url="{{ site_base }}{% url 'combo-public-ajax-page-cell' page_pk=cell.page.id cell_reference=cell.get_reference %}"
{% if cell.ajax_refresh %}
data-ajax-cell-refresh="{{ cell.ajax_refresh }}"
{% endif %}><div>{% render_cell cell %}</div></div>
{% endfor %}
{% if render_skeleton %}
{{ skeleton }}
{% endif %}

View File

@ -26,19 +26,35 @@ from combo.utils import NothingInCacheException
register = template.Library()
def skeleton_text(context, placeholder_name):
if context['request'].GET.get('format') == 'ezt':
return '[if-any %s][%s][end]' % (placeholder_name, placeholder_name)
return '{%% block %s %%}{%% endblock %%}' % placeholder_name
@register.inclusion_tag('combo/placeholder.html', takes_context=True)
def placeholder(context, placeholder_name):
context['cells'] = [x for x in context['page_cells'] if
x.placeholder == placeholder_name and x.is_relevant(context)]
x.placeholder == placeholder_name and
(context.get('render_skeleton') or x.is_relevant(context))]
if context.get('render_skeleton') and not context['cells']:
context['skeleton'] = skeleton_text(context, placeholder_name)
return context
@register.simple_tag(takes_context=True)
def render_cell(context, cell):
if context.get('render_skeleton') and cell.is_user_dependant(context):
return template.loader.get_template('combo/deferred-cell.html').render(context)
try:
return cell.render(context)
except NothingInCacheException:
return template.loader.get_template('combo/deferred-cell.html').render(context)
@register.simple_tag(takes_context=True)
def skeleton_extra_placeholder(context, placeholder_name):
if context.get('render_skeleton'):
return skeleton_text(context, placeholder_name)
return ''
@register.inclusion_tag('combo/menu.html', takes_context=True)
def show_menu(context, level=0, current_page=None, depth=1, reduce_depth=False):
if reduce_depth:
@ -49,6 +65,10 @@ def show_menu(context, level=0, current_page=None, depth=1, reduce_depth=False):
return get_menu_context(new_context, level=level, current_page=current_page,
depth=depth)
@register.simple_tag(takes_context=True)
def page_absolute_url(context, page):
return context['request'].build_absolute_uri(page.get_online_url())
@register.filter(name='strptime')
def strptime(date_string, date_format):
try:

View File

@ -21,5 +21,6 @@ from . import views
urlpatterns = patterns('combo.publicviews',
url(r'^ajax/cell/(?P<page_pk>\w+)/(?P<cell_reference>[\w_-]+)/$',
views.ajax_page_cell, name='combo-public-ajax-page-cell'),
(r'__skeleton__/$', views.skeleton),
(r'', views.page),
)

View File

@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urllib
import urlparse
from django.conf import settings
from django.contrib.auth import logout as auth_logout
@ -67,11 +68,79 @@ def ajax_page_cell(request, page_pk, cell_reference):
'page': page,
'request': request,
'ajax': True,
'site_base': request.build_absolute_uri('/')[:-1],
})
return HttpResponse(cell.render(context), content_type='text/html')
def extend_with_locked_placeholders_cells(cells, page, pages):
locked_placeholders = page.get_locked_placeholders(cells)
if locked_placeholders:
# there are some acquired placeholders, look in parent pages for
# appropriate content.
try:
# add the site index page as ultimate parent
pages.insert(0, Page.objects.get(slug='index'))
except Page.DoesNotExist:
pass
unlocker_cells = CellBase.get_cells(page_id__in=[x.id for x in pages])
found_placeholders = {}
for parent_page in reversed(pages[:-1]):
for placeholder in parent_page.get_unlocked_placeholders(unlocker_cells):
if not placeholder in locked_placeholders:
continue
if not placeholder in found_placeholders:
found_placeholders[placeholder] = parent_page.id
if len(found_placeholders) == len(locked_placeholders):
break
# add found cells to the page cells
for placeholder_key, page_id in found_placeholders.items():
cells.extend([x for x in unlocker_cells if x.page_id == page_id and
x.placeholder == placeholder_key])
def skeleton(request):
source = request.GET['source']
selected_page = None
# look in redirect pages after the best match for the source
redirect_pages = Page.objects.exclude(redirect_url__isnull=True).exclude(redirect_url='')
for page in redirect_pages:
if source.startswith(page.redirect_url):
if selected_page is None or len(page.redirect_url) > len(selected_page.redirect_url):
selected_page = page
if selected_page is None:
# if there was no page found, look for a domain match
netloc = urlparse.urlparse(source).netloc
for page in redirect_pages:
if urlparse.urlparse(page.redirect_url).netloc == netloc:
selected_page = page
break
else:
raise PermissionDenied()
pages = list(page.get_parents_and_self())
cells = CellBase.get_cells(page_id=page.id)
extend_with_locked_placeholders_cells(cells, page, pages)
combo_template = settings.COMBO_PUBLIC_TEMPLATES[page.template_name]
ctx = {
'page': page,
'page_cells': cells,
'request': request,
'render_skeleton': True,
'site_base': request.build_absolute_uri('/')[:-1],
}
template_name = combo_template['template']
return render(request, template_name, ctx)
def page(request):
url = request.path_info
parts = [x for x in request.path_info.strip('/').split('/') if x]
@ -102,32 +171,7 @@ def page(request):
combo_template = settings.COMBO_PUBLIC_TEMPLATES[page.template_name]
cells = CellBase.get_cells(page_id=page.id)
locked_placeholders = page.get_locked_placeholders(cells)
if locked_placeholders:
# there are some acquired placeholders, look in parent pages for
# appropriate content.
try:
# add the site index page as ultimate parent
pages.insert(0, Page.objects.get(slug='index'))
except Page.DoesNotExist:
pass
unlocker_cells = CellBase.get_cells(page_id__in=[x.id for x in pages])
found_placeholders = {}
for parent_page in reversed(pages[:-1]):
for placeholder in parent_page.get_unlocked_placeholders(unlocker_cells):
if not placeholder in locked_placeholders:
continue
if not placeholder in found_placeholders:
found_placeholders[placeholder] = parent_page.id
if len(found_placeholders) == len(locked_placeholders):
break
# add found cells to the page cells
for placeholder_key, page_id in found_placeholders.items():
cells.extend([x for x in unlocker_cells if x.page_id == page_id and
x.placeholder == placeholder_key])
extend_with_locked_placeholders_cells(cells, page, pages)
cells = [x for x in cells if x.is_visible(user=request.user)]
ctx = {

View File

@ -1,5 +1,6 @@
from webtest import TestApp
import pytest
import urllib
from combo.wsgi import application
from combo.data.models import Page, CellBase, TextCell
@ -69,3 +70,31 @@ def test_page_private_logged_in(admin_user):
page.save()
app = login(TestApp(application))
resp = app.get('/', status=200)
def test_page_skeleton():
Page.objects.all().delete()
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
redirect_url='http://example.net/foo/')
page.save()
app = TestApp(application)
# url prefix match
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net/foo/bar'))
assert '{% block content %}{% endblock %}' in resp.body
assert '{% block footer %}{% endblock %}' in resp.body
# url netloc match
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net'))
assert '{% block content %}{% endblock %}' in resp.body
assert '{% block footer %}{% endblock %}' in resp.body
# no match
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.com/foo/bar'), status=403)
# check with a footer cell
cell = TextCell(page=page, placeholder='footer', text='Foobar', order=0)
cell.save()
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net'))
assert '{% block content %}{% endblock %}' in resp.body
assert not '{% block footer %}{% endblock %}' in resp.body
assert 'Foobar' in resp.body