doc/book/en/05-define-views.en.txt
changeset 93 9c919a47e140
child 102 ef84f6b2e4cf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/05-define-views.en.txt	Tue Nov 18 01:16:30 2008 +0100
@@ -0,0 +1,247 @@
+.. -*- coding: utf-8 -*-
+
+.. _DefinitionVues:
+
+Définition de vues
+==================
+
+Les classes de base des vues
+----------------------------
+
+La class `View` (`cubicweb.common.view`)
+````````````````````````````````````````
+Un vue écrit dans son flux de sortie via son attribut `w` (`UStreamIO`).
+
+L'interface de base des vues est la suivante :
+
+* `dispatch(**context)`, appelle ("rend") la vue en appellent `call` ou
+  `cell_call` en fonction des arguments passé
+* `call(**kwargs)`, appelle la vue pour un result set complet ou nul
+* `cell_call(row, col, **kwargs)`, appelle la vue pour une cellule donnée d'un
+  result set
+* `url()`, retourne l'url permettant d'obtenir cette vue avec le result set en
+  cours 
+* `view(__vid, rset, __fallback_vid=None, **kwargs)`, appelle la vue
+  d'identificant `__vid` sur le result set donné. Il est possible de données un
+  identificant de vue de "fallback" qui sera utilisé si la vue demandée n'est
+  pas applicable au result set
+  
+* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, pareil que `view` mais
+  passe automatiquement le flux en argument
+  
+* `html_headers()`, retourne une liste d'en-tête HTML à placer par le template
+  principal 
+
+* `page_title()`, retourne le titre à utiliser dans l'en tête HTML `title`
+
+* `creator(eid)`, retourne l'eid et le login du créateur de l'entité ayant
+  l'eid passé en argument
+
+Autres classes de base :
+
+* `EntityView`, vue s'appliquant à aux lignes ou cellule contenant une entité
+  (eg un eid)
+* `StartupView`, vue de départ n'ayant pas besoin de result set
+* `AnyRsetView`, vue s'appliquant à n'importe quelle result set
+
+Le mecanisme de selection de vues
+---------------------------------
+
+Pour un identifiant de vue donne, plusieurs vues peuvent etre definies.
+`CubicWeb` utilise un selecteur qui permet de calculer un score et d'identifier
+la vue la plus appropriee a appliquer dans le contexte. La librairie du selecteur
+se trouve dans ``cubicweb.common.selector`` et une librairie des methodes utilisees
+pour calculer les scores est dans ``cubicweb.vregistry.vreq``.
+
+[FROM-LAX-BOOK]
+
+Tip: when modifying views, you do not need to restart the local 
+server. Just save the file in your editor and reload the page in your
+browser to see the changes.
+
+With `LAX`, views are defined by Python classes. 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
+
+`LAX` provides a lot of standard views, for a complete list, you
+will have to read the code in directory ``ginco/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 `LAX`. 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 ginco.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]
+
+Les templates ou patron
+-----------------------
+
+Les patrons (ou *template*) sont des cas particulier de vue ne dépendant a
+priori pas d'un result set. La classe de base `Template` (`cubicweb.common.view`)
+est une classe dérivée de la classe `View`.
+
+Pour construire une page HTML, un *template principal* est utilisé. Généralement
+celui possédant l'identifiant 'main' est utilisé (ce n'est pas le cas lors
+d'erreur dans celui-ci ou pour le formulaire de login par exemple). Ce patron
+utilise d'autres patrons en plus des vues dépendants du contenu pour générer la
+page à renvoyer.
+
+C'est ce template qui est chargé :
+
+1. d'éxécuter la requête RQL des données à afficher le cas échéant
+2. éventuellement de déterminer la vue à utiliser pour l'afficher si non
+   spécifiée
+3. de composer la page à retourner
+
+
+Le patron principal par défaut (`cubicweb.web.views.basetemplates.TheMainTemplate`)
+-----------------------------------------------------------------------------------
+
+Le template principal par défaut construit la page selon la décomposition
+suivante :
+
+.. image:: images/main_template_layout.png
+
+Le rectancle contenant le `view.dispatch()` représente l'emplacement où est
+inséré la vue de contenu à afficher. Les autres représentent des sous-templates
+appelé pour construire la page. Les implémentations par défaut de tout ces
+templates sont dans le module `cubicweb.web.views.basetemplates`. Vous pouvez
+évidemment surcharger l'un des sous-templates pour modifier l'aspect visuel
+d'une partie désirée de la page.
+
+On peut également contrôler certains comportements du template principal à
+l'aide des paramètres de formulaire suivante :
+
+* `__notemplate`, si présente (quelque soit la valeur associée), seule la vue de
+  contenu est renvoyée
+* `__force_display`, si présente et contient une valeur non nulle, pas de
+  navigation quelque soit le nombre d'entités à afficher
+* `__method`, si le result set à afficher ne contient qu'une entité et que ce
+  paramètre est spécifié, celui-ci désigne une méthode à appeler sur l'entité
+  en lui donnant en argument le dictionnaire des paramètres de formulaire, avant
+  de reprendre le comportement classique (s'insère entre les étapes 1. et
+  2. décrites ci-dessus)
+
+
+.. include:: 05-01-views-stdlib.en.txt
+
+
+Vues xml, binaires...
+---------------------
+Pour les vues générants autre que du html  (une image générée dynamiquement par
+exemple), et qui ne peuvent donc généralement pas être incluse dans la page
+HTML générée par le template principal (voir ci-dessus), il faut :
+
+* placer l'attribut `templatable` de la classe à `False`
+* indiquer via l'attribut `content_type` de la classe le type MIME généré par la
+  vue 'application/octet-stream'
+
+Pour les vues générants un contenu binaire (une image générée dynamiquement par
+exemple), il faut également placer l'attribut `binary` de la classe à `True` (ce
+qui implique `templatable == False` afin que l'attribut `w` de la vue soit
+remplacé par un flux binaire plutôt que unicode.
+
+
+Quelques trucs (X)HTML à respecter
+----------------------------------
+Certains navigateurs (dont firefox) n'aime pas les `<div>` vides (par vide
+j'entend sans contenu dans la balise, il peut y avoir des attributs), faut
+toujours mettre `<div></div>` même s'il n'y a rien dedans, et non `<div/>`.