diff -r 7a9e71ee5671 -r 2f70fa8b6854 doc/book/en/development/devweb/js.rst --- a/doc/book/en/development/devweb/js.rst Tue Apr 06 10:29:41 2010 +0200 +++ b/doc/book/en/development/devweb/js.rst Tue Apr 06 15:11:51 2010 +0200 @@ -54,12 +54,225 @@ ajax request, otherwise the document itself for standard HTTP requests. +Important AJAX APIS +~~~~~~~~~~~~~~~~~~~ -Overview of what's available +* `jQuery.fn.loadxhtml` is an important extension to jQuery which + allow proper loading and in-place DOM update of xhtml views. It is + suitably augmented to trigger necessary events, and process CubicWeb + specific elements such as the facet system, fckeditor, etc. + +* `asyncRemoteExec` and `remoteExec` are the base building blocks for + doing arbitrary async (resp. sync) communications with the server + +A simple example with asyncRemoteExec +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the python side, we have to extend the BaseController class. The +@jsonize decorator ensures that the `return value` of the method is +encoded as JSON data. By construction, the JSonController inputs +everything in JSON format. + +.. sourcecode: python + + from cubicweb.web.views.basecontrollers import JSonController, jsonize + + @monkeypatch(JSonController) + @jsonize + def js_say_hello(self, name): + return u'hello %s' % name + +In the javascript side, we do the asynchronous call. Notice how it +creates a `deferred` object. Proper treatment of the return value or +error handling has to be done through the addCallback and addErrback +methods. + +.. sourcecode: javascript + + function async_hello(name) { + var deferred = asyncRemoteExec('say_hello', name); + deferred.addCallback(function (response) { + alert(response); + }); + deferred.addErrback(function () { + alert('something fishy happened'); + }); + } + + function sync_hello(name) { + alert( remoteExec('say_hello', name) ); + } + +A simple example with loadxhtml +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here we are concerned with the retrieval of a specific view to be +injected in the live DOM. The view will be of course selected +server-side using an entity eid provided by the client side. + +.. sourcecode: python + + from cubicweb import typed_eid + from cubicweb.web.views.basecontrollers import JSonController, xhtmlize + + @monkeypatch(JSonController) + @xhtmlize + def js_frob_status(self, eid, frobname): + entity = self._cw.entity_from_eid(typed_eid(eid)) + return entity.view('frob', name=frobname) + +.. sourcecode: javascript + + function update_some_div(divid, eid, frobname) { + var params = {fname:'frob_status', eid: eid, frobname:frobname}; + jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post'); + } + +In this example, the url argument is the base json url of a cube +instance (it should contain something like +`http://myinstance/json?`). The actual JSonController method name is +encoded in the `params` dictionnary using the `fname` key. + +A more real-life example from CubicWeb +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A frequent use case of Web 2 applications is the delayed (or +on-demand) loading of pieces of the DOM. This is typically achieved +using some preparation of the initial DOM nodes, jQuery event handling +and proper use of loadxhtml. + +We present here a skeletal version of the mecanism used in CubicWeb +and available in web/views/tabs.py, in the `LazyViewMixin` class. + +.. sourcecode: python + + def lazyview(self, vid, rql=None): + """ a lazy version of wview """ + w = self.w + self._cw.add_js('cubicweb.lazy.js') + urlparams = {'vid' : vid, 'fname' : 'view'} + if rql is not None: + urlparams['rql'] = rql + w(u'
' % ( + vid, xml_escape(self._cw.build_url('json', **urlparams)))) + w(u'
') + self._cw.add_onload(u""" + jQuery('#lazy-%(vid)s').bind('%(event)s', function() { + load_now('#lazy-%(vid)s');});""" + % {'event': 'load_%s' % vid, 'vid': vid}) + +This creates a `div` with an specific event associated to it. + +The full version deals with: + +* optional parameters such as an rql expression, an entity eid, an + rset + +* the ability to further reload the fragment + +* the ability to display a spinning wheel while the fragment is still + not loaded + +* handling of browsers that do not support ajax (search engines, + text-based browsers such as lynx, etc.) + +The javascript side is quite simple, due to loadxhtml awesomeness. + +.. sourcecode: javascript + + function load_now(eltsel) { + var lazydiv = jQuery(eltsel); + lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl')); + } + +This is all significantly different of the previous `simple example` +(albeit this example actually comes from real-life code). + +Notice how the `cubicweb:loadurl` is used to convey the url +information. The base of this url is similar to the global javascript +JSON_BASE_URL. According to the pattern described earlier, +the `fname` parameter refers to the standard `js_view` method of the +JSonController. This method renders an arbitrary view provided a view +id (or `vid`) is provided, and most likely an rql expression yielding +a result set against which a proper view instance will be selected. + +The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML +in a specific cubicweb namespace. It is a means to pass information +without breaking HTML nor XHTML compliance and without resorting to +ungodly hacks. + +Given all this, it is easy to add a small nevertheless useful feature +to force the loading of a lazy view (for instance, a very +computation-intensive web page could be scinded into one fast-loading +part and a delayed part). + +In the server side, a simple call to a javascript function is +sufficient. + +.. sourcecode: python + + def forceview(self, vid): + """trigger an event that will force immediate loading of the view + on dom readyness + """ + self._cw.add_onload("trigger_load('%s');" % vid) + +The browser-side definition follows. + +.. sourcecode: javascript + + function trigger_load(divid) { + jQuery('#lazy-' + divd).trigger('load_' + divid); + } + + +Anatomy of a lodxhtml call +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The loadxhtml extension to jQuery accept many parameters with rich +semantics. Let us detail these. + +* `url` (mandatory) should be a complete url, typically based on the + JSonController, but this is not strictly mandatory + +* `data` (optional) is a dictionnary of values given to the + controller specified through an `url` argument; some keys may have a + special meaning depending on the choosen controller (such as `fname` + for the JSonController); the `callback` key, if present, must refer + to a function to be called at the end of loadxhtml (more on this + below) + +* `reqtype` (optional) specifies the request method to be used (get or + post); if the argument is 'post', then the post method is used, + otherwise the get method is used + +* `mode` (optional) is one of `replace` (the default) which means the + loaded node will replace the current node content, `swap` to replace + the current node with the loaded node, and `append` which will + append the loaded node to the current node content + + +About the `callback` option: + +* it is called with two parameters: the current node, and a list + containing the loaded (and post-processed node) + +* whenever is returns another function, this function is called in + turn with the same parameters as above + +This mecanism allows callback chaining. + + +Javascript library: overview ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * jquery.* : jquery and jquery UI library +* cubicweb.ajax.js : concentrates all ajax related facilities (it + extends jQuery with the loahxhtml function, provides a handfull of + high-level ajaxy operations like asyncRemoteExec, reloadComponent, + replacePageChunk, getDomFromResponse) + * cubicweb.python.js : adds a number of practical extension to stdanrd javascript objects (on Date, Array, String, some list and dictionary operations), and a pythonesque way to build classes. Defines a @@ -69,11 +282,6 @@ in various other cubicweb javascript resources (baseuri, progress cursor handling, popup login box, html2dom function, etc.) -* cubicweb.ajax.js : concentrates all ajax related facilities (it - extends jQuery with the loahxhtml function, provides a handfull of - high-level ajaxy operations like asyncRemoteExec, reloadComponent, - replacePageChunk, getDomFromResponse) - * cubicweb.widgets.js : provides a widget namespace and constructors and helpers for various widgets (mainly facets and timeline) @@ -83,5 +291,6 @@ * cubicweb.facets.js : used by the facets mechanism -xxx massmailing, gmap, fckcwconfig, timeline-bundle, timeline-ext, -calendar, goa, flotn tazy, tabs, bookmarks +There is also javascript support for massmailing, gmap (google maps), +fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over +AppEngine), flot (charts drawing), tabs and bookmarks.