doc/tutorials/advanced/part05_ui-advanced.rst
changeset 12405 99e150b6a876
parent 10491 c67bcee93248
child 12407 d4e0af0b5ad7
equal deleted inserted replaced
12404:83d7752af56a 12405:99e150b6a876
    58 to customize it to write that ``img`` tag, as below:
    58 to customize it to write that ``img`` tag, as below:
    59 
    59 
    60 .. sourcecode:: python
    60 .. sourcecode:: python
    61 
    61 
    62     class HTMLPageHeader(basetemplates.HTMLPageHeader):
    62     class HTMLPageHeader(basetemplates.HTMLPageHeader):
    63 	# override this since it's the easier way to have our bg image
    63         # override this since it's the easier way to have our bg image
    64 	# as the first element following <body>
    64         # as the first element following <body>
    65 	def call(self, **kwargs):
    65         def call(self, **kwargs):
    66             self.w(u'<img id="bg-image" src="%sbackground.jpg" alt="background image"/>'
    66             self.w(u'<img id="bg-image" src="%sbackground.jpg" alt="background image"/>'
    67                    % self._cw.datadir_url)
    67                    % self._cw.datadir_url)
    68 	    super(HTMLPageHeader, self).call(**kwargs)
    68             super(HTMLPageHeader, self).call(**kwargs)
    69 
    69 
    70 
    70 
    71     def registration_callback(vreg):
    71     def registration_callback(vreg):
    72 	vreg.register_all(globals().values(), __name__, (HTMLPageHeader))
    72         vreg.register_all(globals().values(), __name__, (HTMLPageHeader))
    73 	vreg.register_and_replace(HTMLPageHeader, basetemplates.HTMLPageHeader)
    73         vreg.register_and_replace(HTMLPageHeader, basetemplates.HTMLPageHeader)
    74 
    74 
    75 
    75 
    76 As you may have guessed, my background image is in a :file:`background.jpg` file
    76 As you may have guessed, my background image is in a :file:`background.jpg` file
    77 in the cube's :file:`data` directory, but there are still some things to explain
    77 in the cube's :file:`data` directory, but there are still some things to explain
    78 to newcomers here:
    78 to newcomers here:
   102      *
   102      *
   103      * syt update: set z-index=0 on the img instead of z-index=1 on div#page & co to
   103      * syt update: set z-index=0 on the img instead of z-index=1 on div#page & co to
   104      * avoid pb with the user actions menu
   104      * avoid pb with the user actions menu
   105      */
   105      */
   106     img#bg-image {
   106     img#bg-image {
   107 	position: fixed;
   107         position: fixed;
   108 	top: 0;
   108         top: 0;
   109 	left: 0;
   109         left: 0;
   110 	width: 100%;
   110         width: 100%;
   111 	height: 100%;
   111         height: 100%;
   112 	z-index: 0;
   112         z-index: 0;
   113     }
   113     }
   114 
   114 
   115     div#page, table#header, div#footer {
   115     div#page, table#header, div#footer {
   116 	background: transparent;
   116         background: transparent;
   117 	position: relative;
   117         position: relative;
   118     }
   118     }
   119 
   119 
   120     /* add some space around the logo
   120     /* add some space around the logo
   121      */
   121      */
   122     img#logo {
   122     img#logo {
   123 	padding: 5px 15px 0px 15px;
   123         padding: 5px 15px 0px 15px;
   124     }
   124     }
   125 
   125 
   126     /* more dark font for metadata to have a chance to see them with the background
   126     /* more dark font for metadata to have a chance to see them with the background
   127      *  image
   127      *  image
   128      */
   128      */
   129     div.metadata {
   129     div.metadata {
   130 	color: black;
   130         color: black;
   131     }
   131     }
   132 
   132 
   133 You can see here stuff explained in the cited page, with only a slight modification
   133 You can see here stuff explained in the cited page, with only a slight modification
   134 explained in the comments, plus some additional rules to make things somewhat cleaner:
   134 explained in the comments, plus some additional rules to make things somewhat cleaner:
   135 
   135 
   190 
   190 
   191   from cubicweb.predicates import none_rset
   191   from cubicweb.predicates import none_rset
   192   from cubicweb.web.views import bookmark
   192   from cubicweb.web.views import bookmark
   193   from cubes.zone import views as zone
   193   from cubes.zone import views as zone
   194   from cubes.tag import views as tag
   194   from cubes.tag import views as tag
       
   195 
   195 
   196 
   196   # change bookmarks box selector so it's only displayed on startup views
   197   # change bookmarks box selector so it's only displayed on startup views
   197   bookmark.BookmarksBox.__select__ = bookmark.BookmarksBox.__select__ & none_rset()
   198   bookmark.BookmarksBox.__select__ = bookmark.BookmarksBox.__select__ & none_rset()
   198   # move zone box to the left instead of in the context frame and tweak its order
   199   # move zone box to the left instead of in the context frame and tweak its order
   199   zone.ZoneBox.context = 'left'
   200   zone.ZoneBox.context = 'left'
   214     from logilab.common.decorators import monkeypatch
   215     from logilab.common.decorators import monkeypatch
   215     from cubicweb import ValidationError
   216     from cubicweb import ValidationError
   216     from cubicweb.web.views import uicfg, component
   217     from cubicweb.web.views import uicfg, component
   217     from cubicweb.web.views import basecontrollers
   218     from cubicweb.web.views import basecontrollers
   218 
   219 
       
   220 
   219     # hide displayed_on relation using uicfg since it will be displayed by the box below
   221     # hide displayed_on relation using uicfg since it will be displayed by the box below
   220     uicfg.primaryview_section.tag_object_of(('*', 'displayed_on', '*'), 'hidden')
   222     uicfg.primaryview_section.tag_object_of(('*', 'displayed_on', '*'), 'hidden')
   221 
   223 
       
   224 
   222     class PersonBox(component.AjaxEditRelationCtxComponent):
   225     class PersonBox(component.AjaxEditRelationCtxComponent):
   223 	__regid__ = 'sytweb.displayed-on-box'
   226         __regid__ = 'sytweb.displayed-on-box'
   224 	# box position
   227         # box position
   225 	order = 101
   228         order = 101
   226 	context = 'left'
   229         context = 'left'
   227 	# define relation to be handled
   230         # define relation to be handled
   228 	rtype = 'displayed_on'
   231         rtype = 'displayed_on'
   229 	role = 'object'
   232         role = 'object'
   230 	target_etype = 'Person'
   233         target_etype = 'Person'
   231 	# messages
   234         # messages
   232 	added_msg = _('person has been added')
   235         added_msg = _('person has been added')
   233 	removed_msg = _('person has been removed')
   236         removed_msg = _('person has been removed')
   234 	# bind to js_* methods of the json controller
   237         # bind to js_* methods of the json controller
   235 	fname_vocabulary = 'unrelated_persons'
   238         fname_vocabulary = 'unrelated_persons'
   236 	fname_validate = 'link_to_person'
   239         fname_validate = 'link_to_person'
   237 	fname_remove = 'unlink_person'
   240         fname_remove = 'unlink_person'
   238 
   241 
   239 
   242 
   240     @monkeypatch(basecontrollers.JSonController)
   243     @monkeypatch(basecontrollers.JSonController)
   241     @basecontrollers.jsonize
   244     @basecontrollers.jsonize
   242     def js_unrelated_persons(self, eid):
   245     def js_unrelated_persons(self, eid):
   243 	"""return tag unrelated to an entity"""
   246         """return tag unrelated to an entity"""
   244 	rql = "Any F + ' ' + S WHERE P surname S, P firstname F, X eid %(x)s, NOT P displayed_on X"
   247         rql = "Any F + ' ' + S WHERE P surname S, P firstname F, X eid %(x)s, NOT P displayed_on X"
   245 	return [name for (name,) in self._cw.execute(rql, {'x' : eid})]
   248         return [name for (name,) in self._cw.execute(rql, {'x' : eid})]
   246 
   249 
   247 
   250 
   248     @monkeypatch(basecontrollers.JSonController)
   251     @monkeypatch(basecontrollers.JSonController)
   249     def js_link_to_person(self, eid, people):
   252     def js_link_to_person(self, eid, people):
   250 	req = self._cw
   253         req = self._cw
   251 	for name in people:
   254         for name in people:
   252 	    name = name.strip().title()
   255             name = name.strip().title()
   253 	    if not name:
   256             if not name:
   254 		continue
   257                 continue
   255 	    try:
   258             try:
   256 		firstname, surname = name.split(None, 1)
   259                 firstname, surname = name.split(None, 1)
   257 	    except:
   260             except:
   258 		raise ValidationError(eid, {('displayed_on', 'object'): 'provide <first name> <surname>'})
   261                 raise ValidationError(eid, {('displayed_on', 'object'): 'provide <first name> <surname>'})
   259 	    rset = req.execute('Person P WHERE '
   262             rset = req.execute('Person P WHERE '
   260 			       'P firstname %(firstname)s, P surname %(surname)s',
   263                                'P firstname %(firstname)s, P surname %(surname)s',
   261 			       locals())
   264                                locals())
   262 	    if rset:
   265             if rset:
   263 		person = rset.get_entity(0, 0)
   266                 person = rset.get_entity(0, 0)
   264 	    else:
   267             else:
   265 		person = req.create_entity('Person', firstname=firstname,
   268                 person = req.create_entity('Person', firstname=firstname,
   266 						surname=surname)
   269                                                 surname=surname)
   267 	    req.execute('SET P displayed_on X WHERE '
   270             req.execute('SET P displayed_on X WHERE '
   268 			'P eid %(p)s, X eid %(x)s, NOT P displayed_on X',
   271                         'P eid %(p)s, X eid %(x)s, NOT P displayed_on X',
   269 			{'p': person.eid, 'x' : eid})
   272                         {'p': person.eid, 'x' : eid})
       
   273 
   270 
   274 
   271     @monkeypatch(basecontrollers.JSonController)
   275     @monkeypatch(basecontrollers.JSonController)
   272     def js_unlink_person(self, eid, personeid):
   276     def js_unlink_person(self, eid, personeid):
   273 	self._cw.execute('DELETE P displayed_on X WHERE P eid %(p)s, X eid %(x)s',
   277         self._cw.execute('DELETE P displayed_on X WHERE P eid %(p)s, X eid %(x)s',
   274 			 {'p': personeid, 'x': eid})
   278                          {'p': personeid, 'x': eid})
   275 
   279 
   276 
   280 
   277 You basically subclass to configure with some class attributes. The `fname_*`
   281 You basically subclass to configure with some class attributes. The `fname_*`
   278 attributes give the name of methods that should be defined on the json control to
   282 attributes give the name of methods that should be defined on the json control to
   279 make the AJAX part of the widget work: one to get the vocabulary, one to add a
   283 make the AJAX part of the widget work: one to get the vocabulary, one to add a
   325 
   329 
   326 .. sourcecode:: python
   330 .. sourcecode:: python
   327 
   331 
   328     from cubicweb.web import facet
   332     from cubicweb.web import facet
   329 
   333 
       
   334 
   330     class DisplayedOnFacet(facet.RelationFacet):
   335     class DisplayedOnFacet(facet.RelationFacet):
   331 	__regid__ = 'displayed_on-facet'
   336         __regid__ = 'displayed_on-facet'
   332 	# relation to be displayed
   337         # relation to be displayed
   333 	rtype = 'displayed_on'
   338         rtype = 'displayed_on'
   334 	role = 'object'
   339         role = 'object'
   335 	# view to use to display persons
   340         # view to use to display persons
   336 	label_vid = 'combobox'
   341         label_vid = 'combobox'
   337 
   342 
   338 Let's say we also want to filter according to the `visibility` attribute. This is
   343 Let's say we also want to filter according to the `visibility` attribute. This is
   339 even simpler as we just have to derive from the :class:`AttributeFacet` class:
   344 even simpler as we just have to derive from the :class:`AttributeFacet` class:
   340 
   345 
   341 .. sourcecode:: python
   346 .. sourcecode:: python
   342 
   347 
   343     class VisibilityFacet(facet.AttributeFacet):
   348     class VisibilityFacet(facet.AttributeFacet):
   344 	__regid__ = 'visibility-facet'
   349         __regid__ = 'visibility-facet'
   345 	rtype = 'visibility'
   350         rtype = 'visibility'
   346 
   351 
   347 Now if I search for some pictures on my site, I get the following facets available:
   352 Now if I search for some pictures on my site, I get the following facets available:
   348 
   353 
   349 .. image:: ../../images/tutos-photowebsite_facets.png
   354 .. image:: ../../images/tutos-photowebsite_facets.png
   350 
   355