web/htmlwidgets.py
changeset 0 b97547f5f1fa
child 203 60cd67acf7fd
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """html widgets
       
     2 
       
     3 those are in cubicweb.common since we need to know available widgets at schema
       
     4 serialization time
       
     5 
       
     6 :organization: Logilab
       
     7 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     8 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     9 """
       
    10 
       
    11 from logilab.mtconverter import html_escape
       
    12 
       
    13 from cubicweb.common.utils import UStringIO
       
    14 from cubicweb.common.uilib import toggle_action
       
    15 
       
    16 class HTMLWidget(object):
       
    17 
       
    18     def _initialize_stream(self, w=None):
       
    19         if w:
       
    20             self.w = w
       
    21         else:
       
    22             self._stream = UStringIO()
       
    23             self.w = self._stream.write
       
    24 
       
    25     def _render(self):
       
    26         raise NotImplementedError
       
    27 
       
    28     def render(self, w=None):
       
    29         self._initialize_stream(w)
       
    30         self._render()
       
    31         if w is None:
       
    32             return self._stream.getvalue()
       
    33 
       
    34     def is_empty(self):
       
    35         return False
       
    36 
       
    37 
       
    38 class BoxWidget(HTMLWidget):
       
    39     def __init__(self, title, id, items=None, _class="boxFrame",
       
    40                  islist=True, shadow=True, escape=True):
       
    41         self.title = title
       
    42         self.id = id
       
    43         self.items = items or []
       
    44         self._class = _class
       
    45         self.islist = islist
       
    46         self.shadow = shadow
       
    47         self.escape = escape
       
    48 
       
    49     def __len__(self):
       
    50         return len(self.items)
       
    51 
       
    52     def is_empty(self):
       
    53         return len(self) == 0
       
    54 
       
    55     def append(self, item):
       
    56         self.items.append(item)
       
    57 
       
    58     main_div_class = 'boxContent'
       
    59     listing_class = 'boxListing'
       
    60     
       
    61     def box_begin_content(self):
       
    62         self.w(u'<div class="%s">\n' % self.main_div_class)
       
    63         if self.islist:
       
    64             self.w(u'<ul class="%s">' % self.listing_class)
       
    65 
       
    66     def box_end_content(self):
       
    67         if self.islist:
       
    68             self.w(u'</ul>\n')
       
    69         self.w(u'</div>\n')
       
    70         if self.shadow:
       
    71             self.w(u'<div class="shadow">&nbsp;</div>')
       
    72         
       
    73     def _render(self):
       
    74         if self.id:
       
    75             self.w(u'<div class="%s" id="%s">' % (self._class, self.id))
       
    76         else:
       
    77             self.w(u'<div class="%s">' % self._class)            
       
    78         if self.title:
       
    79             if self.escape:
       
    80                 title = '<span>%s</span>' % html_escape(self.title)
       
    81             else:
       
    82                 title = '<span>%s</span>' % self.title
       
    83             self.w(u'<div class="boxTitle">%s</div>' % title)
       
    84         if self.items:
       
    85             self.box_begin_content()
       
    86             for item in self.items:
       
    87                 item.render(self.w)
       
    88             self.box_end_content()
       
    89         self.w(u'</div>')
       
    90 
       
    91 
       
    92 class SideBoxWidget(BoxWidget):
       
    93     """default CubicWeb's sidebox widget"""
       
    94     main_div_class = u'sideBoxBody'
       
    95     listing_class = ''
       
    96 
       
    97     def __init__(self, title, id=None):
       
    98         super(SideBoxWidget, self).__init__(title, id=id, _class='sideBox',
       
    99                                             shadow=False)
       
   100 
       
   101                                             
       
   102 class MenuWidget(BoxWidget):
       
   103     main_div_class = 'menuContent'
       
   104     listing_class = 'menuListing'
       
   105 
       
   106     def box_end_content(self):
       
   107         if self.islist:
       
   108             self.w(u'</ul>\n')
       
   109         self.w(u'</div>\n')
       
   110     
       
   111 
       
   112 class RawBoxItem(HTMLWidget):
       
   113     """a simpe box item displaying raw data"""
       
   114     def __init__(self, label, liclass=None):
       
   115         self.label = label
       
   116         self.liclass = liclass
       
   117 
       
   118     def _start_li(self):
       
   119         if self.liclass is None:
       
   120             return u'<li>'
       
   121         else:
       
   122             return u'<li class="%s">' % self.liclass
       
   123         
       
   124         return self.label
       
   125     
       
   126     def _render(self):
       
   127         self.w(u'%s%s</li>' % (self._start_li(), self.label))
       
   128 
       
   129 
       
   130 class BoxMenu(RawBoxItem):
       
   131     """a menu in a box"""
       
   132     link_class = 'boxMenu'
       
   133     
       
   134     def __init__(self, label, items=None, isitem=True, liclass=None, ident=None,
       
   135                  link_class=None):
       
   136         super(BoxMenu, self).__init__(label, liclass)
       
   137         self.items = items or []
       
   138         self.isitem = isitem
       
   139         self.ident = ident or u'boxmenu_%s' % label.replace(' ', '_').replace("'", '')
       
   140         if link_class:
       
   141             self.link_class = link_class
       
   142             
       
   143     def append(self, item):
       
   144         self.items.append(item)
       
   145 
       
   146     def _begin_menu(self, ident):
       
   147         self.w(u'<ul id="%s" class="hidden">' % ident)
       
   148 
       
   149     def _end_menu(self):
       
   150         self.w(u'</ul>')
       
   151         
       
   152     def _render(self):
       
   153         if self.isitem:
       
   154             self.w(self._start_li())
       
   155         ident = self.ident
       
   156         self.w(u'<a href="%s" class="%s">%s</a>' % (
       
   157             toggle_action(ident), self.link_class, self.label))
       
   158         self._begin_menu(ident)
       
   159         for item in self.items:
       
   160             item.render(self.w)
       
   161         self._end_menu()
       
   162         if self.isitem:
       
   163             self.w(u'</li>')
       
   164 
       
   165 
       
   166 class PopupBoxMenu(BoxMenu):
       
   167     """like BoxMenu but uses div and specific css class
       
   168     in order to behave like a popup menu
       
   169     """
       
   170     link_class = 'popupMenu'
       
   171 
       
   172     def _begin_menu(self, ident):
       
   173         self.w(u'<div class="popupWrapper"><div id="%s" class="hidden popup"><ul>' % ident)
       
   174 
       
   175     def _end_menu(self):
       
   176         self.w(u'</ul></div></div>')
       
   177 
       
   178 
       
   179 class BoxField(HTMLWidget):
       
   180     """couples label / value meant to be displayed in a box"""
       
   181     def __init__(self, label, value):
       
   182         self.label = label
       
   183         self.value = value
       
   184     
       
   185     def _render(self):
       
   186         self.w(u'<li><div><span class="label">%s</span>&nbsp;'
       
   187                u'<span class="value">%s</span></div></li>' 
       
   188                % (self.label, self.value))
       
   189 
       
   190 class BoxSeparator(HTMLWidget):
       
   191     """a menu separator"""
       
   192     
       
   193     def _render(self):
       
   194         self.w(u'</ul><hr class="boxSeparator"/><ul>')
       
   195 
       
   196 
       
   197 class BoxLink(HTMLWidget):
       
   198     """a link in a box"""
       
   199     def __init__(self, href, label, _class='', title='', ident='', escape=False):
       
   200         self.href = href
       
   201         if escape:
       
   202             self.label = html_escape(label)
       
   203         else:
       
   204             self.label = label
       
   205         self._class = _class or ''
       
   206         self.title = title
       
   207         self.ident = ident
       
   208 
       
   209     def _render(self):
       
   210         link = u'<a href="%s" title="%s">%s</a>' % (
       
   211             html_escape(self.href), html_escape(self.title), self.label)
       
   212         if self.ident:
       
   213             self.w(u'<li id="%s" class="%s">%s</li>\n' % (self.ident, self._class, link))
       
   214         else:
       
   215             self.w(u'<li class="%s">%s</li>\n' % (self._class, link))
       
   216 
       
   217 
       
   218 class BoxHtml(HTMLWidget):
       
   219     """a form in a box"""
       
   220     def __init__(self, rawhtml):
       
   221         self.rawhtml = rawhtml
       
   222 
       
   223     def _render(self):
       
   224         self.w(self.rawhtml)
       
   225 
       
   226 
       
   227 class TableColumn(object):
       
   228     def __init__(self, name, rset_sortcol):
       
   229         """
       
   230         :param name: the column's name
       
   231         :param rset_sortcol: the model's column used to sort this column view
       
   232         """
       
   233         self.name = name
       
   234         self.cellrenderers = []
       
   235         self.rset_sortcol = rset_sortcol
       
   236         self.cell_attrs = {}
       
   237 
       
   238     def append_renderer(self, cellvid, colindex):
       
   239         # XXX (adim) : why do we need colindex here ?
       
   240         self.cellrenderers.append( (cellvid, colindex) )
       
   241 
       
   242     def add_attr(self, attr, value):
       
   243         self.cell_attrs[attr] = value
       
   244 
       
   245 
       
   246 class TableWidget(HTMLWidget):
       
   247 
       
   248     highlight = "onmouseover=\"addElementClass(this, 'highlighted');\" " \
       
   249                 "onmouseout=\"removeElementClass(this, 'highlighted');\""
       
   250     
       
   251     def __init__(self, model):
       
   252         self.model = model
       
   253         self.columns = []
       
   254 
       
   255     def append_column(self, column):
       
   256         """
       
   257         :type column: TableColumn
       
   258         """
       
   259         self.columns.append(column)
       
   260 
       
   261     def _render(self):
       
   262         self.w(u'<table class="listing">')
       
   263         self.w(u'<thead>')
       
   264         self.w(u'<tr class="header">')
       
   265         for column in self.columns:
       
   266             attrs = ('%s="%s"' % (name, value) for name, value in column.cell_attrs.iteritems())
       
   267             self.w(u'<th %s>%s</th>' % (' '.join(attrs), column.name))
       
   268         self.w(u'</tr>')
       
   269         self.w(u'</thead><tbody>')
       
   270         for rowindex, row in enumerate(self.model.get_rows()):
       
   271             klass = (rowindex%2==1) and 'odd' or 'even'
       
   272             self.w(u'<tr class="%s" %s>' % (klass, self.highlight))
       
   273             for column, sortvalue in self.itercols(rowindex):
       
   274                 attrs = dict(column.cell_attrs)
       
   275                 attrs["cubicweb:sortvalue"] = 'json:' + sortvalue
       
   276                 attrs = ('%s="%s"' % (name, value) for name, value in attrs.iteritems())
       
   277                 self.w(u'<td %s>' % (' '.join(attrs)))
       
   278                 for cellvid, colindex in column.cellrenderers:
       
   279                     self.model.render(cellvid, rowindex, colindex, w=self.w)
       
   280                 self.w(u'</td>')
       
   281             self.w(u'</tr>')
       
   282         self.w(u'</tbody>')
       
   283         self.w(u'</table>')
       
   284 
       
   285     def itercols(self, rowindex):
       
   286         for column in self.columns:
       
   287             yield column, self.model.sortvalue(rowindex, column.rset_sortcol)
       
   288 
       
   289 
       
   290 class ProgressBarWidget(HTMLWidget):
       
   291     """display a progress bar widget"""
       
   292     def __init__(self, done, todo, total):
       
   293         self.done = done
       
   294         self.todo = todo
       
   295         self.total = total
       
   296 
       
   297     def _render(self):
       
   298         try:
       
   299             pourcent = self.done*100./self.total
       
   300         except ZeroDivisionError:
       
   301             pourcent = 0
       
   302         real_pourcent = pourcent
       
   303         if pourcent > 100 :
       
   304             color = 'done'
       
   305             pourcent = 100
       
   306         elif self.todo + self.done > self.total :
       
   307             color = 'overpassed'
       
   308         else:
       
   309             color = 'inprogress'
       
   310         if pourcent < 0:
       
   311             pourcent = 0
       
   312         self.w(u'<div class="progressbarback" title="%i %%">' % real_pourcent)
       
   313         self.w(u'<div class="progressbar %s" style="width: %spx; align: left;" ></div>' % (color, pourcent))
       
   314         self.w(u'</div>')