doc/book/en/B1020-define-views.en.txt
changeset 288 487bcc269d50
parent 229 767ff7f5d5a7
child 292 2d9e83c34b23
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/B1020-define-views.en.txt	Tue Dec 23 13:28:48 2008 -0800
@@ -0,0 +1,238 @@
+.. -*- coding: utf-8 -*-
+
+.. _DefinitionVues:
+
+Views definition
+================
+
+Basic class for views
+---------------------
+
+Class `View` (`cubicweb.common.view`)
+`````````````````````````````````````
+
+A view writes in its output exit thanks to its attribute `w` (`UStreamIO`).
+
+The basic interface for views is as follows:
+
+* `dispatch(**context)`, render the view by calling `call` or
+  `cell_call` depending on the given parameters
+* `call(**kwargs)`, call the view for a complete result set or null
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set
+* `url()`, returns the URL enabling us to get the view with the current
+  result set 
+* `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier 
+  `__vid` on the given result set. It is possible to give a view identifier
+  of fallback that will be used if the view requested is not applicable to the
+  result set
+  
+* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except
+  the flow is automatically passed in the parameters
+  
+* `html_headers()`, returns a list of HTML headers to set by the main template
+
+* `page_title()`, returns the title to use in the HTML header `title`
+
+* `creator(eid)`, returns the eid and the login of the entity creator of the entity
+  having the eid given in the parameter 
+
+Other basic classes:
+
+* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
+* `StartupView`, start view that does not require a result set to apply to
+* `AnyRsetView`, view applied to any result set 
+
+
+The selection view principle
+----------------------------
+
+A view includes :
+
+- an identifier (all objects in `LAX` are entered in a registry
+  and this identifier will be used as a key)
+  
+- a filter to select the resulsets it can be applied to
+
+
+For a given identifier, multiple views can be defined. `CubicWeb` uses
+a selector which computes scores so that it can identify and select the
+best view to apply in context. The selector library is in 
+``cubicweb.common.selector`` and a library of the methods used to
+compute scores is in ``cubicweb.vregistry.vreq``.
+
+
+`CubicWeb` provides a lot of standard views, for a complete list, you
+will have to read the code in directory ``cubicweb/web/views/`` (XXX
+improve doc).
+
+For example, the view named ``primary`` is the one used to display
+a single entity.
+
+If you want to change the way a ``BlogEntry`` is displayed, just
+override the view ``primary`` in ``BlogDemo/views.py`` ::
+
+  01. from ginco.web.views import baseviews
+  02.
+  03. class BlogEntryPrimaryView(baseviews.PrimaryView):
+  04.
+  05.     accepts = ('BlogEntry',)
+  06.
+  07.     def cell_call(self, row, col):
+  08.         entity = self.entity(row, col)
+  09.         self.w(u'<h1>%s</h1>' % entity.title)
+  10.         self.w(u'<p>published on %s in category %s</p>' % \
+  11.                (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
+  12.         self.w(u'<p>%s</p>' % entity.text)
+
+The above source code defines a new primary view (`line 03`) for
+``BlogEntry`` (`line 05`). 
+
+Since views are applied to resultsets and resulsets can be tables of
+data, it is needed to recover the entity from its (row,col)
+coordinates (`line 08`). We will get to this in more detail later.
+
+The view has a ``self.w()`` method that is used to output data. Here `lines
+09-12` output HTML tags and values of the entity's attributes.
+
+When displaying same blog entry as before, you will notice that the
+page is now looking much nicer.
+
+.. image:: images/lax-book.09-new-view-blogentry.en.png
+   :alt: blog entries now look much nicer
+
+Let us now improve the primary view of a blog ::
+
+  01. class BlogPrimaryView(baseviews.PrimaryView):
+  02. 
+  03.     accepts = ('Blog',)
+  04.
+  05.     def cell_call(self, row, col):
+  06.         entity = self.entity(row, col)
+  07.         self.w(u'<h1>%s</h1>' % entity.title)
+  08.         self.w(u'<p>%s</p>' % entity.description)
+  09.         rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
+  10.         self.wview('primary', rset)
+
+In the above source code, `lines 01-08` are similar to the previous
+view we defined.
+
+At `line 09`, a simple request in made to build a resultset with all
+the entities linked to the current ``Blog`` entity by the relationship
+``entry_of``. The part of the framework handling the request knows
+about the schema and infer that such entities have to be of the
+``BlogEntry`` kind and retrieves them.
+
+The request returns a selection of data called a resultset. At 
+`line 10` the view 'primary' is applied to this resultset to output
+HTML. 
+
+**This is to be compared to interfaces and protocols in object-oriented
+languages. Applying a given view to all the entities of a resultset only
+requires the availability, for each entity of this resultset, of a
+view with that name that can accepts the entity.**
+
+Assuming we added entries to the blog titled `MyLife`, displaying it
+now allows to read its description and all its entries.
+
+.. image:: images/lax-book.10-blog-with-two-entries.en.png
+   :alt: a blog and all its entries
+
+**Before we move forward, remember that the selection/view principle is
+at the core of `CubicWeb`. Everywhere in the engine, data is requested
+using the RQL language, then HTML/XML/text/PNG is output by applying a
+view to the resultset returned by the query. That is where most of the
+flexibility comes from.**
+
+[WRITE ME]
+
+* implementing interfaces, calendar for blog entries
+* show that a calendar view can export data to ical
+
+We will implement the cubicwweb.interfaces.ICalendarable interfaces on
+entities.BloEntry and apply the OneMonthCalendar and iCalendar views
+to resultsets like "Any E WHERE E is BlogEntry"
+
+* create view "blogentry table" with title, publish_date, category
+
+We will show that by default the view that displays 
+"Any E,D,C WHERE E publish_date D, E category C" is the table view.
+Of course, the same can be obtained by calling
+self.wview('table',rset)
+
+* in view blog, select blogentries and apply view "blogentry table"
+* demo ajax by filtering blogentry table on category
+
+we did the same with 'primary', but with tables we can turn on filters
+and show that ajax comes for free.
+[FILLME]
+
+
+Templates
+---------
+
+*Templates* are specific view that does not depend on a result set. The basic
+class `Template` (`cubicweb.common.view`) is derived from the class `View`.
+
+To build a HTML page, a *main template* is used. In general, the template of
+identifier `main` is the one (it is not used in case an error is raised or for
+the login form for example). This template uses other templates in addition
+to the views which depends on the content to generate the HTML page to return.
+
+A *template* is responsible for:
+
+1. executing RQL query of data to render if necessarry
+2. identifying the view to use to render data if it is not specified
+3. composing the HTML page to return
+
+
+The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`)
+------------------------------------------------------------------------------
+
+The default main template build the page based on the following pattern:
+
+.. image:: images/main_template_layout.png
+
+The rectangle containing `view.dispathc()` represents the area where the content
+view has to be displayed. The others represents sub-templates called to complete
+the page. A default implementation of those is provided in 
+`cubicweb.views.basetemplates`. You can, of course, overload those sub-templates
+to implement your own customization of the HTML page.
+
+We can also control certain aspects of the main template thanks to the following
+forms parameters:
+
+* `__notemplate`, if present (whatever the value assigned), only the content view
+  is returned
+* `__force_display`, if present and its value is not null, no navigation 
+  whatever the number of entities to display
+* `__method`, if the result set to render contains only one entity and this 
+  parameter is set, it refers to a method to call on the entity by passing it
+  the dictionnary of the forms parameters, before going the classic way (through
+  step 1 and 2 described juste above)
+
+.. include:: B031-views-stdlib.en.txt
+
+
+XML views, binaries...
+----------------------
+For the views generating other formats that HTML (an image generated dynamically
+for example), and which can not usually be included in the HTML page generated
+by the main template (see above), you have to:
+
+* set the atribute `templatable` of the class to `False`
+* set, through the attribute `content_type` of the class, the MIME type generated
+  by the view to `application/octet-stream`
+
+For the views dedicated to binary content creation (an image dynamically generated
+for example), we have to set the attribute `binary` of the class to `True` (which
+implies that `templateable == False`, so that the attribute `w` of the view could be
+replaced by a binary flow instead of unicode).
+
+(X)HTML tricks to apply
+-----------------------
+
+Some web browser (Firefox for example) are not happy with empty `<div>`
+(by empty we mean that there is no content in the tag, but there
+could be attributes), so we should always use `<div></div>` even if
+it is empty and not use `<div/>`.
+