index a01fa7c768b2740d13e176a2e2eb12b0e22989f2..d29f31d6600aac87eae1d8eae92f55a511c90a2b 100644 (file)
-import sys, cgi, urllib, os
+import sys, cgi, urllib, os, re, os.path, time, errno
from roundup import hyperdb, date
from roundup.i18n import _
from roundup import hyperdb, date
from roundup.i18n import _
-
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+try:
+ import cStringIO as StringIO
+except ImportError:
+ import StringIO
try:
import StructuredText
except ImportError:
StructuredText = None
try:
import StructuredText
except ImportError:
StructuredText = None
-# Make sure these modules are loaded
-# I need these to run PageTemplates outside of Zope :(
-# If we're running in a Zope environment, these modules will be loaded
-# already...
-if not sys.modules.has_key('zLOG'):
- import zLOG
- sys.modules['zLOG'] = zLOG
-if not sys.modules.has_key('MultiMapping'):
- import MultiMapping
- sys.modules['MultiMapping'] = MultiMapping
-if not sys.modules.has_key('ComputedAttribute'):
- import ComputedAttribute
- sys.modules['ComputedAttribute'] = ComputedAttribute
-if not sys.modules.has_key('ExtensionClass'):
- import ExtensionClass
- sys.modules['ExtensionClass'] = ExtensionClass
-if not sys.modules.has_key('Acquisition'):
- import Acquisition
- sys.modules['Acquisition'] = Acquisition
-
-# now it's safe to import PageTemplates and ZTUtils
-from PageTemplates import PageTemplate
-import ZTUtils
+# bring in the templating support
+from roundup.cgi.PageTemplates import PageTemplate
+from roundup.cgi.PageTemplates.Expressions import getEngine
+from roundup.cgi.TAL.TALInterpreter import TALInterpreter
+from roundup.cgi import ZTUtils
+
+# XXX WAH pagetemplates aren't pickleable :(
+#def getTemplate(dir, name, classname=None, request=None):
+# ''' Interface to get a template, possibly loading a compiled template.
+# '''
+# # source
+# src = os.path.join(dir, name)
+#
+# # see if we can get a compile from the template"c" directory (most
+# # likely is "htmlc"
+# split = list(os.path.split(dir))
+# split[-1] = split[-1] + 'c'
+# cdir = os.path.join(*split)
+# split.append(name)
+# cpl = os.path.join(*split)
+#
+# # ok, now see if the source is newer than the compiled (or if the
+# # compiled even exists)
+# MTIME = os.path.stat.ST_MTIME
+# if (not os.path.exists(cpl) or os.stat(cpl)[MTIME] < os.stat(src)[MTIME]):
+# # nope, we need to compile
+# pt = RoundupPageTemplate()
+# pt.write(open(src).read())
+# pt.id = name
+#
+# # save off the compiled template
+# if not os.path.exists(cdir):
+# os.makedirs(cdir)
+# f = open(cpl, 'wb')
+# pickle.dump(pt, f)
+# f.close()
+# else:
+# # yay, use the compiled template
+# f = open(cpl, 'rb')
+# pt = pickle.load(f)
+# return pt
+
+templates = {}
+
+def getTemplate(dir, name, extension, classname=None, request=None):
+ ''' Interface to get a template, possibly loading a compiled template.
+
+ "name" and "extension" indicate the template we're after, which in
+ most cases will be "name.extension". If "extension" is None, then
+ we look for a template just called "name" with no extension.
+
+ If the file "name.extension" doesn't exist, we look for
+ "_generic.extension" as a fallback.
+ '''
+ # default the name to "home"
+ if name is None:
+ name = 'home'
+
+ # find the source, figure the time it was last modified
+ if extension:
+ filename = '%s.%s'%(name, extension)
+ else:
+ filename = name
+ src = os.path.join(dir, filename)
+ try:
+ stime = os.stat(src)[os.path.stat.ST_MTIME]
+ except os.error, error:
+ if error.errno != errno.ENOENT or not extension:
+ raise
+ # try for a generic template
+ filename = '_generic.%s'%extension
+ src = os.path.join(dir, filename)
+ stime = os.stat(src)[os.path.stat.ST_MTIME]
+
+ key = (dir, filename)
+ if templates.has_key(key) and stime < templates[key].mtime:
+ # compiled template is up to date
+ return templates[key]
+
+ # compile the template
+ templates[key] = pt = RoundupPageTemplate()
+ pt.write(open(src).read())
+ pt.id = filename
+ pt.mtime = time.time()
+ return pt
class RoundupPageTemplate(PageTemplate.PageTemplate):
''' A Roundup-specific PageTemplate.
class RoundupPageTemplate(PageTemplate.PageTemplate):
''' A Roundup-specific PageTemplate.
python modules made available (XXX: not sure what's actually in
there tho)
'''
python modules made available (XXX: not sure what's actually in
there tho)
'''
- def __init__(self, client, classname=None, request=None):
- ''' Extract the vars from the client and install in the context.
- '''
- self.client = client
- self.classname = classname or self.client.classname
- self.request = request or HTMLRequest(self.client)
-
- def pt_getContext(self):
+ def getContext(self, client, classname, request):
c = {
c = {
- 'klass': HTMLClass(self.client, self.classname),
+ 'klass': HTMLClass(client, classname),
'options': {},
'nothing': None,
'options': {},
'nothing': None,
- 'request': self.request,
- 'content': self.client.content,
- 'db': HTMLDatabase(self.client),
- 'instance': self.client.instance
+ 'request': request,
+ 'content': client.content,
+ 'db': HTMLDatabase(client),
+ 'instance': client.instance
}
# add in the item if there is one
}
# add in the item if there is one
- if self.client.nodeid:
- c['item'] = HTMLItem(self.client.db, self.classname,
- self.client.nodeid)
- c[self.classname] = c['item']
+ if client.nodeid:
+ c['item'] = HTMLItem(client.db, classname, client.nodeid)
+ c[classname] = c['item']
else:
else:
- c[self.classname] = c['klass']
+ c[classname] = c['klass']
return c
return c
-
- def render(self, *args, **kwargs):
- if not kwargs.has_key('args'):
- kwargs['args'] = args
- return self.pt_render(extra_context={'options': kwargs})
+
+ def render(self, client, classname, request, **options):
+ """Render this Page Template"""
+
+ if not self._v_cooked:
+ self._cook()
+
+ __traceback_supplement__ = (PageTemplate.PageTemplateTracebackSupplement, self)
+
+ if self._v_errors:
+ raise PTRuntimeError, 'Page Template %s has errors.' % self.id
+
+ # figure the context
+ classname = classname or client.classname
+ request = request or HTMLRequest(client)
+ c = self.getContext(client, classname, request)
+ c.update({'options': options})
+
+ # and go
+ output = StringIO.StringIO()
+ TALInterpreter(self._v_program, self._v_macros,
+ getEngine().getContext(c), output, tal=1, strictinsert=0)()
+ return output.getvalue()
class HTMLDatabase:
''' Return HTMLClasses for valid class fetches
class HTMLDatabase:
''' Return HTMLClasses for valid class fetches
self.client = client
self.config = client.db.config
def __getattr__(self, attr):
self.client = client
self.config = client.db.config
def __getattr__(self, attr):
- self.client.db.getclass(attr)
+ try:
+ self.client.db.getclass(attr)
+ except KeyError:
+ raise AttributeError, attr
return HTMLClass(self.client, attr)
def classes(self):
l = self.client.db.classes.keys()
return HTMLClass(self.client, attr)
def classes(self):
l = self.client.db.classes.keys()
def __repr__(self):
return '<HTMLClass(0x%x) %s>'%(id(self), self.classname)
def __repr__(self):
return '<HTMLClass(0x%x) %s>'%(id(self), self.classname)
- def __getattr__(self, attr):
+ def __getitem__(self, item):
''' return an HTMLItem instance'''
''' return an HTMLItem instance'''
- #print 'getattr', (self, attr)
- if attr == 'creator':
+ #print 'getitem', (self, attr)
+ if item == 'creator':
return HTMLUser(self.client)
return HTMLUser(self.client)
- if not self.props.has_key(attr):
- raise AttributeError, attr
- prop = self.props[attr]
+ if not self.props.has_key(item):
+ raise KeyError, item
+ prop = self.props[item]
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
else:
value = None
if isinstance(prop, klass):
else:
value = None
if isinstance(prop, klass):
- return htmlklass(self.db, '', prop, attr, value)
+ return htmlklass(self.db, '', prop, item, value)
# no good
# no good
- raise AttributeError, attr
+ raise KeyError, item
+
+ def __getattr__(self, attr):
+ ''' convenience access '''
+ try:
+ return self[attr]
+ except KeyError:
+ raise AttributeError, attr
def properties(self):
''' Return HTMLProperty for all props
def properties(self):
''' Return HTMLProperty for all props
l = [HTMLItem(self.db, self.classname, x) for x in self.klass.list()]
return l
l = [HTMLItem(self.db, self.classname, x) for x in self.klass.list()]
return l
+ def csv(self):
+ ''' Return the items of this class as a chunk of CSV text.
+ '''
+ # get the CSV module
+ try:
+ import csv
+ except ImportError:
+ return 'Sorry, you need the csv module to use this function.\n'\
+ 'Get it from: http://www.object-craft.com.au/projects/csv/'
+
+ props = self.propnames()
+ p = csv.parser()
+ s = StringIO.StringIO()
+ s.write(p.join(props) + '\n')
+ for nodeid in self.klass.list():
+ l = []
+ for name in props:
+ value = self.klass.get(nodeid, name)
+ if value is None:
+ l.append('')
+ elif isinstance(value, type([])):
+ l.append(':'.join(map(str, value)))
+ else:
+ l.append(str(self.klass.get(nodeid, name)))
+ s.write(p.join(l) + '\n')
+ return s.getvalue()
+
+ def propnames(self):
+ ''' Return the list of the names of the properties of this class.
+ '''
+ idlessprops = self.klass.getprops(protected=0).keys()
+ idlessprops.sort()
+ return ['id'] + idlessprops
+
def filter(self, request=None):
''' Return a list of items from this class, filtered and sorted
by the current requested filterspec/filter/sort/group args
def filter(self, request=None):
''' Return a list of items from this class, filtered and sorted
by the current requested filterspec/filter/sort/group args
You may optionally override the label displayed, the width and
height. The popup window will be resizable and scrollable.
'''
You may optionally override the label displayed, the width and
height. The popup window will be resizable and scrollable.
'''
- return '<a href="javascript:help_window(\'classhelp?classname=%s&' \
- 'properties=%s\', \'%s\', \'%s\')"><b>(%s)</b></a>'%(self.classname,
- properties, width, height, label)
+ return '<a href="javascript:help_window(\'%s?:template=help&' \
+ ':contentonly=1&properties=%s\', \'%s\', \'%s\')"><b>'\
+ '(%s)</b></a>'%(self.classname, properties, width, height, label)
def submit(self, label="Submit New Entry"):
''' Generate a submit button (and action hidden element)
def submit(self, label="Submit New Entry"):
''' Generate a submit button (and action hidden element)
# create a new request and override the specified args
req = HTMLRequest(self.client)
req.classname = self.classname
# create a new request and override the specified args
req = HTMLRequest(self.client)
req.classname = self.classname
- req.__dict__.update(kwargs)
+ req.update(kwargs)
# new template, using the specified classname and request
# new template, using the specified classname and request
- pt = RoundupPageTemplate(self.client, self.classname, req)
-
- # use the specified template
- name = self.classname + '.' + name
- pt.write(open('/tmp/test/html/%s'%name).read())
- pt.id = name
+ pt = getTemplate(self.db.config.TEMPLATES, self.classname, name)
# XXX handle PT rendering errors here nicely
try:
# XXX handle PT rendering errors here nicely
try:
- return pt.render()
+ # use our fabricated request
+ return pt.render(self.client, self.classname, req)
except PageTemplate.PTRuntimeError, message:
return '<strong>%s</strong><ol>%s</ol>'%(message,
cgi.escape('<li>'.join(pt._v_errors)))
except PageTemplate.PTRuntimeError, message:
return '<strong>%s</strong><ol>%s</ol>'%(message,
cgi.escape('<li>'.join(pt._v_errors)))
def __repr__(self):
return '<HTMLItem(0x%x) %s %s>'%(id(self), self.classname, self.nodeid)
def __repr__(self):
return '<HTMLItem(0x%x) %s %s>'%(id(self), self.classname, self.nodeid)
- def __getattr__(self, attr):
+ def __getitem__(self, item):
''' return an HTMLItem instance'''
''' return an HTMLItem instance'''
- #print 'getattr', (self, attr)
- if attr == 'id':
+ if item == 'id':
return self.nodeid
return self.nodeid
-
- if not self.props.has_key(attr):
- raise AttributeError, attr
- prop = self.props[attr]
+ if not self.props.has_key(item):
+ raise KeyError, item
+ prop = self.props[item]
# get the value, handling missing values
# get the value, handling missing values
- value = self.klass.get(self.nodeid, attr, None)
+ value = self.klass.get(self.nodeid, item, None)
if value is None:
if value is None:
- if isinstance(self.props[attr], hyperdb.Multilink):
+ if isinstance(self.props[item], hyperdb.Multilink):
value = []
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
if isinstance(prop, klass):
value = []
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
if isinstance(prop, klass):
- return htmlklass(self.db, self.nodeid, prop, attr, value)
+ return htmlklass(self.db, self.nodeid, prop, item, value)
- # no good
- raise AttributeError, attr
+ raise KeyErorr, item
+
+ def __getattr__(self, attr):
+ ''' convenience access to properties '''
+ try:
+ return self[attr]
+ except KeyError:
+ raise AttributeError, attr
def submit(self, label="Submit Changes"):
''' Generate a submit button (and action hidden element)
def submit(self, label="Submit Changes"):
''' Generate a submit button (and action hidden element)
def plain(self, escape=0):
if self.value is None:
return _('[unselected]')
def plain(self, escape=0):
if self.value is None:
return _('[unselected]')
- linkcl = self.db.classes[self.klass.classname]
+ linkcl = self.db.classes[self.prop.classname]
k = linkcl.labelprop(1)
value = str(linkcl.get(self.value, k))
if escape:
k = linkcl.labelprop(1)
value = str(linkcl.get(self.value, k))
if escape:
s = 'selected '
l.append(_('<option %svalue="-1">- no selection -</option>')%s)
if linkcl.getprops().has_key('order'):
s = 'selected '
l.append(_('<option %svalue="-1">- no selection -</option>')%s)
if linkcl.getprops().has_key('order'):
- sort_on = 'order'
+ sort_on = ('+', 'order')
else:
else:
- sort_on = linkcl.labelprop()
- options = linkcl.filter(None, conditions, [sort_on], [])
+ sort_on = ('+', linkcl.labelprop())
+ options = linkcl.filter(None, conditions, sort_on, (None, None))
for optionid in options:
option = linkcl.get(optionid, k)
s = ''
for optionid in options:
option = linkcl.get(optionid, k)
s = ''
value = self.value[num]
return HTMLItem(self.db, self.prop.classname, value)
value = self.value[num]
return HTMLItem(self.db, self.prop.classname, value)
+ def reverse(self):
+ ''' return the list in reverse order '''
+ l = self.value[:]
+ l.reverse()
+ return [HTMLItem(self.db, self.prop.classname, value) for value in l]
+
def plain(self, escape=0):
linkcl = self.db.classes[self.prop.classname]
k = linkcl.labelprop(1)
def plain(self, escape=0):
linkcl = self.db.classes[self.prop.classname]
k = linkcl.labelprop(1)
linkcl = self.db.getclass(self.prop.classname)
if linkcl.getprops().has_key('order'):
linkcl = self.db.getclass(self.prop.classname)
if linkcl.getprops().has_key('order'):
- sort_on = 'order'
+ sort_on = ('+', 'order')
else:
else:
- sort_on = linkcl.labelprop()
- options = linkcl.filter(None, conditions, [sort_on], [])
+ sort_on = ('+', linkcl.labelprop())
+ options = linkcl.filter(None, conditions, sort_on, (None,None))
height = height or min(len(options), 7)
l = ['<select multiple name="%s" size="%s">'%(self.name, height)]
k = linkcl.labelprop(1)
height = height or min(len(options), 7)
l = ['<select multiple name="%s" size="%s">'%(self.name, height)]
k = linkcl.labelprop(1)
else:
return value.value.split(',')
else:
return value.value.split(',')
-# XXX This is starting to look a lot (in data terms) like the client object
-# itself!
+class ShowDict:
+ ''' A convenience access to the :columns index parameters
+ '''
+ def __init__(self, columns):
+ self.columns = {}
+ for col in columns:
+ self.columns[col] = 1
+ def __getitem__(self, name):
+ return self.columns.has_key(name)
+
class HTMLRequest:
''' The *request*, holding the CGI form and environment.
class HTMLRequest:
''' The *request*, holding the CGI form and environment.
+ "form" the CGI form as a cgi.FieldStorage
+ "env" the CGI environment variables
+ "url" the current URL path for this request
+ "base" the base URL for this instance
+ "user" a HTMLUser instance for this user
+ "classname" the current classname (possibly None)
+ "template" the current template (suffix, also possibly None)
+
+ Index args:
+ "columns" dictionary of the columns to display in an index page
+ "show" a convenience access to columns - request/show/colname will
+ be true if the columns should be displayed, false otherwise
+ "sort" index sort column (direction, column name)
+ "group" index grouping property (direction, column name)
+ "filter" properties to filter the index on
+ "filterspec" values to filter the index on
+ "search_text" text to perform a full-text search on for an index
+
'''
def __init__(self, client):
self.client = client
'''
def __init__(self, client):
self.client = client
self.form = client.form
self.env = client.env
self.base = client.base
self.form = client.form
self.env = client.env
self.base = client.base
+ self.url = client.url
self.user = HTMLUser(client)
# store the current class name and action
self.classname = client.classname
self.user = HTMLUser(client)
# store the current class name and action
self.classname = client.classname
- self.template_type = client.template_type
+ self.template = client.template
# extract the index display information from the form
# extract the index display information from the form
- self.columns = {}
+ self.columns = []
if self.form.has_key(':columns'):
if self.form.has_key(':columns'):
- for entry in handleListCGIValue(self.form[':columns']):
- self.columns[entry] = 1
- self.sort = []
+ self.columns = handleListCGIValue(self.form[':columns'])
+ self.show = ShowDict(self.columns)
+
+ # sorting
+ self.sort = (None, None)
if self.form.has_key(':sort'):
if self.form.has_key(':sort'):
- self.sort = handleListCGIValue(self.form[':sort'])
- self.group = []
+ sort = self.form[':sort'].value
+ if sort.startswith('-'):
+ self.sort = ('-', sort[1:])
+ else:
+ self.sort = ('+', sort)
+ if self.form.has_key(':sortdir'):
+ self.sort = ('-', self.sort[1])
+
+ # grouping
+ self.group = (None, None)
if self.form.has_key(':group'):
if self.form.has_key(':group'):
- self.group = handleListCGIValue(self.form[':group'])
+ group = self.form[':group'].value
+ if group.startswith('-'):
+ self.group = ('-', group[1:])
+ else:
+ self.group = ('+', group)
+ if self.form.has_key(':groupdir'):
+ self.group = ('-', self.group[1])
+
+ # filtering
self.filter = []
if self.form.has_key(':filter'):
self.filter = handleListCGIValue(self.form[':filter'])
self.filterspec = {}
self.filter = []
if self.form.has_key(':filter'):
self.filter = handleListCGIValue(self.form[':filter'])
self.filterspec = {}
- for name in self.filter:
- if self.form.has_key(name):
- self.filterspec[name]=handleListCGIValue(self.form[name])
+ if self.classname is not None:
+ props = self.client.db.getclass(self.classname).getprops()
+ for name in self.filter:
+ if self.form.has_key(name):
+ prop = props[name]
+ fv = self.form[name]
+ if (isinstance(prop, hyperdb.Link) or
+ isinstance(prop, hyperdb.Multilink)):
+ self.filterspec[name] = handleListCGIValue(fv)
+ else:
+ self.filterspec[name] = fv.value
+
+ # full-text search argument
+ self.search_text = None
+ if self.form.has_key(':search_text'):
+ self.search_text = self.form[':search_text'].value
+
+ # pagination - size and start index
+ # figure batch args
+ if self.form.has_key(':pagesize'):
+ self.pagesize = int(self.form[':pagesize'].value)
+ else:
+ self.pagesize = 50
+ if self.form.has_key(':startwith'):
+ self.startwith = int(self.form[':startwith'].value)
+ else:
+ self.startwith = 0
+
+ def update(self, kwargs):
+ self.__dict__.update(kwargs)
+ if kwargs.has_key('columns'):
+ self.show = ShowDict(self.columns)
+
+ def description(self):
+ ''' Return a description of the request - handle for the page title.
+ '''
+ s = [self.client.db.config.INSTANCE_NAME]
+ if self.classname:
+ if self.client.nodeid:
+ s.append('- %s%s'%(self.classname, self.client.nodeid))
+ else:
+ s.append('- index of '+self.classname)
+ else:
+ s.append('- home')
+ return ' '.join(s)
def __str__(self):
d = {}
def __str__(self):
d = {}
d['env'] = e
return '''
form: %(form)s
d['env'] = e
return '''
form: %(form)s
+url: %(url)r
base: %(base)r
classname: %(classname)r
base: %(base)r
classname: %(classname)r
-template_type: %(template_type)r
+template: %(template)r
columns: %(columns)r
sort: %(sort)r
group: %(group)r
filter: %(filter)r
columns: %(columns)r
sort: %(sort)r
group: %(group)r
filter: %(filter)r
-filterspec: %(filterspec)r
+search_text: %(search_text)r
+pagesize: %(pagesize)r
+startwith: %(startwith)r
env: %(env)s
'''%d
env: %(env)s
'''%d
- def indexargs_form(self):
+ def indexargs_form(self, columns=1, sort=1, group=1, filter=1,
+ filterspec=1):
''' return the current index args as form elements '''
l = []
s = '<input type="hidden" name="%s" value="%s">'
''' return the current index args as form elements '''
l = []
s = '<input type="hidden" name="%s" value="%s">'
- if self.columns:
- l.append(s%(':columns', ','.join(self.columns.keys())))
- if self.sort:
- l.append(s%(':sort', ','.join(self.sort)))
- if self.group:
- l.append(s%(':group', ','.join(self.group)))
- if self.filter:
+ if columns and self.columns:
+ l.append(s%(':columns', ','.join(self.columns)))
+ if sort and self.sort[1] is not None:
+ if self.sort[0] == '-':
+ val = '-'+self.sort[1]
+ else:
+ val = self.sort[1]
+ l.append(s%(':sort', val))
+ if group and self.group[1] is not None:
+ if self.group[0] == '-':
+ val = '-'+self.group[1]
+ else:
+ val = self.group[1]
+ l.append(s%(':group', val))
+ if filter and self.filter:
l.append(s%(':filter', ','.join(self.filter)))
l.append(s%(':filter', ','.join(self.filter)))
- for k,v in self.filterspec.items():
- l.append(s%(k, ','.join(v)))
+ if filterspec:
+ for k,v in self.filterspec.items():
+ l.append(s%(k, ','.join(v)))
+ if self.search_text:
+ l.append(s%(':search_text', self.search_text))
+ l.append(s%(':pagesize', self.pagesize))
+ l.append(s%(':startwith', self.startwith))
return '\n'.join(l)
def indexargs_href(self, url, args):
return '\n'.join(l)
def indexargs_href(self, url, args):
+ ''' embed the current index args in a URL '''
l = ['%s=%s'%(k,v) for k,v in args.items()]
l = ['%s=%s'%(k,v) for k,v in args.items()]
- if self.columns:
- l.append(':columns=%s'%(','.join(self.columns.keys())))
- if self.sort:
- l.append(':sort=%s'%(','.join(self.sort)))
- if self.group:
- l.append(':group=%s'%(','.join(self.group)))
- if self.filter:
+ if self.columns and not args.has_key(':columns'):
+ l.append(':columns=%s'%(','.join(self.columns)))
+ if self.sort[1] is not None and not args.has_key(':sort'):
+ if self.sort[0] == '-':
+ val = '-'+self.sort[1]
+ else:
+ val = self.sort[1]
+ l.append(':sort=%s'%val)
+ if self.group[1] is not None and not args.has_key(':group'):
+ if self.group[0] == '-':
+ val = '-'+self.group[1]
+ else:
+ val = self.group[1]
+ l.append(':group=%s'%val)
+ if self.filter and not args.has_key(':columns'):
l.append(':filter=%s'%(','.join(self.filter)))
for k,v in self.filterspec.items():
l.append(':filter=%s'%(','.join(self.filter)))
for k,v in self.filterspec.items():
- l.append('%s=%s'%(k, ','.join(v)))
+ if not args.has_key(k):
+ l.append('%s=%s'%(k, ','.join(v)))
+ if self.search_text and not args.has_key(':search_text'):
+ l.append(':search_text=%s'%self.search_text)
+ if not args.has_key(':pagesize'):
+ l.append(':pagesize=%s'%self.pagesize)
+ if not args.has_key(':startwith'):
+ l.append(':startwith=%s'%self.startwith)
return '%s?%s'%(url, '&'.join(l))
def base_javascript(self):
return '%s?%s'%(url, '&'.join(l))
def base_javascript(self):
# get the list of ids we're batching over
klass = self.client.db.getclass(self.classname)
# get the list of ids we're batching over
klass = self.client.db.getclass(self.classname)
- l = klass.filter(None, filterspec, sort, group)
-
- # figure batch args
- if self.form.has_key(':pagesize'):
- size = int(self.form[':pagesize'].value)
- else:
- size = 50
- if self.form.has_key(':startwith'):
- start = int(self.form[':startwith'].value)
+ if self.search_text:
+ matches = self.client.db.indexer.search(
+ re.findall(r'\b\w{2,25}\b', self.search_text), klass)
else:
else:
- start = 0
+ matches = None
+ l = klass.filter(matches, filterspec, sort, group)
# return the batch object
# return the batch object
- return Batch(self.client, self.classname, l, size, start)
+ return Batch(self.client, self.classname, l, self.pagesize,
+ self.startwith)
+
+# extend the standard ZTUtils Batch object to remove dependency on
+# Acquisition and add a couple of useful methods
class Batch(ZTUtils.Batch):
def __init__(self, client, classname, l, size, start, end=0, orphan=0, overlap=0):
self.client = client
self.classname = classname
class Batch(ZTUtils.Batch):
def __init__(self, client, classname, l, size, start, end=0, orphan=0, overlap=0):
self.client = client
self.classname = classname
+ self.last_index = self.last_item = None
+ self.current_item = None
ZTUtils.Batch.__init__(self, l, size, start, end, orphan, overlap)
# overwrite so we can late-instantiate the HTMLItem instance
ZTUtils.Batch.__init__(self, l, size, start, end, orphan, overlap)
# overwrite so we can late-instantiate the HTMLItem instance
if index >= self.length: raise IndexError, index
if index >= self.length: raise IndexError, index
+ # move the last_item along - but only if the fetched index changes
+ # (for some reason, index 0 is fetched twice)
+ if index != self.last_index:
+ self.last_item = self.current_item
+ self.last_index = index
+
# wrap the return in an HTMLItem
# wrap the return in an HTMLItem
- return HTMLItem(self.client.db, self.classname,
+ self.current_item = HTMLItem(self.client.db, self.classname,
self._sequence[index+self.first])
self._sequence[index+self.first])
+ return self.current_item
+
+ def propchanged(self, property):
+ ''' Detect if the property marked as being the group property
+ changed in the last iteration fetch
+ '''
+ if (self.last_item is None or
+ self.last_item[property] != self.current_item[property]):
+ return 1
+ return 0
# override these 'cos we don't have access to acquisition
def previous(self):
# override these 'cos we don't have access to acquisition
def previous(self):
- print self.start
if self.start == 1:
return None
return Batch(self.client, self.classname, self._sequence, self._size,
if self.start == 1:
return None
return Batch(self.client, self.classname, self._sequence, self._size,