class MyosotisTimeline(timeline.TimelineView): __regid__ = 'myosotis.timeline' __select__ = adaptable('ICalendarable') widget_class = 'MyosotisTimelineWidget' jsfiles = timeline.TimelineView.jsfiles + ('cubicweb.myosotis.js',) def render_url(self, loadurl, tlunit=None): # copied to avoid loadtype=auto tlunit = tlunit or self._cw.form.get('tlunit') self._cw.add_js(self.jsfiles) self._cw.add_css('timeline-bundle.css') if tlunit: additional = u' cubicweb:tlunit="%s"' % tlunit else: additional = u'' self.w(u'<div class="widget" cubicweb:wdgtype="%s" ' u'cubicweb:loadurl="%s" style="height:400px;" %s >' % (self.widget_class, xml_escape(loadurl), additional)) self.w(u'</div>') def call(self, tlunit=None): super(MyosotisTimeline, self).call(tlunit) min_start_date = min(entity.cw_adapt_to('ICalendarable').start for entity in self.cw_rset.entities()) year, month, day = min_start_date.year, min_start_date.month-1, min_start_date.day self.w(u'<script type="text/javascript">jQuery(document).ready(function(){setMinVisibleDate(new Date(%d, %d, %d));});</script>' % (year, month, day))
class RSSEntityFeedURL(Component): __regid__ = 'rss_feed_url' __select__ = one_line_rset() & adaptable('IFeed') def feed_url(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return entity.cw_adapt_to('IFeed').rss_feed_url()
class SetInitialStateHook(WorkflowHook): __regid__ = 'wfsetinitial' __select__ = WorkflowHook.__select__ & adaptable('IWorkflowable') events = ('after_add_entity', ) def __call__(self): _SetInitialStateOp(self._cw, eid=self.entity.eid)
class BaseTreeView(baseviews.ListView): """base tree view""" __regid__ = 'tree' __select__ = adaptable('ITree') item_vid = 'treeitem' def call(self, done=None, **kwargs): if done is None: done = set() super(BaseTreeView, self).call(done=done, **kwargs) def cell_call(self, row, col=0, vid=None, done=None, maxlevel=None, klass=None, **kwargs): assert maxlevel is None or maxlevel > 0 done, entity = _done_init(done, self, row, col) if done is None: # entity is actually an error message self.w(u'<li class="badcontent">%s</li>' % entity) return self.open_item(entity) entity.view(vid or self.item_vid, w=self.w, **kwargs) if maxlevel is not None: maxlevel -= 1 if maxlevel == 0: self.close_item(entity) return relatedrset = entity.cw_adapt_to('ITree').children(entities=False) self.wview(self.__regid__, relatedrset, 'null', done=done, maxlevel=maxlevel, klass=klass, **kwargs) self.close_item(entity) def open_item(self, entity): self.w(u'<li class="%s">\n' % entity.cw_etype.lower()) def close_item(self, entity): self.w(u'</li>\n')
class hCalView(EntityView): """A calendar view that generates a hCalendar file Does apply to ICalendarable compatible entities """ __regid__ = 'hcal' __select__ = adaptable('ICalendarable') paginable = False title = _('hCalendar') #templatable = False def call(self): self.w(u'<div class="hcalendar">') for i in range(len(self.cw_rset.rows)): task = self.cw_rset.complete_entity(i, 0) self.w(u'<div class="vevent">') self.w(u'<h3 class="summary">%s</h3>' % xml_escape(task.dc_title())) self.w(u'<div class="description">%s</div>' % task.dc_description(format='text/html')) icalendarable = task.cw_adapt_to('ICalendarable') if icalendarable.start: self.w(u'<abbr class="dtstart" title="%s">%s</abbr>' % (icalendarable.start.isoformat(), self._cw.format_date(icalendarable.start))) if icalendarable.stop: self.w(u'<abbr class="dtstop" title="%s">%s</abbr>' % (icalendarable.stop.isoformat(), self._cw.format_date(icalendarable.stop))) self.w(u'</div>') self.w(u'</div>')
class InContextWithStateView(EntityView): """display incontext view for an entity as well as its current state""" __regid__ = 'incontext-state' __select__ = adaptable('IWorkflowable') def entity_call(self, entity): iwf = entity.cw_adapt_to('IWorkflowable') self.w(u'%s [%s]' % (entity.view('incontext'), iwf.printable_state))
def test_etype_priority(self): with self.admin_access.web_request() as req: f = req.create_entity('FakeFile', data_name=u'hop.txt', data=Binary(b'hop'), data_format=u'text/plain') rset = f.as_rset() anyscore = is_instance('Any')(f.__class__, req, rset=rset) idownscore = adaptable('IDownloadable')(f.__class__, req, rset=rset) self.assertTrue(idownscore > anyscore, (idownscore, anyscore)) filescore = is_instance('FakeFile')(f.__class__, req, rset=rset) self.assertTrue(filescore > idownscore, (filescore, idownscore))
class DownloadLinkView(EntityView): """view displaying a link to download the file""" __regid__ = 'downloadlink' __select__ = adaptable('IDownloadable') title = None # should not be listed in possible views def cell_call(self, row, col, title=None, **kwargs): entity = self.cw_rset.get_entity(row, col) url = xml_escape(entity.cw_adapt_to('IDownloadable').download_url()) self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
def test_multiple_entity_types_rset(self): class CWUserIWhatever(EntityAdapter): __regid__ = 'IWhatever' __select__ = is_instance('CWUser') class CWGroupIWhatever(EntityAdapter): __regid__ = 'IWhatever' __select__ = is_instance('CWGroup') with self.temporary_appobjects(CWUserIWhatever, CWGroupIWhatever): with self.admin_access.web_request() as req: selector = adaptable('IWhatever') rset = req.execute('Any X WHERE X is IN(CWGroup, CWUser)') self.assertTrue(selector(None, req, rset=rset))
class MyosotisTimelineJson(timeline.TimelineJsonView): __select__ = adaptable('ICalendarable') & is_instance('Compte') colors = {u'trésorerie': 'gold', u'hôtel du comte': 'skyblue', u'hôtel de la comtesse': 'deeppink', u'compte de voyage': 'green', u'nul': 'grey', } def build_event(self, entity): event = super(MyosotisTimelineJson, self).build_event(entity) event['color'] = self.colors.get(entity.type_compte.lower(), 'red') return event
class IDownloadableOneLineView(baseviews.OneLineView): __select__ = adaptable('IDownloadable') def cell_call(self, row, col, title=None, **kwargs): """the oneline view is a link to download the file""" entity = self.cw_rset.get_entity(row, col) url = xml_escape(entity.absolute_url()) adapter = entity.cw_adapt_to('IDownloadable') name = xml_escape(title or entity.dc_title()) durl = xml_escape(adapter.download_url()) self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' % (url, name, durl, self._cw._('download')))
class IDownloadablePrimaryView(primary.PrimaryView): __select__ = adaptable('IDownloadable') def render_entity_attributes(self, entity): self.w(u'<div class="content">') adapter = entity.cw_adapt_to('IDownloadable') contenttype = adapter.download_content_type() if contenttype.startswith('image/'): self._cw.add_js('cubicweb.image.js') self.wview('image', entity.cw_rset, row=entity.cw_row, col=entity.cw_col, link=True, klass='contentimage') super(IDownloadablePrimaryView, self).render_entity_attributes(entity) elif contenttype.endswith('html'): self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row) self.wview('ehtml', entity.cw_rset, row=entity.cw_row, col=entity.cw_col, height='600px', width='100%') else: super(IDownloadablePrimaryView, self).render_entity_attributes(entity) self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row) self.render_data(entity, contenttype, 'text/html') self.w(u'</div>') def render_data(self, entity, sourcemt, targetmt): adapter = entity.cw_adapt_to('IDownloadable') if ENGINE.find_path(sourcemt, targetmt): try: self.w( entity._cw_mtc_transform(adapter.download_data(), sourcemt, targetmt, adapter.download_encoding())) except Exception as ex: self.exception('while rendering data for %s', entity) msg = self._cw._("can't display data, unexpected error: %s") \ % xml_escape(unicode(ex)) self.w('<div class="error">%s</div>' % msg) return True return False
class BreadCrumbETypeVComponent(BreadCrumbEntityVComponent): __select__ = (basecomponents.HeaderComponent.__select__ & multi_lines_rset() & one_etype_rset() & adaptable('IBreadCrumbs')) def render_breadcrumbs(self, w, contextentity, path): # XXX hack: only display etype name or first non entity path part root = path.pop(0) if isinstance(root, Entity): w(u'<a href="%s">%s</a>' % (self._cw.build_url(root.__regid__), root.dc_type('plural'))) else: self.wpath_part(w, root, contextentity, not path)
class ChangeStateFormView(form.FormViewMixIn, EntityView): __regid__ = 'statuschange' title = _('status change') __select__ = (one_line_rset() & match_form_params('treid') & adaptable('IWorkflowable')) def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) transition = self._cw.entity_from_eid(self._cw.form['treid']) form = self.get_form(entity, transition) self.w(u'<h4>%s %s</h4>\n' % (self._cw._(transition.name), entity.view('oneline'))) msg = self._cw._('status will change from %(st1)s to %(st2)s') % { 'st1': entity.cw_adapt_to('IWorkflowable').printable_state, 'st2': self._cw._(transition.destination(entity).name) } self.w(u'<p>%s</p>\n' % msg) form.render(w=self.w) def redirectpath(self, entity): return entity.rest_path() def get_form(self, entity, transition, **kwargs): # XXX used to specify both rset/row/col and entity in case implements # selector (and not is_instance) is used on custom form form = self._cw.vreg['forms'].select( 'changestate', self._cw, entity=entity, transition=transition, redirect_path=self.redirectpath(entity), **kwargs) trinfo = self._cw.vreg['etypes'].etype_class('TrInfo')(self._cw) trinfo.eid = next(self._cw.varmaker) subform = self._cw.vreg['forms'].select('edition', self._cw, entity=trinfo, mainform=False) subform.field_by_name('wf_info_for', 'subject').value = entity.eid trfield = subform.field_by_name('by_transition', 'subject') trfield.widget = fwdgs.HiddenInput() trfield.value = transition.eid form.add_subform(subform) return form
class DownloadBox(component.EntityCtxComponent): """add download box""" __regid__ = 'download_box' # no download box for images __select__ = (component.EntityCtxComponent.__select__ & adaptable('IDownloadable') & ~has_mimetype('image/')) order = 10 title = _('download') def init_rendering(self): self.items = [self.entity] def render_body(self, w): for item in self.items: idownloadable = item.cw_adapt_to('IDownloadable') w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>' % (xml_escape(idownloadable.download_url()), self._cw.uiprops['DOWNLOAD_ICON'], self._cw._('download icon'), xml_escape(idownloadable.download_file_name())))
class DownloadView(EntityView): """download view this view is replacing the deprecated 'download' controller and allow downloading of entities providing the necessary interface """ __regid__ = 'download' __select__ = one_line_rset() & adaptable('IDownloadable') templatable = False content_type = 'application/octet-stream' binary = True http_cache_manager = httpcache.EntityHTTPCacheManager add_to_breadcrumbs = False def set_request_content_type(self): """overriden to set the correct filetype and filename""" entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) adapter = entity.cw_adapt_to('IDownloadable') encoding = adapter.download_encoding() if encoding in BINARY_ENCODINGS: contenttype = 'application/%s' % encoding encoding = None else: contenttype = adapter.download_content_type() self._cw.set_content_type(contenttype or self.content_type, filename=adapter.download_file_name(), encoding=encoding, disposition='attachment') def call(self): entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) adapter = entity.cw_adapt_to('IDownloadable') self.w(adapter.download_data()) def last_modified(self): return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).modification_date
class TreePathView(EntityView): """a recursive path view""" __regid__ = 'path' __select__ = adaptable('ITree') item_vid = 'oneline' separator = u' > ' def call(self, **kwargs): self.w(u'<div class="pathbar">') super(TreePathView, self).call(**kwargs) self.w(u'</div>') def cell_call(self, row, col=0, vid=None, done=None, **kwargs): done, entity = _done_init(done, self, row, col) if done is None: # entity is actually an error message self.w(u'<span class="badcontent">%s</span>' % entity) return parent = entity.cw_adapt_to('ITree').parent() if parent: parent.view(self.__regid__, w=self.w, done=done) self.w(self.separator) entity.view(vid or self.item_vid, w=self.w)
class iCalView(EntityView): """A calendar view that generates a iCalendar file (RFC 5545) Does apply to ICalendarable compatible entities """ __select__ = adaptable('ICalendarable') paginable = False content_type = 'text/calendar' title = _('iCalendar') templatable = False __regid__ = 'ical' def call(self): ical = iCalendar() for i in range(len(self.cw_rset.rows)): task = self.cw_rset.complete_entity(i, 0) ical_task = task.cw_adapt_to('ICalendarable') if ical_task.component == ICAL_TODO: elt = ical.add('vtodo') stop_kw = "due" else: elt = ical.add('vevent') stop_kw = "dtend" elt.add('uid').value = task.absolute_url() # unique stable id elt.add('url').value = task.absolute_url() elt.add('summary').value = task.dc_title() elt.add('description').value = task.dc_description() if ical_task.start: elt.add('dtstart').value = ical_task.start if ical_task.stop: elt.add(stop_kw).value = ical_task.stop buff = ical.serialize() if not isinstance(buff, str): buff = str(buff, self._cw.encoding) self.w(buff)
class NextPrevNavigationComponent(EntityCtxComponent): """Entities adaptable to the 'IPrevNext' should have this component automatically displayed. You may want to override this component to have a different look and feel. """ __regid__ = 'prevnext' # register msg not generated since no entity implements IPrevNext in cubicweb # itself help = _('ctxcomponents_prevnext_description') __select__ = EntityCtxComponent.__select__ & adaptable('IPrevNext') context = 'navbottom' order = 10 @property def prev_icon(self): return '<img src="%s" alt="%s" />' % (xml_escape( self._cw.data_url('go_prev.png')), self._cw._('previous page')) @property def next_icon(self): return '<img src="%s" alt="%s" />' % (xml_escape( self._cw.data_url('go_next.png')), self._cw._('next page')) def init_rendering(self): adapter = self.entity.cw_adapt_to('IPrevNext') self.previous = adapter.previous_entity() self.next = adapter.next_entity() if not (self.previous or self.next): raise EmptyComponent() def render_body(self, w): w(u'<div class="prevnext">') self.prevnext(w) w(u'</div>') w(u'<div class="clear"></div>') def prevnext(self, w): if self.previous: self.prevnext_entity(w, self.previous, 'prev') if self.next: self.prevnext_entity(w, self.next, 'next') def prevnext_entity(self, w, entity, type): textsize = self._cw.property_value('navigation.short-line-size') content = xml_escape(cut(entity.dc_title(), textsize)) if type == 'prev': title = self._cw._('i18nprevnext_previous') icon = self.prev_icon cssclass = u'previousEntity left' content = icon + '  ' + content else: title = self._cw._('i18nprevnext_next') icon = self.next_icon cssclass = u'nextEntity right' content = content + '  ' + icon self.prevnext_div(w, type, cssclass, entity.absolute_url(), title, content) def prevnext_div(self, w, type, cssclass, url, title, content): w(u'<div class="%s">' % cssclass) w(u'<a href="%s" title="%s">%s</a>' % (xml_escape(url), xml_escape(title), content)) w(u'</div>') self._cw.html_headers.add_raw('<link rel="%s" href="%s" />' % (type, xml_escape(url)))
class BreadCrumbEntityVComponent(basecomponents.HeaderComponent): __regid__ = 'breadcrumbs' __select__ = (basecomponents.HeaderComponent.__select__ & one_line_rset() & adaptable('IBreadCrumbs')) order = basecomponents.ApplicationName.order + 1 context = basecomponents.ApplicationName.context separator = u' > ' link_template = u'<a href="%s">%s</a>' first_separator = True # XXX support kwargs for compat with other components which gets the view as # argument def render(self, w, **kwargs): try: entity = self.cw_extra_kwargs['entity'] except KeyError: entity = self.cw_rset.get_entity(0, 0) adapter = entity.cw_adapt_to('IBreadCrumbs') view = self.cw_extra_kwargs.get('view') path = adapter.breadcrumbs(view) if path: self.open_breadcrumbs(w) self.render_breadcrumbs(w, entity, path) self.close_breadcrumbs(w) def open_breadcrumbs(self, w): w(u'<span id="breadcrumbs" class="pathbar">') if self.first_separator: w(self.separator) def close_breadcrumbs(self, w): w(u'</span>') def render_root(self, w, contextentity, path): root = path.pop(0) if isinstance(root, Entity): w(self.link_template % (self._cw.build_url(root.__regid__), root.dc_type('plural'))) w(self.separator) self.wpath_part(w, root, contextentity, not path) def render_breadcrumbs(self, w, contextentity, path): self.render_root(w, contextentity, path) for i, parent in enumerate(path): w(self.separator) w(u"\n") self.wpath_part(w, parent, contextentity, i == len(path) - 1) def wpath_part(self, w, part, contextentity, last=False): # XXX deprecates last argument? if isinstance(part, Entity): w(part.view('breadcrumbs')) elif isinstance(part, tuple): url, title = part textsize = self._cw.property_value('navigation.short-line-size') w(self.link_template % (xml_escape(url), xml_escape(uilib.cut(title, textsize)))) else: textsize = self._cw.property_value('navigation.short-line-size') w(xml_escape(uilib.cut(str(part), textsize)))
class TimeTableView(EntityView): __regid__ = 'timetable' title = _('timetable') __select__ = adaptable('ICalendarable') paginable = False def call(self, title=None): """Dumps a timetable from a resultset composed of a note (anything with start/stop) and a user (anything)""" self._cw.add_css('cubicweb.timetable.css') dates = {} users = [] users_max = {} # XXX: try refactoring with calendar.py:OneMonthCal for row in range(self.cw_rset.rowcount): task = self.cw_rset.get_entity(row, 0) icalendarable = task.cw_adapt_to('ICalendarable') if len(self.cw_rset[row] ) > 1 and self.cw_rset.description[row][1] == 'CWUser': user = self.cw_rset.get_entity(row, 1) else: user = ALL_USERS the_dates = [] if icalendarable.start and icalendarable.stop: if icalendarable.start.toordinal( ) == icalendarable.stop.toordinal(): the_dates.append(icalendarable.start) else: the_dates += date_range(icalendarable.start, icalendarable.stop + ONEDAY) elif icalendarable.start: the_dates.append(icalendarable.start) elif icalendarable.stop: the_dates.append(icalendarable.stop) for d in the_dates: d = todatetime(d) d_users = dates.setdefault(d, {}) u_tasks = d_users.setdefault(user, set()) u_tasks.add(task) task_max = users_max.setdefault(user, 0) if len(u_tasks) > task_max: users_max[user] = len(u_tasks) if user not in users: # keep original ordering users.append(user) if not dates: return date_min = min(dates) date_max = max(dates) #users = list(sorted(users, key=lambda u:u.login)) rows = [] # colors here are class names defined in cubicweb.css colors = ["col%x" % i for i in range(12)] next_color_index = 0 visited_tasks = {} # holds a description of a task for a user task_colors = {} # remember a color assigned to a task for date in date_range(date_min, date_max + ONEDAY): columns = [date] d_users = dates.get(date, {}) for user in users: # every user has its column "splitted" in at least MIN_COLS # sub-columns (for overlapping tasks) user_columns = [None] * max(MIN_COLS, users_max[user]) # every task that is "visited" for the first time # require a special treatment, so we put them in # 'postpone' postpone = [] for task in d_users.get(user, []): key = (task, user) if key in visited_tasks: task_descr = visited_tasks[key] user_columns[task_descr.column] = task_descr, False task_descr.lines += 1 else: postpone.append(key) for key in postpone: # to every 'new' task we must affect a color # (which must be the same for every user concerned # by the task) task, user = key for i, t in enumerate(user_columns): if t is None: if task in task_colors: color = task_colors[task] else: color = colors[next_color_index] next_color_index = (next_color_index + 1) % len(colors) task_colors[task] = color task_descr = _TaskEntry(task, color, i) user_columns[i] = task_descr, True visited_tasks[key] = task_descr break else: raise RuntimeError("is it possible we got it wrong?") columns.append(user_columns) rows.append(columns) widths = [len(col) for col in rows[0][1:]] self.w(u'<div class="section">') if title: self.w(u'<h4>%s</h4>\n' % title) self.w(u'<table class="listing timetable">') self.render_col_headers(users, widths) self.render_rows(rows) self.w(u'</table>') self.w(u'</div>\n') def render_col_headers(self, users, widths): """ render column headers """ self.w(u'<tr class="header">\n') self.w(u'<th class="ttdate"> </th>\n') columns = [] for user, width in zip(users, widths): self.w(u'<th colspan="%s">' % max(MIN_COLS, width)) if user is ALL_USERS: self.w(u'*') else: user.view('oneline', w=self.w) self.w(u'</th>') self.w(u'</tr>\n') return columns def render_rows(self, rows): """ render table content (row headers and central content) """ odd = False previous_is_empty = False for row in rows: date = row[0] empty_line = True for group in row[1:]: for value in group: if value: empty_line = False break else: continue break if empty_line and previous_is_empty: continue previous_is_empty = False klass = "even" if date.weekday() in (5, 6) and not empty_line: klass = "odd" self.w(u'<tr class="%s">' % klass) odd = not odd if not empty_line: self.w(u'<th class="ttdate">%s</th>' % self._cw.format_date(date)) else: self.w(u'<th>...</th>') previous_is_empty = True empty_klasses = ["ttle", "ttme", "ttre"] filled_klasses = ["ttlf", "ttmf", "ttrf"] kj = 0 # 0: left, 1: mid, 2: right for uid, group in enumerate(row[1:]): for i, value in enumerate(group): if i == 0: kj = 0 elif i == len(group): kj = 2 else: kj = 1 if value: task_descr, first_row = value if first_row: url = xml_escape( task_descr.task.absolute_url(vid="edition")) self.w( u'<td rowspan="%d" class="%s %s" onclick="document.location=\'%s\'"> <div>' % (task_descr.lines, task_descr.color, filled_klasses[kj], url)) task_descr.task.view('tooltip', w=self.w) self.w(u'</div></td>') else: if empty_line: self.w(u'<td class="ttempty"> </td>') else: self.w(u'<td class="%s"> </td>' % empty_klasses[kj]) self.w(u'</tr>\n')
class CalendarView(EntityView): __regid__ = 'calendar' __select__ = adaptable('ICalendarable') paginable = False title = _('calendar') fullcalendar_options = { 'firstDay': 1, 'firstHour': 8, 'defaultView': 'month', 'editable': True, 'header': {'left': 'prev,next today', 'center': 'title', 'right': 'month,agendaWeek,agendaDay', }, } def call(self, cssclass=""): self._cw.add_css(('fullcalendar.css', 'cubicweb.calendar.css')) self._cw.add_js(('jquery.ui.js', 'fullcalendar.min.js', 'jquery.qtip.min.js', 'fullcalendar.locale.js')) self.calendar_id = 'cal' + make_uid('uid') self.add_onload() # write calendar div to load jquery fullcalendar object if cssclass: self.w(u'<div class="%s" id="%s"></div>' % (cssclass, self.calendar_id)) else: self.w(u'<div id="%s"></div>' % self.calendar_id) def add_onload(self): fullcalendar_options = self.fullcalendar_options.copy() fullcalendar_options['events'] = self.get_events() # i18n # js callback to add a tooltip and to put html in event's title js = """ var options = $.fullCalendar.regional('%s', %s); options.eventRender = function(event, $element) { // add a tooltip for each event var div = '<div class="tooltip">'+ event.description+ '</div>'; $element.append(div); // allow to have html tags in event's title $element.find('span.fc-event-title').html($element.find('span.fc-event-title').text()); }; $("#%s").fullCalendar(options); """ #" self._cw.add_onload(js % (self._cw.lang, json_dumps(fullcalendar_options), self.calendar_id)) def get_events(self): events = [] for entity in self.cw_rset.entities(): icalendarable = entity.cw_adapt_to('ICalendarable') if not (icalendarable.start and icalendarable.stop): continue start_date = icalendarable.start or icalendarable.stop event = {'eid': entity.eid, 'title': entity.view('calendaritem'), 'url': xml_escape(entity.absolute_url()), 'className': 'calevent', 'description': entity.view('tooltip'), } event['start'] = start_date.strftime('%Y-%m-%dT%H:%M') event['allDay'] = True if icalendarable.stop: event['end'] = icalendarable.stop.strftime('%Y-%m-%dT%H:%M') event['allDay'] = False events.append(event) return events
class TreeViewItemView(EntityView): """specific treeitem view for entities which adapt to ITree (each item should be expandable if it's not a tree leaf) """ __regid__ = 'treeitemview' __select__ = adaptable('ITree') default_branch_state_is_open = False def open_state(self, eeid, treeid): cookies = self._cw.get_cookie() treestate = cookies.get(treecookiename(treeid)) if treestate: return str(eeid) in treestate.value.split(':') return self.default_branch_state_is_open def cell_call(self, row, col, treeid, vid='oneline', parentvid='treeview', is_last=False, **morekwargs): w = self.w entity = self.cw_rset.get_entity(row, col) itree = entity.cw_adapt_to('ITree') liclasses = [] if self._cw.url(includeparams=False) == entity.absolute_url(): liclasses.append(u'selected') is_open = self.open_state(entity.eid, treeid) is_leaf = itree is None or itree.is_leaf() if is_leaf: if is_last: liclasses.append('last') w(u'<li class="%s">' % u' '.join(liclasses)) else: rql = itree.children_rql() % {'x': entity.eid} url = xml_escape(self._cw.build_url('ajax', rql=rql, vid=parentvid, pageid=self._cw.pageid, treeid=treeid, fname='view', treesubvid=vid, morekwargs=json.dumps(morekwargs))) divclasses = ['hitarea'] if is_open: liclasses.append('collapsable') divclasses.append('collapsable-hitarea') else: liclasses.append('expandable') divclasses.append('expandable-hitarea') if is_last: if is_open: liclasses.append('lastCollapsable') divclasses.append('lastCollapsable-hitarea') else: liclasses.append('lastExpandable') divclasses.append('lastExpandable-hitarea') if is_open: w(u'<li class="%s">' % u' '.join(liclasses)) else: w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(liclasses))) if treeid.startswith('throw_away'): divtail = '' else: divtail = """ onclick="asyncRemoteExec('node_clicked', '%s', '%s')" """ % ( treeid, entity.eid) w(u'<div class="%s"%s></div>' % (u' '.join(divclasses), divtail)) # add empty <ul> because jquery's treeview plugin checks for # sublists presence if not is_open: w(u'<ul class="placeholder"><li>place holder</li></ul>') # the local node info self.wview(vid, self.cw_rset, row=row, col=col, **morekwargs) if is_open and not is_leaf: # => rql is defined self.wview(parentvid, itree.children(entities=False), subvid=vid, treeid=treeid, initial_load=False, **morekwargs) w(u'</li>')