cone.app
uses bdajax
for AJAXification of it’s User Interface.
Detailed documentation about the features provided by bdajax
can be found
in it’s Documentation.
Related client and server side implementation details are described in the following sections.
To make custom JavaScript work properly in combination with bdajax
, the
plugin needs to provide a binder function which gets registered to
bdajax.binders
. The binder function is responsible for proper event
bindings and gets called each time bdajax
modifies the DOM tree with
the modified part of the DOM tree as context
.
A best practice JS stub for a plugin looks like so.
(function($) {
$(document).ready(function() {
// register binder function to bdajax. The register function takes
// a function and a boolean flag whether to immediately execute
// this function as arguments.
bdajax.register(example.binder, true);
});
// plugin namespace
var example = {
// plugin binder function. gets called on initial page load and
// every time bdajax modifies the DOM tree.
binder: function(context) {
// event binding code goes here. context is the modified
// part of the DOM tree if called by bdajax.
}
};
})(jQuery);
When working with bdajax
in page templates, the related XML namespace
must be defined.
<tal:block xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:ajax="http://namespaces.conestack.org/ajax"
omit-tag="True">
<!-- bdajax using markup goes here -->
</tal:block>
cone.app
uses a custom JavaScript event named contextchanged
to
notify the UI about a changed traversal context.
If some action changes the application context it’s usually desired to render
the entire layout
on the new context. To achieve this, trigger
contextchanged
event to #layout
DOM element. The target must contain
the new traversal path without a trailing view name but including request
parameters if desired.
<a href=""
ajax:bind="click"
ajax:target="http://example.com/path/to/node/without/trailing/view?a=1"
ajax:event="contextchanged:#layout">
Trigger context change.
</a>
bdajax
related markup gets delivered by a tile with name bdajax
and is
included in main template.
bdajax
expects a server side implemented JSON view for performing
actions by name ajaxaction
.
The implementation is located at cone.app.browser.ajax.ajax_tile
. It
renders a tile registered by action name and returns a JSON reponse in the
format expected by bdajax
.
If an uncaught exception is thrown during action processing, the traceback is delivered to the client and gets displayed as error message.
bdajax
supports AJAX continuation. This can be useful if data manipulating
actions need to finish it’s job before anything can be re-rendered,
or if user should get a message displayed after action processing just to name
a few usecases.
AJAX continuation definitions are collected during request execution and
translated via cone.app.browser.ajax.AjaxContinue
to the format
expected by bdajax
on the client side in the ajaxaction
JSON view.
The Available continuation definitions are located in module
cone.app.browser.ajax
and represented by the following classes:
AjaxPath: Set browser path. Accepted arguments
path
: Browser path to be set.target
: Traversable target URL without trailing server view.action
: Name of action which should be performed.event
: Event to trigger.overlay
: Overlay to display.overlay_css
: Additional overlay CSS class.
AjaxAction: Execute action. Accepted arguments
target
: Traversable target URL without trailing server view.name
: Action name.mode
: DOM modification mode. Eitherinner
andreplace
.selector
: DOM modification selector.
AjaxEvent: Trigger event. Accepted arguments
target
: Traversable target URL without trailing server view.name
: Event name.selector
: Selector of DOM elements on which to trigger the eventdata
: Optional data set on event.
AjaxMessage: Display message. Accepted arguments
payload
: Message payload as text or markup.flavor
: XOR withselector
. One out ofmessage
,info
,warning
orerror
.selector
: XOR withflavor
. If given, render message to DOM element found by selector.
AjaxOverlay: Display or close overlay. Accepted arguments
selector
: selector of overlay DOM element. Defaults to#ajax-overlay
.action
: Name of action which should be displayed in overlay.target
: Traversable target URL without trailing server view.close
: Flag whether to close an open overlay.content_selector
: Optional overlay content selector. Defaults to.overlay_content
.css
: Additional overlay CSS class.
AJAX continuation can be queued by passing continuation definition objects
to cone.app.browser.ajax.ajax_continue
, which expects the request and
a single or a list of continuation definitions.
from cone.app.browser.ajax import AjaxEvent
from cone.app.browser.ajax import AjaxOverlay
from cone.app.browser.ajax import ajax_continue
from cone.tile import Tile
from cone.tile import tile
@tile(name='exampleaction', permission='view')
class ExampleAction(Tile):
def render(self):
# close overlay
overlay = AjaxOverlay(close=True)
# trigger changed context to layout
event = AjaxEvent(
target=make_url(self.request, node=self.model),
name='contextchanged',
selector='#layout'
)
# queue continuation definitions
ajax_continue(request, [overlay, event])
return u''
A shortcut for continuation messages is located at
cone.app.browser.ajax.ajax_message
.
from cone.app.browser.ajax import ajax_message
payload = '<div>Message</div>'
ajax_message(request, payload, flavor='message')
AJAX forms are automatically detected and computed properly as long as they are
rendered via cone.app.browser.authoring.render_form
. The default rendering
location is the main content area of the page. If form target DOM element
differs, re-rendering definitions must also change in order to hook the form at
the right location.
The rendering target of a form can be changed with
cone.app.browser.ajax.ajax_form_fiddle
. It expects request
,
selector
and mode
as arguments.
ajax_form_fiddle
must be called somewhen during request processing. For
unique form tiles the function can be called at prepare
time, while for
generic forms it might be worth providing a plumbing behavior hooking to the
__call__
function.
from plumber import plumbing
from plumber import plumb
from plumber import Behavior
from cone.app.browser.ajax import ajax_form_fiddle
class ExampleNonStandardFormLocation(Behavior):
@plumb
def __call__(_next, self, model, request):
ajax_form_fiddle(request, '.some_selector', 'inner')
return _next(self, model, request)
And then use this behavior for form tiles.
@tile('exampleform', interface=ExampleNode, permission='edit')
@plumbing(ExampleNonStandardFormLocation)
class ExampleForm(Form):
pass