nulib: génération d'une table
This commit is contained in:
parent
51f4e92c3d
commit
0bbcef690b
|
@ -36,7 +36,36 @@ mydir, myname = path.split(myself)
|
|||
|
||||
# Fonctions diverses
|
||||
|
||||
_undef = object()
|
||||
class Undef(object):
|
||||
def sa(self, value, kw, name, default=_undef):
|
||||
"""si value est Undef, récupérer la valeur avec le nom court name dans kw
|
||||
"""
|
||||
if default is _undef: default = self
|
||||
if value is self and name is not None: value = kw.pop(name, self)
|
||||
if value is self: value = default
|
||||
return value
|
||||
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
def __len__(self):
|
||||
return 0
|
||||
def __lt__(self, other):
|
||||
if other: return True
|
||||
else: return False
|
||||
def __le__(self, other):
|
||||
return True
|
||||
def __eq__(self, other):
|
||||
if other: return False
|
||||
else: return True
|
||||
def __ne__(self, other):
|
||||
if other: return True
|
||||
else: return False
|
||||
def __gt__(self, other):
|
||||
if other: return False
|
||||
else: return True
|
||||
def __ge__(self, other):
|
||||
return True
|
||||
def __repr__(self):
|
||||
return 'Undef'
|
||||
def __call__(self):
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
|
||||
__all__ = ('_weburl', '_ensure_session')
|
||||
__all__ = (
|
||||
'_weburl', '_ensure_session',
|
||||
'u', 'uval',
|
||||
)
|
||||
|
||||
from types import UnicodeType, StringType
|
||||
from ..ext import web
|
||||
|
||||
def _weburl(path, __BASEURL, **kw):
|
||||
|
@ -14,3 +18,21 @@ def _ensure_session(page):
|
|||
if session is None: raise ValueError("no session configured")
|
||||
page.session = session
|
||||
return session
|
||||
|
||||
def u(text):
|
||||
"""Si text n'est pas de l'unicode, le convertir en unicode avec l'encoding utf-8
|
||||
"""
|
||||
t = type(text)
|
||||
if t is not UnicodeType:
|
||||
if t is not StringType: text = str(text)
|
||||
text = unicode(text, "utf-8")
|
||||
return text
|
||||
|
||||
def uval(value):
|
||||
"""Transformer value en unicode, en particulier s'il est callable ou s'il
|
||||
a une méthode render()
|
||||
"""
|
||||
if value is None: return None
|
||||
if hasattr(value, 'render'): value = value.render()
|
||||
if callable(value): value = value()
|
||||
return u(value)
|
||||
|
|
|
@ -2,19 +2,22 @@
|
|||
|
||||
__all__ = (
|
||||
'load',
|
||||
'table', 'tr', 'td',
|
||||
'Menu', 'Action',
|
||||
'About',
|
||||
'Alert', 'set_alert',
|
||||
'Menu', 'Action',
|
||||
)
|
||||
|
||||
import sys, traceback
|
||||
from types import StringType
|
||||
|
||||
from ..base import seqof, Undef
|
||||
from ..base import isseq, seqof, Undef
|
||||
from ..ext import web
|
||||
|
||||
from . import ui
|
||||
from .ui import Action, u, p
|
||||
from .api import _ensure_session
|
||||
from .api import _ensure_session, u, uval
|
||||
from .model import Row, TableSchema
|
||||
from .ui import Action, p
|
||||
|
||||
Undef = Undef() # spécifique à ce module
|
||||
|
||||
|
@ -43,12 +46,98 @@ def load(prefix=None, icons=True, charset="utf-8"):
|
|||
])
|
||||
return u"\n".join(lines)
|
||||
|
||||
def sa(value, kw, name, default=Undef):
|
||||
"""si value est indéfini, récupérer la valeur avec le nom court dans kw
|
||||
"""
|
||||
if value is Undef and name is not None: value = kw.pop(name, Undef)
|
||||
if value is Undef: value = default
|
||||
return value
|
||||
################################################################################
|
||||
# Table
|
||||
|
||||
TRD_CLASS_MAP = dict(
|
||||
active="active",
|
||||
success="success", done="success",
|
||||
info="info",
|
||||
warning="warning", warn="warning", notice="warning",
|
||||
danger="danger", error="danger",
|
||||
)
|
||||
def trd_joinc(css):
|
||||
if css is Undef: css = None
|
||||
if type(css) is StringType:
|
||||
css = css.split(",")
|
||||
classes = []
|
||||
for css in seqof(css):
|
||||
classes.append(TRD_CLASS_MAP.get(css, css))
|
||||
css = ' '.join(classes)
|
||||
return css
|
||||
|
||||
def td(value, schema=None, css=Undef, tag=Undef, **kw):
|
||||
css = Undef.sa(css, kw, 'c')
|
||||
value = uval(value)
|
||||
if schema:
|
||||
value = schema.html(value)
|
||||
if css is Undef: css = schema.css(value)
|
||||
if tag is Undef: tag = 'td'
|
||||
css = trd_joinc(css)
|
||||
return u'<%s%s>%s</%s>' % (tag, ui.classif(css), value, tag)
|
||||
|
||||
def tr(values, schema=None, css=Undef, celltag=Undef, **kw):
|
||||
css = Undef.sa(css, kw, 'c')
|
||||
tdschema = lambda value, index: None
|
||||
if schema is not None:
|
||||
if css is Undef: css = schema.css(values)
|
||||
tdschema = lambda value, index: schema.cell_schema(value, index)
|
||||
css = trd_joinc(css)
|
||||
lines = []
|
||||
lines.append(u'<tr%s>' % ui.classif(css))
|
||||
index = 0
|
||||
if isinstance(values, dict) or isinstance(values, Row):
|
||||
if schema is not None:
|
||||
for col in schema.cols:
|
||||
value = values[col.key]
|
||||
lines.append(td(value, tdschema(value, index), tag=celltag))
|
||||
index += 1
|
||||
else:
|
||||
for value in values.values():
|
||||
lines.append(td(value, tdschema(value, index), tag=celltag))
|
||||
index += 1
|
||||
else:
|
||||
for value in values:
|
||||
lines.append(td(value, tdschema(value, index), tag=celltag))
|
||||
index += 1
|
||||
lines.append(u'</tr>')
|
||||
return u'\n'.join(lines)
|
||||
|
||||
TABLE_CLASS_MAP = dict(
|
||||
auto="table-auto", a="table-auto",
|
||||
striped="table-striped", strip="table-striped", s="table-striped",
|
||||
bordered="table-bordered", border="table-bordered", b="table-bordered",
|
||||
hover="table-hover", h="table-hover",
|
||||
condensed="table-condensed", c="table-condensed",
|
||||
)
|
||||
def table_joinc(css):
|
||||
if css is Undef: css = None
|
||||
if type(css) is StringType:
|
||||
css = css.split(",")
|
||||
classes = ['table']
|
||||
for css in seqof(css):
|
||||
classes.append(TABLE_CLASS_MAP.get(css, css))
|
||||
css = ' '.join(classes)
|
||||
return css
|
||||
|
||||
def table(rows, schema=None, css=Undef, **kw):
|
||||
css = Undef.sa(css, kw, 'c')
|
||||
if schema is None: schema = TableSchema.parse(rows)
|
||||
elif isseq(schema): schema = TableSchema(schema)
|
||||
if css is Undef: css = schema.css(rows)
|
||||
css = table_joinc(css)
|
||||
lines = []
|
||||
lines.append(u'<table%s>' % ui.classif(css))
|
||||
lines.append(u'<thead>')
|
||||
lines.append(tr(schema.headers(), schema.header_row_schema(), celltag='th'))
|
||||
lines.append(u'</thead><tbody>')
|
||||
index = 0
|
||||
for row in rows:
|
||||
lines.append(tr(row, schema.body_row_schema(index)))
|
||||
index += 1
|
||||
lines.append(u'</tbody>')
|
||||
lines.append(u'</table>')
|
||||
return u'\n'.join(lines)
|
||||
|
||||
################################################################################
|
||||
# Menu
|
||||
|
@ -265,12 +354,12 @@ class Alert(object):
|
|||
showtb = None
|
||||
|
||||
def __init__(self, msg=None, exc_info=Undef, type=Undef, closeable=Undef, escape=Undef, action=None, showtb=True, **kw):
|
||||
exc_info = sa(exc_info, kw, 'e')
|
||||
exc_info = Undef.sa(exc_info, kw, 'e')
|
||||
if exc_info is Undef: exc_info = sys.exc_info()
|
||||
if exc_info == (None, None, None): exc_info = None
|
||||
type = sa(type, kw, 't', "error")
|
||||
closeable = sa(closeable, kw, 'c', False)
|
||||
escape = sa(escape, kw, 'x', None)
|
||||
type = Undef.sa(type, kw, 't', "error")
|
||||
closeable = Undef.sa(closeable, kw, 'c', False)
|
||||
escape = Undef.sa(escape, kw, 'x', None)
|
||||
|
||||
self.msg = msg
|
||||
self.exc_info = exc_info
|
||||
|
@ -281,7 +370,7 @@ class Alert(object):
|
|||
self.showtb = showtb
|
||||
|
||||
def __call__(self, msg=Undef, exc_info=Undef, type=Undef, closeable=Undef, escape=Undef, action=Undef, showtb=Undef, **kw):
|
||||
exc_info = sa(exc_info, kw, 'e')
|
||||
exc_info = Undef.sa(exc_info, kw, 'e')
|
||||
if msg is Undef:
|
||||
# si on ne spécifie pas de message, alors prendre la valeur actuelle
|
||||
msg = self.msg
|
||||
|
@ -290,11 +379,11 @@ class Alert(object):
|
|||
# si on spécifie un message, alors prendre aussi l'exception courante
|
||||
if exc_info is Undef: exc_info = sys.exc_info()
|
||||
if exc_info == (None, None, None): exc_info = None
|
||||
type = sa(type, kw, 't', self.type)
|
||||
closeable = sa(closeable, kw, 'c', self.closeable)
|
||||
escape = sa(escape, kw, 'x', self.escape)
|
||||
action = sa(action, kw, None, self.action)
|
||||
showtb = sa(showtb, kw, None, self.showtb)
|
||||
type = Undef.sa(type, kw, 't', self.type)
|
||||
closeable = Undef.sa(closeable, kw, 'c', self.closeable)
|
||||
escape = Undef.sa(escape, kw, 'x', self.escape)
|
||||
action = Undef.sa(action, kw, None, self.action)
|
||||
showtb = Undef.sa(showtb, kw, None, self.showtb)
|
||||
|
||||
self.msg = msg
|
||||
self.exc_info = exc_info
|
||||
|
@ -306,7 +395,7 @@ class Alert(object):
|
|||
return self
|
||||
|
||||
def render(self, msg=Undef, exc_info=Undef, type=Undef, closeable=Undef, escape=Undef, action=Undef, showtb=Undef, **kw):
|
||||
exc_info = sa(exc_info, kw, 'e')
|
||||
exc_info = Undef.sa(exc_info, kw, 'e')
|
||||
if msg is Undef:
|
||||
# si on ne spécifie pas de message, alors prendre la valeur initiale
|
||||
msg = self.msg
|
||||
|
@ -314,11 +403,11 @@ class Alert(object):
|
|||
else:
|
||||
# si on spécifie un message, alors prendre aussi l'exception courante
|
||||
if exc_info is Undef: exc_info = sys.exc_info()
|
||||
type = sa(type, kw, 't', self.type)
|
||||
closeable = sa(closeable, kw, 'c', self.closeable)
|
||||
escape = sa(escape, kw, 'x', self.escape)
|
||||
action = sa(action, kw, None, self.action)
|
||||
showtb = sa(showtb, kw, None, self.showtb)
|
||||
type = Undef.sa(type, kw, 't', self.type)
|
||||
closeable = Undef.sa(closeable, kw, 'c', self.closeable)
|
||||
escape = Undef.sa(escape, kw, 'x', self.escape)
|
||||
action = Undef.sa(action, kw, None, self.action)
|
||||
showtb = Undef.sa(showtb, kw, None, self.showtb)
|
||||
|
||||
if callable(msg):
|
||||
# si msg est callable, par défaut ne pas mettre le résultat en
|
||||
|
|
|
@ -3,14 +3,19 @@
|
|||
__all__ = (
|
||||
'LazyObject',
|
||||
'dbconfig', 'fixsqlite', 'lazydb', 'oradbinfos',
|
||||
'incd', 'excd', 'Row', 'RowCtl',
|
||||
'incd', 'excd', 'ColSchema', 'Col', 'Row', 'RowCtl',
|
||||
'Migration',
|
||||
)
|
||||
|
||||
from os import path
|
||||
from types import StringType
|
||||
import csv
|
||||
|
||||
from ..base import Undef, odict, seqof
|
||||
from ..ext import web
|
||||
from .api import uval
|
||||
|
||||
Undef = Undef() # spécifique à ce module
|
||||
|
||||
class LazyObject(object):
|
||||
"""Un objet proxy vers un autre objet qui est construit avec retard
|
||||
|
@ -84,6 +89,69 @@ class oradbinfos(object):
|
|||
def __unicode__(self):
|
||||
return self()
|
||||
|
||||
class ColSchema(odict):
|
||||
def __init__(self, formatter=Undef, link=Undef, **kw):
|
||||
formatter = Undef.sa(formatter, kw, 'f', None)
|
||||
link = Undef.sa(link, kw, 'u', None)
|
||||
super(ColSchema, self).__init__(**kw)
|
||||
self.formatter = formatter
|
||||
self.link = link
|
||||
|
||||
def css(self, value=Undef):
|
||||
return None
|
||||
def format(self, value, index=Undef):
|
||||
formatter = self.formatter
|
||||
if type(formatter) is StringType:
|
||||
return formatter % value
|
||||
elif formatter is not None:
|
||||
return formatter(value)
|
||||
else:
|
||||
return value
|
||||
def text(self, value, index=Undef):
|
||||
return self.format(value, index)
|
||||
def html(self, value, index=Undef):
|
||||
link = uval(self.link)
|
||||
value = self.format(value, index)
|
||||
if link is None: return value
|
||||
else: return u'<a href="%s">%s</a>' % (link, value)
|
||||
|
||||
class Col(odict):
|
||||
def __init__(self, key, title=Undef, schema=Undef, formatter=Undef, link=Undef, **kw):
|
||||
title = Undef.sa(title, kw, 't', None)
|
||||
schema = Undef.sa(schema, kw, 's', None)
|
||||
formatter = Undef.sa(formatter, kw, 'f')
|
||||
link = Undef.sa(link, kw, 'u')
|
||||
super(Col, self).__init__(**kw)
|
||||
if title is None: title = key
|
||||
if schema is None and (formatter is not Undef or link is not Undef):
|
||||
schema = ColSchema(formatter, link)
|
||||
self.key = key
|
||||
self.title = title
|
||||
self.schema = schema
|
||||
|
||||
def geti(values, index):
|
||||
return values[index] if index >= 0 and index < len(values) else None
|
||||
|
||||
class RowSchema(odict):
|
||||
def __init__(self, cols=Undef, **kw):
|
||||
cols = seqof(Undef.sa(cols, kw, None, None))
|
||||
super(RowSchema, self).__init__(**kw)
|
||||
self.cols = cols
|
||||
|
||||
def col(self, index=Undef):
|
||||
if index is not Undef:
|
||||
return geti(self.cols, index)
|
||||
return None
|
||||
|
||||
def cell_schema(self, value=Undef, index=Undef):
|
||||
if index is not Undef:
|
||||
col = geti(self.cols, index)
|
||||
if col is not None: return col.schema
|
||||
return None
|
||||
|
||||
def css(self, value=Undef):
|
||||
return None
|
||||
|
||||
class Row(object):
|
||||
"""un proxy vers une ligne de web.database
|
||||
|
||||
|
@ -94,8 +162,24 @@ class Row(object):
|
|||
def __init__(self, row):
|
||||
self.__dict__['_row'] = row
|
||||
|
||||
def __contains__(self, name):
|
||||
return name in self._row
|
||||
def keys(self): return self._row.keys()
|
||||
def values(self): return self._row.values()
|
||||
def items(self): return self._row.items()
|
||||
def has_key(self): return self._row.has_key()
|
||||
def get(self): return self._row.get()
|
||||
def clear(self): return self._row.clear()
|
||||
def setdefault(self): return self._row.setdefault()
|
||||
def iterkeys(self): return self._row.iterkeys()
|
||||
def itervalues(self): return self._row.itervalues()
|
||||
def iteritems(self): return self._row.iteritems()
|
||||
def pop(self): return self._row.pop()
|
||||
def popitem(self): return self._row.popitem()
|
||||
def update(self): return self._row.update()
|
||||
def __iter__(self): return self._row.__iter__()
|
||||
def __contains__(self, key): return self._row.__contains__(key)
|
||||
|
||||
def copy(self): return self.__class__(self._row)
|
||||
|
||||
def __getattr__(self, name):
|
||||
row = self._row
|
||||
try:
|
||||
|
@ -128,9 +212,36 @@ class Row(object):
|
|||
def __delitem__(self, key):
|
||||
del self._row[key]
|
||||
|
||||
def __repr__(self): return repr(self._row)
|
||||
def __repr__(self): return '<%s:%r>' % (self.__class__.__name__, self._row)
|
||||
def __str__(self): return str(self._row)
|
||||
|
||||
def _firstof(values):
|
||||
for value in values:
|
||||
return value
|
||||
return None
|
||||
|
||||
class TableSchema(odict):
|
||||
@staticmethod
|
||||
def parse(rows):
|
||||
# on assume que rows est une liste de dictionnaires
|
||||
cols = [Col(key) for key in _firstof(rows)] if rows else Undef
|
||||
return TableSchema(cols)
|
||||
|
||||
def __init__(self, cols=Undef, **kw):
|
||||
cols = seqof(Undef.sa(cols, kw, None, None))
|
||||
super(TableSchema, self).__init__(**kw)
|
||||
self.cols = cols
|
||||
self.row_schemas = {}
|
||||
self.row_schemas['header'] = RowSchema(cols)
|
||||
self.row_schemas['body'] = RowSchema(cols)
|
||||
|
||||
def headers(self):
|
||||
return [col.title for col in self.cols]
|
||||
def header_row_schema(self):
|
||||
return self.row_schemas["header"]
|
||||
def body_row_schema(self, index):
|
||||
return self.row_schemas["body"]
|
||||
|
||||
def incd(fd, *names):
|
||||
td = dict()
|
||||
if not names:
|
||||
|
|
|
@ -5,15 +5,15 @@ __all__ = (
|
|||
'accesskeyif',
|
||||
'classif', 'addclassif',
|
||||
'favicon', 'css', 'js', 'jscss',
|
||||
'u', 'p',
|
||||
'p',
|
||||
'Action', 'Menu',
|
||||
)
|
||||
|
||||
from types import StringType, UnicodeType
|
||||
import urlparse, urllib
|
||||
|
||||
from nulib.base import odict, isseq, seqof
|
||||
from nulib.web import web
|
||||
from .api import u
|
||||
|
||||
def checked(b):
|
||||
return u' checked="checked"' if b else u''
|
||||
|
@ -45,7 +45,7 @@ def css(href, media=None):
|
|||
return ur'<link rel="stylesheet" href="%s" type="text/css"%s />' % (href, media or u'')
|
||||
def js(href):
|
||||
return ur'<script type="text/javascript" src="%s"></script>' % href
|
||||
def jscss(href, min=False):
|
||||
def jscss(href):
|
||||
if href.endswith(".min.js"):
|
||||
jshref = href
|
||||
csshref = "%s.css" % href[:-len(".min.js")]
|
||||
|
@ -57,15 +57,6 @@ def jscss(href, min=False):
|
|||
csshref = href
|
||||
return u"%s\n%s" % (js(jshref), css(csshref))
|
||||
|
||||
def u(text):
|
||||
"""Si text n'est pas de l'unicode, le convertir en unicode avec l'encoding utf-8
|
||||
"""
|
||||
t = type(text)
|
||||
if t is not UnicodeType:
|
||||
if t is not StringType: text = str(text)
|
||||
text = unicode(text, "utf-8")
|
||||
return text
|
||||
|
||||
def p(text):
|
||||
"""Si text commence par un tag, le laisser tel quel, sinon le mettre entre <p> et </p>
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue