--- a/doc/book/en/devweb/js.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,394 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Javascript
-----------
-
-*CubicWeb* uses quite a bit of javascript in its user interface and
-ships with jquery (1.3.x) and parts of the jquery UI library, plus a
-number of homegrown files and also other third party libraries.
-
-All javascript files are stored in cubicweb/web/data/. There are
-around thirty js files there. In a cube it goes to data/.
-
-Obviously one does not want javascript pieces to be loaded all at
-once, hence the framework provides a number of mechanisms and
-conventions to deal with javascript resources.
-
-Conventions
-~~~~~~~~~~~
-
-It is good practice to name cube specific js files after the name of
-the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
-
-.. XXX external_resources variable (which needs love)
-
-Server-side Javascript API
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Javascript resources are typically loaded on demand, from views. The
-request object (available as self._cw from most application objects,
-for instance views and entities objects) has a few methods to do that:
-
-* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
- javascript files and writes proper entries into the HTML header
- section. The localfile parameter allows to declare resources which
- are not from web/data (for instance, residing on a content delivery
- network).
-
-* `add_onload(self, jscode)` which adds one raw javascript code
- snippet inline in the html headers. This is quite useful for setting
- up early jQuery(document).ready(...) initialisations.
-
-Javascript events
-~~~~~~~~~~~~~~~~~
-
-* ``server-response``: this event is triggered on HTTP responses (both
- standard and ajax). The two following extra parameters are passed
- to callbacks :
-
- - ``ajax``: a boolean that says if the reponse was issued by an
- ajax request
-
- - ``node``: the DOM node returned by the server in case of an
- ajax request, otherwise the document itself for standard HTTP
- requests.
-
-Important javascript AJAX APIS
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* `asyncRemoteExec` and `remoteExec` are the base building blocks for
- doing arbitrary async (resp. sync) communications with the server
-
-* `reloadComponent` is a convenience function to replace a DOM node
- with server supplied content coming from a specific registry (this
- is quite handy to refresh the content of some boxes for instances)
-
-* `jQuery.fn.loadxhtml` is an important extension to jQuery which
- allows 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.
-
-
-A simple example with asyncRemoteExec
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-On the python side, we have to define an
-:class:`cubicweb.web.views.ajaxcontroller.AjaxFunction` object. The
-simplest way to do that is to use the
-:func:`cubicweb.web.views.ajaxcontroller.ajaxfunc` decorator (for more
-details on this, refer to :ref:`ajax`).
-
-.. sourcecode: python
-
- from cubicweb.web.views.ajaxcontroller import ajaxfunc
-
- # serialize output to json to get it back easily on the javascript side
- @ajaxfunc(output_type='json')
- def js_say_hello(self, name):
- return u'hello %s' % name
-
-On 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 asyncHello(name) {
- var deferred = asyncRemoteExec('say_hello', name);
- deferred.addCallback(function (response) {
- alert(response);
- });
- deferred.addErrback(function (error) {
- alert('something fishy happened');
- });
- }
-
- function syncHello(name) {
- alert( remoteExec('say_hello', name) );
- }
-
-Anatomy of a reloadComponent call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`reloadComponent` allows to dynamically replace some DOM node with new
-elements. It has the following signature:
-
-* `compid` (mandatory) is the name of the component to be reloaded
-
-* `rql` (optional) will be used to generate a result set given as
- argument to the selected component
-
-* `registry` (optional) defaults to 'components' but can be any other
- valid registry name
-
-* `nodeid` (optional) defaults to compid + 'Component' but can be any
- explicitly specified DOM node id
-
-* `extraargs` (optional) should be a dictionary of values that will be
- given to the cell_call method of the component
-
-A simple reloadComponent example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The server side implementation of `reloadComponent` is the
-:func:`cubicweb.web.views.ajaxcontroller.component` *AjaxFunction* appobject.
-
-The following function implements a two-steps method to delete a
-standard bookmark and refresh the UI, while keeping the UI responsive.
-
-.. sourcecode:: javascript
-
- function removeBookmark(beid) {
- d = asyncRemoteExec('delete_bookmark', beid);
- d.addCallback(function(boxcontent) {
- reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
- document.location.hash = '#header';
- updateMessage(_("bookmark has been removed"));
- });
- }
-
-`reloadComponent` is called with the id of the bookmark box as
-argument, no rql expression (because the bookmarks display is actually
-independant of any dataset context), a reference to the 'boxes'
-registry (which hosts all left, right and contextual boxes) and
-finally an explicit 'bookmarks_box' nodeid argument that stipulates
-the target DOM node.
-
-Anatomy of a loadxhtml call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
-proper loading and in-place DOM update of xhtml views. The existing
-`jQuery.load`_ function does not handle xhtml, hence the addition. The
-API of loadxhtml is roughly similar to that of `jQuery.load`_.
-
-.. _`jQuery.load`: http://api.jquery.com/load/
-
-
-* `url` (mandatory) should be a complete url (typically referencing
- the :class:`cubicweb.web.views.ajaxcontroller.AjaxController`,
- but this is not strictly mandatory)
-
-* `data` (optional) is a dictionary 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 it returns another function, this function is called in
- turn with the same parameters as above
-
-This mechanism allows callback chaining.
-
-
-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.web.views.ajaxcontroller import ajaxfunc
-
- @ajaxfunc(output_type='xhtml')
- def frob_status(self, eid, frobname):
- entity = self._cw.entity_from_eid(eid)
- return entity.view('frob', name=frobname)
-
-.. sourcecode:: javascript
-
- function updateSomeDiv(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/ajax?`). The actual AjaxController method name is
-encoded in the `params` dictionary using the `fname` key.
-
-A more real-life example
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-A frequent need of Web 2 applications is the delayed (or demand
-driven) 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'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
- vid, xml_escape(self._cw.build_url('json', **urlparams))))
- w(u'</div>')
- self._cw.add_onload(u"""
- jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
- loadNow('#lazy-%(vid)s');});"""
- % {'event': 'load_%s' % vid, 'vid': vid})
-
-This creates a `div` with a specific event associated to it.
-
-The full version deals with:
-
-* optional parameters such as 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 loadNow(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).
-
-On 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("triggerLoad('%s');" % vid)
-
-The browser-side definition follows.
-
-.. sourcecode:: javascript
-
- function triggerLoad(divid) {
- jQuery('#lazy-' + divd).trigger('load_' + divid);
- }
-
-
-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
- CubicWeb namespace.
-
-* cubicweb.htmlhelpers.js : a small bag of convenience functions used
- in various other cubicweb javascript resources (baseuri, progress
- cursor handling, popup login box, html2dom function, etc.)
-
-* cubicweb.widgets.js : provides a widget namespace and constructors
- and helpers for various widgets (mainly facets and timeline)
-
-* cubicweb.edition.js : used by edition forms
-
-* cubicweb.preferences.js : used by the preference form
-
-* cubicweb.facets.js : used by the facets mechanism
-
-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.
-
-API
-~~~
-
-.. toctree::
- :maxdepth: 1
-
- js_api/index
-
-
-Testing javascript
-~~~~~~~~~~~~~~~~~~
-
-You with the ``cubicweb.qunit.QUnitTestCase`` can include standard Qunit tests
-inside the python unittest run . You simply have to define a new class that
-inherit from ``QUnitTestCase`` and register your javascript test file in the
-``all_js_tests`` lclass attribut. This ``all_js_tests`` is a sequence a
-3-tuple (<test_file, [<dependencies> ,] [<data_files>]):
-
-The <test_file> should contains the qunit test. <dependencies> defines the list
-of javascript file that must be imported before the test script. Dependencies
-are included their definition order. <data_files> are additional files copied in the
-test directory. both <dependencies> and <data_files> are optionnal.
-``jquery.js`` is preincluded in for all test.
-
-.. sourcecode:: python
-
- from cubicweb.qunit import QUnitTestCase
-
- class MyQUnitTest(QUnitTestCase):
-
- all_js_tests = (
- ("relative/path/to/my_simple_testcase.js",)
- ("relative/path/to/my_qunit_testcase.js",(
- "rel/path/to/dependency_1.js",
- "rel/path/to/dependency_2.js",)),
- ("relative/path/to/my_complexe_qunit_testcase.js",(
- "rel/path/to/dependency_1.js",
- "rel/path/to/dependency_2.js",
- ),(
- "rel/path/file_dependency.html",
- "path/file_dependency.json")
- ),
- )