Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Products/CMFPlone/browser/main_template.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from plone.base.utils import is_truthy
from Products.CMFPlone.browser.interfaces import IMainTemplate
from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
Expand All @@ -14,7 +15,8 @@ def __call__(self):

@property
def template_name(self):
if self.request.form.get("ajax_load"):
# Directly query the request object, which includes the form.
if is_truthy(self.request.get("ajax_load")):
return self.ajax_template_name
else:
return self.main_template_name
Expand Down
2 changes: 1 addition & 1 deletion Products/CMFPlone/browser/templates/ajax_main_template.pt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
portal_url python:portal_state.portal_url();
checkPermission python:context.restrictedTraverse('portal_membership').checkPermission;
ajax_include_head python:request.get('ajax_include_head', False);
ajax_load python:False;"
ajax_load python:True;"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea why this ajax_main_template has ajax_load=False in the first place. This variable seems really obscure defined like this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

But I think it's maybe needed by other templates and was incorrectly defined due to a copy paste error.

I did now looked it up and saw:

  • It was added here:‌ 4f58ba6
  • The copy error changing from ajax_load python:True to ajax_load python:False happened in this commit at some Barceloneta LTS syncing:
    954942a

Now it makes sense.

But no big deal apparently that it was defined incorrectly, because everything was working just fine.

i18n:domain="plone"
tal:attributes="lang lang;">

Expand Down
6 changes: 6 additions & 0 deletions Products/CMFPlone/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@
name="plone"
/>

<subscriber
for="*
zope.traversing.interfaces.IBeforeTraverseEvent"
handler=".traversal.set_ajax"
/>

<!-- Adapter for default workflow lookup -->
<adapter
factory=".workflow.ToolWorkflowChain"
Expand Down
78 changes: 78 additions & 0 deletions Products/CMFPlone/tests/test_main_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING
from zope.component import getMultiAdapter
from zope.event import notify
from zope.traversing.interfaces import BeforeTraverseEvent

import unittest


class TestMainTemplate(unittest.TestCase):
layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING

def setUp(self):
self.portal = self.layer["portal"]
self.request = self.layer["request"]

def test_request_containment(self):
"""Very basic test to show that the following works:
`"ajax_load" in request`
instead of:
`request.get("ajax_load", MARKER) is not MARKER1`
"""
request = self.request.clone()
request.form["ajax_load"] = True
self.assertTrue("ajax_load" in request.form)
self.assertTrue("ajax_load" in request)

def test_main_template_standard(self):
view = getMultiAdapter((self.portal, self.request), name="main_template")
self.assertEqual(view.template_name, "templates/main_template.pt")

def test_main_template_ajax_parameter(self):
request = self.request.clone()
request.form["ajax_load"] = True
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/ajax_main_template.pt")

def test_main_template_ajax_manually(self):
request = self.request.clone()
request.set("ajax_load", True)
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/ajax_main_template.pt")

def test_main_template_auto(self):
request = self.request.clone()
request.environ["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
# Manually trigger the BeforeTraverseEvent to set the ajax_load
# parameter - using restrictedTraverse would not work here
notify(BeforeTraverseEvent(self.portal, request))
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/ajax_main_template.pt")

def test_main_template_noauto_if_set(self):
request = self.request.clone()
request.form["ajax_load"] = "False"
request.environ["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
# Manually trigger the BeforeTraverseEvent to set the ajax_load
# parameter - using restrictedTraverse would not work here
notify(BeforeTraverseEvent(self.portal, request))
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/main_template.pt")

def test_main_template_no_ajax_1(self):
request = self.request.clone()
request.form["ajax_load"] = False
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/main_template.pt")

def test_main_template_no_ajax_2(self):
request = self.request.clone()
request.form["ajax_load"] = "0"
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/main_template.pt")

def test_main_template_no_ajax_3(self):
request = self.request.clone()
request.form["ajax_load"] = "off"
view = getMultiAdapter((self.portal, request), name="main_template")
self.assertEqual(view.template_name, "templates/main_template.pt")
14 changes: 14 additions & 0 deletions Products/CMFPlone/traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,17 @@ def get_zope_page_template_engine(engine):
return getEngine()
if isinstance(engine, zpt_engine.TrustedZopeEngine):
return getTrustedEngine()


def set_ajax(obj, event):
"""Set the ajax_load parameter automatically for XMLHttpRequest requests."""
request = event.request

# If ajax_load was already set to a true-ish or false-ish value, don't set
# it again.
if (
request.getHeader("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"
and "ajax_load" not in request
):
# Directly set on the request object
request.set("ajax_load", True)
11 changes: 11 additions & 0 deletions news/+set_ajax.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Automatically set the ajax_load request parameter.

Zope maintains the "HTTP_X_REQUESTED_WITH" request header. If this is set to
"XMLHttpRequest", we have an AJAX request. In this case the ajax_load parameter
is set to True directly on the request object.
If the ajax_load parameter was already set to a true-ish or false-ish value, it
is not overwritten.

This should make use for the ajax_main_template for any AJAX request,
regardless if the ajax_load parameter was manually set or not and potentially
speed up Plone Classic UI rendering.