web/views/timeline.py
changeset 0 b97547f5f1fa
child 431 18b4dd650ef8
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """basic support for SIMILE's timline widgets
       
     2 
       
     3 cf. http://code.google.com/p/simile-widgets/
       
     4 
       
     5 :organization: Logilab
       
     6 :copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     7 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     8 """
       
     9 __docformat__ = "restructuredtext en"
       
    10 
       
    11 import simplejson
       
    12 
       
    13 from logilab.mtconverter import html_escape
       
    14 
       
    15 from cubicweb.interfaces import ICalendarable
       
    16 from cubicweb.common.view import EntityView, StartupView
       
    17 from cubicweb.common.selectors import interface_selector
       
    18 
       
    19 
       
    20 # 
       
    21 class TimelineJsonView(EntityView):
       
    22     """generates a json file to feed Timeline.loadJSON()
       
    23     NOTE: work in progress (image_url, bubbleUrl and so on
       
    24     should be properties of entity classes or subviews)
       
    25     """
       
    26     id = 'timeline-json'
       
    27     binary = True
       
    28     templatable = False
       
    29     content_type = 'application/json'
       
    30 
       
    31     __selectors__ = (interface_selector,)
       
    32     accepts_interfaces = (ICalendarable,)
       
    33     date_fmt = '%Y/%m/%d'
       
    34     
       
    35     def call(self):
       
    36         events = []
       
    37         for entity in self.rset.entities():
       
    38             event = self.build_event(entity)
       
    39             if event is not None:
       
    40                 events.append(event)
       
    41         timeline_data = {'dateTimeFormat': self.date_fmt,
       
    42                          'events': events}
       
    43         self.w(simplejson.dumps(timeline_data))
       
    44 
       
    45     # FIXME: those properties should be defined by the entity class
       
    46     def onclick_url(self, entity):
       
    47         return entity.absolute_url()
       
    48     
       
    49     def onclick(self, entity):
       
    50         url = self.onclick_url(entity)
       
    51         if url:
       
    52             return u"javascript: document.location.href='%s'" % url
       
    53         return None
       
    54     
       
    55     def build_event(self, entity):
       
    56         """converts `entity` into a JSON object
       
    57         {'start': '1891',
       
    58         'end': '1915',
       
    59         'title': 'Portrait of Horace Brodsky',
       
    60         'description': 'by Henri Gaudier-Brzeska, French Sculptor, 1891-1915',
       
    61         'image': 'http://imagecache2.allposters.com/images/BRGPOD/102770_b.jpg',
       
    62         'link': 'http://www.allposters.com/-sp/Portrait-of-Horace-Brodsky-Posters_i1584413_.htm'
       
    63         }
       
    64         """
       
    65         start = entity.start
       
    66         stop = entity.stop
       
    67         start = start or stop
       
    68         if start is None and stop is None:
       
    69             return None
       
    70         event_data = {'start': start.strftime(self.date_fmt),
       
    71                       'title': html_escape(entity.dc_title()),
       
    72                       'description': entity.dc_description(),
       
    73                       'link': entity.absolute_url(),
       
    74                       }
       
    75         onclick = self.onclick(entity)
       
    76         if onclick:
       
    77             event_data['onclick'] = onclick
       
    78         if stop:
       
    79             event_data['end'] = stop.strftime(self.date_fmt)
       
    80         return event_data
       
    81 
       
    82     
       
    83 class TimelineViewMixIn(object):
       
    84     widget_class = 'TimelineWidget'
       
    85     jsfiles = ('cubicweb.timeline-bundle.js', 'cubicweb.widgets.js',
       
    86                'cubicweb.timeline-ext.js', 'cubicweb.ajax.js')
       
    87     
       
    88     def render(self, loadurl, tlunit=None):
       
    89         tlunit = tlunit or self.req.form.get('tlunit')
       
    90         self.req.add_js(self.jsfiles)
       
    91         self.req.add_css('timeline-bundle.css')
       
    92         if tlunit:
       
    93             additional = u' cubicweb:tlunit="%s"' % tlunit
       
    94         else:
       
    95             additional = u''
       
    96         self.w(u'<div class="widget" cubicweb:wdgtype="%s" '
       
    97                u'cubicweb:loadtype="auto" cubicweb:loadurl="%s" %s >' %
       
    98                (self.widget_class, html_escape(loadurl),
       
    99                 additional))
       
   100         self.w(u'</div>')
       
   101 
       
   102 
       
   103 class TimelineView(TimelineViewMixIn, EntityView):
       
   104     """builds a cubicweb timeline widget node"""
       
   105     id = 'timeline'
       
   106     __selectors__ = (interface_selector,)
       
   107     accepts_interfaces = (ICalendarable,)
       
   108     need_navigation = False
       
   109     def call(self, tlunit=None):
       
   110         self.req.html_headers.define_var('Timeline_urlPrefix', self.req.datadir_url)
       
   111         rql = self.rset.printable_rql()
       
   112         loadurl = self.build_url(rql=rql, vid='timeline-json')
       
   113         self.render(loadurl, tlunit)
       
   114         
       
   115     
       
   116 class StaticTimelineView(TimelineViewMixIn, StartupView):
       
   117     """similar to `TimelineView` but loads data from a static
       
   118     JSON file instead of one after a RQL query.
       
   119     """
       
   120     id = 'static-timeline'
       
   121     
       
   122     def call(self, loadurl, tlunit=None, wdgclass=None):
       
   123         self.widget_class = wdgclass or self.widget_clas
       
   124         self.render(loadurl, tlunit)