doc/book/en/development/devweb/js.rst
branchstable
changeset 5157 1202e6565aff
parent 5152 35e6878e2fd0
child 5186 f3c2cb460ad9
equal deleted inserted replaced
5156:0ec436cba1a6 5157:1202e6565aff
     2 
     2 
     3 Javascript
     3 Javascript
     4 ----------
     4 ----------
     5 
     5 
     6 *CubicWeb* uses quite a bit of javascript in its user interface and
     6 *CubicWeb* uses quite a bit of javascript in its user interface and
     7 ships with jquery (1.3.x) and parts of the jquery UI
     7 ships with jquery (1.3.x) and parts of the jquery UI library, plus a
     8 library, plus a number of homegrown files and also other thirparty
     8 number of homegrown files and also other thir party libraries.
     9 libraries.
       
    10 
     9 
    11 All javascript files are stored in cubicweb/web/data/. There are
    10 All javascript files are stored in cubicweb/web/data/. There are
    12 around thirty js files there. In a cube it goes to data/.
    11 around thirty js files there. In a cube it goes to data/.
    13 
    12 
    14 Obviously one does not want javascript pieces to be loaded all at
    13 Obviously one does not want javascript pieces to be loaded all at
    21 It is good practice to name cube specific js files after the name of
    20 It is good practice to name cube specific js files after the name of
    22 the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
    21 the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
    23 
    22 
    24 XXX external_resources variable (which needs love)
    23 XXX external_resources variable (which needs love)
    25 
    24 
    26 CubicWeb javascript api
    25 CubicWeb javascript API
    27 ~~~~~~~~~~~~~~~~~~~~~~~
    26 ~~~~~~~~~~~~~~~~~~~~~~~
    28 
    27 
    29 Javascript resources are typically loaded on demand, from views. The
    28 Javascript resources are typically loaded on demand, from views. The
    30 request object (available as self._cw from most application objects,
    29 request object (available as self._cw from most application objects,
    31 for instance views and entities objects) has a few methods to do that:
    30 for instance views and entities objects) has a few methods to do that:
    55     requests.
    54     requests.
    56 
    55 
    57 Important AJAX APIS
    56 Important AJAX APIS
    58 ~~~~~~~~~~~~~~~~~~~
    57 ~~~~~~~~~~~~~~~~~~~
    59 
    58 
       
    59 * `asyncRemoteExec` and `remoteExec` are the base building blocks for
       
    60   doing arbitrary async (resp. sync) communications with the server
       
    61 
       
    62 * `reloadComponent` is a convenience function to replace a DOM node
       
    63   with server supplied content coming from a specific registry (this
       
    64   is quite handy to refresh the content of some boxes for instances)
       
    65 
    60 * `jQuery.fn.loadxhtml` is an important extension to jQuery which
    66 * `jQuery.fn.loadxhtml` is an important extension to jQuery which
    61   allow proper loading and in-place DOM update of xhtml views. It is
    67   allows proper loading and in-place DOM update of xhtml views. It is
    62   suitably augmented to trigger necessary events, and process CubicWeb
    68   suitably augmented to trigger necessary events, and process CubicWeb
    63   specific elements such as the facet system, fckeditor, etc.
    69   specific elements such as the facet system, fckeditor, etc.
    64 
    70 
    65 * `asyncRemoteExec` and `remoteExec` are the base building blocks for
       
    66   doing arbitrary async (resp. sync) communications with the server
       
    67 
    71 
    68 A simple example with asyncRemoteExec
    72 A simple example with asyncRemoteExec
    69 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    73 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    70 
    74 
    71 In the python side, we have to extend the BaseController class. The
    75 In the python side, we have to extend the BaseController class. The
    87 error handling has to be done through the addCallback and addErrback
    91 error handling has to be done through the addCallback and addErrback
    88 methods.
    92 methods.
    89 
    93 
    90 .. sourcecode: javascript
    94 .. sourcecode: javascript
    91 
    95 
    92     function async_hello(name) {
    96     function asyncHello(name) {
    93         var deferred = asyncRemoteExec('say_hello', name);
    97         var deferred = asyncRemoteExec('say_hello', name);
    94         deferred.addCallback(function (response) {
    98         deferred.addCallback(function (response) {
    95             alert(response);
    99             alert(response);
    96         });
   100         });
    97         deferred.addErrback(function () {
   101         deferred.addErrback(function (error) {
    98             alert('something fishy happened');
   102             alert('something fishy happened');
    99         });
   103         });
   100      }
   104      }
   101 
   105 
   102      function sync_hello(name) {
   106      function syncHello(name) {
   103          alert( remoteExec('say_hello', name) );
   107          alert( remoteExec('say_hello', name) );
   104      }
   108      }
       
   109 
       
   110 Anatomy of a reloadComponent call
       
   111 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   112 
       
   113 `reloadComponent` allows to dynamically replace some DOM node with new
       
   114 elements. It has the following signature:
       
   115 
       
   116 * `compid` (mandatory) is the name of the component to be reloaded
       
   117 
       
   118 * `rql` (optional) will be used to generate a result set given as
       
   119   argument to the selected component
       
   120 
       
   121 * `registry` (optional) defaults to 'components' but can be any other
       
   122   valid registry name
       
   123 
       
   124 * `nodeid` (optional) defaults to compid + 'Component' but can be any
       
   125   explicitly specified DOM node id
       
   126 
       
   127 * `extraargs` (optional) should be a dictionary of values that will be
       
   128   given to the cell_call method of the component
       
   129 
       
   130 A simple reloadComponent example
       
   131 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   132 
       
   133 The server side implementation of `reloadComponent` is the
       
   134 js_component method of the JSonController.
       
   135 
       
   136 The following function implements a two-steps method to delete a
       
   137 standard bookmark and refresh the UI, while keeping the UI responsive.
       
   138 
       
   139 .. sourcecode:: javascript
       
   140 
       
   141     function removeBookmark(beid) {
       
   142         d = asyncRemoteExec('delete_bookmark', beid);
       
   143         d.addCallback(function(boxcontent) {
       
   144 	    reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
       
   145             document.location.hash = '#header';
       
   146             updateMessage(_("bookmark has been removed"));
       
   147          });
       
   148     }
       
   149 
       
   150 `reloadComponent` is called with the id of the bookmark box as
       
   151 argument, no rql expression (because the bookmarks display is actually
       
   152 independant of any dataset context), a reference to the 'boxes'
       
   153 registry (which hosts all left, right and contextual boxes) and
       
   154 finally an explicit 'bookmarks_box' nodeid argument that stipulates
       
   155 the target DOM node.
       
   156 
       
   157 Anatomy of a loadxhtml call
       
   158 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   159 
       
   160 `jQuery.fn.loadxhtml` is an important extension to jQuery which allows
       
   161 proper loading and in-place DOM update of xhtml views. The existing
       
   162 `jQuery.load`_ function does not handle xhtml, hence the addition. The
       
   163 API of loadxhtml is roughly similar to that of `jQuery.load`_.
       
   164 
       
   165 .. _`jQuery.load`: http://api.jquery.com/load/
       
   166 
       
   167 
       
   168 * `url` (mandatory) should be a complete url (typically referencing
       
   169   the JSonController, but this is not strictly mandatory)
       
   170 
       
   171 * `data` (optional) is a dictionary of values given to the
       
   172   controller specified through an `url` argument; some keys may have a
       
   173   special meaning depending on the choosen controller (such as `fname`
       
   174   for the JSonController); the `callback` key, if present, must refer
       
   175   to a function to be called at the end of loadxhtml (more on this
       
   176   below)
       
   177 
       
   178 * `reqtype` (optional) specifies the request method to be used (get or
       
   179   post); if the argument is 'post', then the post method is used,
       
   180   otherwise the get method is used
       
   181 
       
   182 * `mode` (optional) is one of `replace` (the default) which means the
       
   183   loaded node will replace the current node content, `swap` to replace
       
   184   the current node with the loaded node, and `append` which will
       
   185   append the loaded node to the current node content
       
   186 
       
   187 About the `callback` option:
       
   188 
       
   189 * it is called with two parameters: the current node, and a list
       
   190   containing the loaded (and post-processed node)
       
   191 
       
   192 * whenever is returns another function, this function is called in
       
   193   turn with the same parameters as above
       
   194 
       
   195 This mechanism allows callback chaining.
       
   196 
   105 
   197 
   106 A simple example with loadxhtml
   198 A simple example with loadxhtml
   107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   199 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   108 
   200 
   109 Here we are concerned with the retrieval of a specific view to be
   201 Here we are concerned with the retrieval of a specific view to be
   110 injected in the live DOM. The view will be of course selected
   202 injected in the live DOM. The view will be of course selected
   111 server-side using an entity eid provided by the client side.
   203 server-side using an entity eid provided by the client side.
   112 
   204 
   113 .. sourcecode: python
   205 .. sourcecode:: python
   114 
   206 
   115     from cubicweb import typed_eid
   207     from cubicweb import typed_eid
   116     from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
   208     from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
   117 
   209 
   118     @monkeypatch(JSonController)
   210     @monkeypatch(JSonController)
   119     @xhtmlize
   211     @xhtmlize
   120     def js_frob_status(self, eid, frobname):
   212     def js_frob_status(self, eid, frobname):
   121         entity = self._cw.entity_from_eid(typed_eid(eid))
   213         entity = self._cw.entity_from_eid(typed_eid(eid))
   122         return entity.view('frob', name=frobname)
   214         return entity.view('frob', name=frobname)
   123 
   215 
   124 .. sourcecode: javascript
   216 .. sourcecode:: javascript
   125 
   217 
   126     function update_some_div(divid, eid, frobname) {
   218     function update_some_div(divid, eid, frobname) {
   127         var params = {fname:'frob_status', eid: eid, frobname:frobname};
   219         var params = {fname:'frob_status', eid: eid, frobname:frobname};
   128         jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
   220         jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
   129      }
   221      }
   130 
   222 
   131 In this example, the url argument is the base json url of a cube
   223 In this example, the url argument is the base json url of a cube
   132 instance (it should contain something like
   224 instance (it should contain something like
   133 `http://myinstance/json?`). The actual JSonController method name is
   225 `http://myinstance/json?`). The actual JSonController method name is
   134 encoded in the `params` dictionnary using the `fname` key.
   226 encoded in the `params` dictionary using the `fname` key.
   135 
   227 
   136 A more real-life example from CubicWeb
   228 A more real-life example from CubicWeb
   137 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   229 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   138 
   230 
   139 A frequent use case of Web 2 applications is the delayed (or
   231 A frequent use case of Web 2 applications is the delayed (or
   142 and proper use of loadxhtml.
   234 and proper use of loadxhtml.
   143 
   235 
   144 We present here a skeletal version of the mecanism used in CubicWeb
   236 We present here a skeletal version of the mecanism used in CubicWeb
   145 and available in web/views/tabs.py, in the `LazyViewMixin` class.
   237 and available in web/views/tabs.py, in the `LazyViewMixin` class.
   146 
   238 
   147 .. sourcecode: python
   239 .. sourcecode:: python
   148 
   240 
   149     def lazyview(self, vid, rql=None):
   241     def lazyview(self, vid, rql=None):
   150         """ a lazy version of wview """
   242         """ a lazy version of wview """
   151         w = self.w
   243         w = self.w
   152         self._cw.add_js('cubicweb.lazy.js')
   244         self._cw.add_js('cubicweb.lazy.js')
   159         self._cw.add_onload(u"""
   251         self._cw.add_onload(u"""
   160             jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
   252             jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
   161                    load_now('#lazy-%(vid)s');});"""
   253                    load_now('#lazy-%(vid)s');});"""
   162             % {'event': 'load_%s' % vid, 'vid': vid})
   254             % {'event': 'load_%s' % vid, 'vid': vid})
   163 
   255 
   164 This creates a `div` with an specific event associated to it.
   256 This creates a `div` with a specific event associated to it.
   165 
   257 
   166 The full version deals with:
   258 The full version deals with:
   167 
   259 
   168 * optional parameters such as an entity eid, an rset
   260 * optional parameters such as an entity eid, an rset
   169 
   261 
   175 * handling of browsers that do not support ajax (search engines,
   267 * handling of browsers that do not support ajax (search engines,
   176   text-based browsers such as lynx, etc.)
   268   text-based browsers such as lynx, etc.)
   177 
   269 
   178 The javascript side is quite simple, due to loadxhtml awesomeness.
   270 The javascript side is quite simple, due to loadxhtml awesomeness.
   179 
   271 
   180 .. sourcecode: javascript
   272 .. sourcecode:: javascript
   181 
   273 
   182     function load_now(eltsel) {
   274     function load_now(eltsel) {
   183         var lazydiv = jQuery(eltsel);
   275         var lazydiv = jQuery(eltsel);
   184         lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
   276         lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
   185     }
   277     }
   203 Given all this, it is easy to add a small nevertheless useful feature
   295 Given all this, it is easy to add a small nevertheless useful feature
   204 to force the loading of a lazy view (for instance, a very
   296 to force the loading of a lazy view (for instance, a very
   205 computation-intensive web page could be scinded into one fast-loading
   297 computation-intensive web page could be scinded into one fast-loading
   206 part and a delayed part).
   298 part and a delayed part).
   207 
   299 
   208 In the server side, a simple call to a javascript function is
   300 On the server side, a simple call to a javascript function is
   209 sufficient.
   301 sufficient.
   210 
   302 
   211 .. sourcecode: python
   303 .. sourcecode:: python
   212 
   304 
   213     def forceview(self, vid):
   305     def forceview(self, vid):
   214         """trigger an event that will force immediate loading of the view
   306         """trigger an event that will force immediate loading of the view
   215         on dom readyness
   307         on dom readyness
   216         """
   308         """
   217         self._cw.add_onload("trigger_load('%s');" % vid)
   309         self._cw.add_onload("trigger_load('%s');" % vid)
   218 
   310 
   219 The browser-side definition follows.
   311 The browser-side definition follows.
   220 
   312 
   221 .. sourcecode: javascript
   313 .. sourcecode:: javascript
   222 
   314 
   223     function trigger_load(divid) {
   315     function trigger_load(divid) {
   224         jQuery('#lazy-' + divd).trigger('load_' + divid);
   316         jQuery('#lazy-' + divd).trigger('load_' + divid);
   225     }
   317     }
   226 
   318 
   227 
   319 
   228 Anatomy of a lodxhtml call
   320 
   229 ~~~~~~~~~~~~~~~~~~~~~~~~~~
   321 
   230 
   322 XXX reloadComponent
   231 The loadxhtml extension to jQuery accept many parameters with rich
   323 XXX userCallback / user_callback
   232 semantics. Let us detail these.
       
   233 
       
   234 * `url` (mandatory) should be a complete url, typically based on the
       
   235   JSonController, but this is not strictly mandatory
       
   236 
       
   237 * `data` (optional) is a dictionnary of values given to the
       
   238   controller specified through an `url` argument; some keys may have a
       
   239   special meaning depending on the choosen controller (such as `fname`
       
   240   for the JSonController); the `callback` key, if present, must refer
       
   241   to a function to be called at the end of loadxhtml (more on this
       
   242   below)
       
   243 
       
   244 * `reqtype` (optional) specifies the request method to be used (get or
       
   245   post); if the argument is 'post', then the post method is used,
       
   246   otherwise the get method is used
       
   247 
       
   248 * `mode` (optional) is one of `replace` (the default) which means the
       
   249   loaded node will replace the current node content, `swap` to replace
       
   250   the current node with the loaded node, and `append` which will
       
   251   append the loaded node to the current node content
       
   252 
       
   253 
       
   254 About the `callback` option:
       
   255 
       
   256 * it is called with two parameters: the current node, and a list
       
   257   containing the loaded (and post-processed node)
       
   258 
       
   259 * whenever is returns another function, this function is called in
       
   260   turn with the same parameters as above
       
   261 
       
   262 This mecanism allows callback chaining.
       
   263 
       
   264 
   324 
   265 Javascript library: overview
   325 Javascript library: overview
   266 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   326 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   267 
   327 
   268 * jquery.* : jquery and jquery UI library
   328 * jquery.* : jquery and jquery UI library