Leave the db.py as Mr.Freeze built it - we need this for the "things" model.
In model/A_widgets.py add the following:
def __process_data(dt,level,maxlevels,db): # this is butt-ugly ... but seems to work ! header = dt[0] data = dt[1:] if level == 1: cnt = len(db[0]) + 1 db[0].append((cnt,header,None)) else: lvl = level - 1 plvl = lvl - 1 cnt = len(db[lvl]) + 1 pcnt = len(db[plvl]) db[lvl].append((cnt,header,pcnt)) if level < maxlevels-1: for t in data: __process_data(t,level+1,maxlevels,db) else: for r in data: for t in r: lvl = maxlevels-1 plvl = lvl - 1 cnt = len(db[lvl]) + 1 pcnt = len(db[plvl]) db[lvl].append((cnt,t,pcnt))
def process_it(hd,lst): depth = len(dhead) db = [[] for d in range(depth)] # one list per heading for t in lst: __process_data(t,1,depth,db) return db
class ListCascadingSelect(object):
"""
Creates dependent selects based on a recursive list-of-lists.
Pass the list headings in order of least to most specific.
Based on http://web2pyslices.com/main/slices/take_slice/85
"""
def init(self, headings, datalist):
self.datalist = datalist
self.tables = headings
self.prompt = lambda table:str(table)
def widget(self,f,v):
uid = str(uuid.uuid4())[:8]
d_id = "cascade-" + uid
wrapper = TABLE(id=d_id)
parent = None; parent_format = None;
fn = ''
vr = 'var dd%s = [];var oi%s = [];\n' % (uid,uid)
prompt = [self.prompt(table) for table in self.tables]
vr += 'var pr%s = ["' % uid + '","'.join([str(p) for p in prompt]) + '"];\n'
f_inp = SQLFORM.widgets.string.widget(f,v)
f_id = f_inp['_id']
f_inp['_type'] = "hidden"
datadict = process_it(self.tables,self.datalist)
for tc, table in enumerate(self.tables):
db = table
format = table + "_name"
options = datadict[tc]
id = str(table)
opts = [OPTION(opt,_value=rowid,
_parent=str(parent) if parent else '0') \
for (rowid,opt,parent) in options]
opts.insert(0, OPTION(prompt[tc],_value=0))
inp = SELECT(opts ,_parent=str(parent) + \
"" + str(parent_format),
_id=id,_name=id,
_disabled="disabled" if parent else None)
wrapper.append(TR(inp))
next = str(tc + 1)
vr += 'var p%s = jQuery("#%s #%s"); dd%s.push(p%s);\n' % (tc,d_id,id,uid,tc)
vr += 'var i%s = jQuery("option",p%s).clone(); oi%s.push(i%s);\n' % (tc,tc,uid,tc)
fn_in = 'for (i=%s;i<%s;i+=1){dd%s[i].find("option").remove();'\
'dd%s[i].append(\'<option value="0">\' + pr%s[i] + \'</option>\');'\
'dd%s[i].attr("disabled","disabled");}\n' % \
(next,len(self.tables),uid,uid,uid,uid)
fn_in +='oi%s[%s].each(function(i){'\
'if (jQuery(this).attr("parent") == dd%s[%s].val()){'\
'dd%s[%s].append(this);}});' % (uid,next,uid,tc,uid,next)
fn_in += 'dd%s[%s].removeAttr("disabled");\n' % (uid,next)
fn_in += 'jQuery("#%s").val("");' % f_id
if (tc < len(self.tables)-1):
fn += 'dd%s[%s].change(function(){%s});\n' % (uid,tc,fn_in)
else:
fn_in = 'jQuery("#%s").val(jQuery(this).val());' % f_id
fn += 'dd%s[%s].change(function(){%s});\n' % (uid,tc,fn_in)
if v:
fn += 'dd%s[%s].val(%s);' % (uid,tc,v)
parent = table
parent_format = format
wrapper.append(f_inp)
wrapper.append(SCRIPT(vr,fn))
return wrapper
Then in controllers/default.py I hacked the following ...
dhead = ("State", "City", "Zipcode")
dlist = ( ("Texas", ("Austin", ("78704","78745")), ("Dallas", ("75001","75038")) ), ("Illinois", ("Chicago", ("60606","60607")), ("Aurora", ("60504","60505")) ), ("California", ("Los Angeles", ("90005","90006")), ("San Diego", ("92101","92102")) ) )
def cascading_select(): #cascade = CascadingSelect(db.state,db.city,db.zipcode) Mr.Freeze's call - cascade = ListCascadingSelect(dhead,dlist) db.things.location.widget = cascade.widget form = SQLFORM(db.things) return dict(form=form)
Ok - that's it. To be frank I hardly understood what Mr.Freeze did - while I understand Python quite well, javascripy/ajax/css/html is beyond me, so I had to build on his talented work. I make no claims on the above code - in the end it's just a hack on existing code.
Comments (4)
0
bebers 14 years ago
0
mrgrieves 14 years ago
0
mrfreeze 14 years ago
0
mrfreeze 14 years ago