From dbf6ce6d6c64de889470b8d101a3acffdca46480 Mon Sep 17 00:00:00 2001 From: Nico Zanferrari Date: Sat, 22 Sep 2012 00:06:21 +0200 Subject: [PATCH 01/78] Modified share to Buzz to Google+ --- .../welcome/static/images/google-buzz.png | Bin 1976 -> 0 bytes applications/welcome/static/images/gplus-32.png | Bin 0 -> 1513 bytes applications/welcome/static/js/share.js | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 applications/welcome/static/images/google-buzz.png create mode 100644 applications/welcome/static/images/gplus-32.png diff --git a/applications/welcome/static/images/google-buzz.png b/applications/welcome/static/images/google-buzz.png deleted file mode 100644 index 844d5412db197af8942c71747d899c08694e7c75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1976 zcmV;p2S@mcP)l+U-0@@V z+IiRRP$1CXP!~zy7Ov^J`H@U6*MI2sj}HzUc@84Gx##gsFLkut*>}%|weWk~w-O)u zl9KrE(C`75OX?mtf<4^+KOWk>Wz&WOT^;M_F$be;-ckahz|*gVlV{K4?1hVcV!-F? zZ*N%*-7pEfj9a~QgOL!hzI6?TN3Zsak#Hy>hypajz!$X`7QGgHPl?rX!kIyVZsg%km%vKmen44Xi`TYy{Oa96z#8|xD| zPek5(?Uz{76-2mu?+R|Phya0G*RjA){xXEDCy1xEHX={JZw+UVD(GN*EvrJD2^n>+ z6{8Hn(6P%njIVExgDZ|8`A$DVJ^Pj?KxagY1X#;hVE@q}jB_6BY;C|mvValNxC-hJ zU}wv;4N{<_>6lDs@U8p-^xT(6xcNbF-iKkGIfBpLeF2fJ&n$HTo#o4P`15;yU;uT$ z+lP%_3xB;djiH$$6xFb|O1q?J$QMYK`zK1Hr?4Cr&&*#j>9sv`>`gq95DsDW)@d2UI~iUqYHd)42jNw5KyU zT)vvbquR^Zw=;lnq78yC)YR+0y@{5t7Hl26h;(v4 zUcC2d1fwyEdxV z1gzQ^D17n>JRZu=*(`zq36Bd|l>hx({Ho(gNRb#ghlHVNFf%Fakl(>CzTJ%Q?W=0R zZ564smo*5I1(`CXlp2B@i=oIwaJXu_?Xw77rbZr!=?q&(30Es6{E14=zg#g8X>6Adz ziEzv9fu@vUP+?(O2-LlNbpbrp;m5OMufsbv0cma=Yh%aJyDg7EBagQmU3mAz-=WS< zz|s`bTBWX20Mrbu(iF<+5opCC48c>ysn!9@A+YezH8nw{OI0@^Srvs?pKyo#c={_* za3_!B)eQo=yA^~&WI_&b1$ex5n;XhM{)MmIdpG28grZx4rOpDS2^dpjP$*+`|7y4v zYQEs4Vbui-%&0~eHhl?2)wC^OIlHV<7R+VgZkWaWJt`tWx5F?0;d3bqe;fdqxHDW#WH|gTm?s!1Pfk|kHf)I6s3Z zj%!4yy~0QC_{;8KZz!ixfp|CGHmuf1rk?N3*52`p`ahx?|vVz{P}12 zbd!lYJSJ&_rPb_n1gKGBf)XH0v%;C!Lul&wCPIFnEpstO1rwDRSV)P*t1cA6hhyh( zdXB9w!FK z1&j@9UpPJTA^tS@8hDvUu0S&YX*OT9AQ=*x0&$GzCQ&LYHW`m7qsbq~x=16sR&}B& z6t`vgXvD7zhnC2$gaGIC0#=PUESZX~OphWWhcTK-!Yot(?r&L-FR$)|S6cbofobjc zc_F)`>rPuXCW`@0Gn~Avjf3qSy?C(YfhE%t^PMP)Fbt#mY~daow>@qdk|fJ1v7}UA@{%TOFF#CL|JO(!B=-;|7&fnITK|6rFW5rku_(MAxoV=Dxmn^f*$jhW zF-(SS+ww>IfAdmvJl;p&h-hqxQuE<%`iDxT4O3a3p2exNgGi=Q2Y&j)@9n8N^Vt_( z+)W<}{cc%K2oy|$Al_60W$Ik)3rtbf5nb2&f4=tz2ig7q2`~T?5QoJ-f!3=40000< KMNUMnLSTZR$)e-{ diff --git a/applications/welcome/static/images/gplus-32.png b/applications/welcome/static/images/gplus-32.png new file mode 100644 index 0000000000000000000000000000000000000000..c42eab784578bf4e827722400f125760ebab527a GIT binary patch literal 1513 zcmV~mL-d9E}6-eW&UBZZ2My_Cfm%i zR~F|3K~NBsXK5*=D3)i1wty(22(yB`TUx&RokMTe)+&h3CZC-4{C@YG-#z!-d&`WO zGS-!qz^GkB4wEK=|ACn(NH+1}^K$G@-wCy z0;G7yEEQ9(4no!1aNNo}0oZK9SWg%F&gWvdMeFGE#5OSwZT4>7=WNp!v>pB&nq6C< ze0`nBxsnntCUn;FS~TQt1(Z_(Qe0=pMhw?5W1SYR?%xf?>OeHnUTCEOc*}pQcWi=X z_`V}=;&v}o8LJ(6o;0ULd0YW0-e$*UEEaIq(NVfaeqzuTI#|+7zvZ+)8V`O1DVMud zkR$d@vpugu=KqlDG`9lW;+2HW&?e$0dT)r0#3yvukQ|26SYM17+9Bmn4-cU{F$7mA z#&Z;Ilg;85BjW5K2>{ar;8Phz&JpAg9TdRG24xRXBc2dwLg0 zaS1Dt1>wf2zhE`pb1~J|3zMc6!_8Vp-#xVw@)UZ+(o)U`-%swOSe3nHmDE`jxdIB> zV8&mL!c?ckkhWg5(}Vr6-Ww1mdpc2>5`#)Qi)W$2-ZD{Hj2}v(R*6CiBUa#i#B!8n zB*97#CrMvn9_@`)v>*JQiBfyZ`0g$vrA~Mu)$eY`^uQg5v5q!eppAGbdX-D=(_$BC zKzF==qBUWdyxxWB{@V_NiVBpZ#)`Yd({XbtacU*3ByuIV3w-Irm!lwT8P0|-Ltf}o zXg>J>)AZ_fHp*|oots5&F&+1`SRoCRPm|?_EJaaLB-H!&K>O8aF#h@@ZqdJ@$?HZ~ z`fj?Iy3vKYkM|*;iY=nT7oyPKvUBw0YdmxirrK&)dV3s3ni?=DFBSNA=a{4}doS{+ zaK0LaPw2cI8*gug^kR3*sZ}FL+C1UXT$O&4E zv$9~ARC1WR90=>T`dVjeH1J4JnS9Y<8;0P&*v_?+xtd)gw|EW3ec P00000NkvXXu0mjf1Z(LN literal 0 HcmV?d00001 diff --git a/applications/welcome/static/js/share.js b/applications/welcome/static/js/share.js index ab0bcf1b..5e9d2c26 100644 --- a/applications/welcome/static/js/share.js +++ b/applications/welcome/static/js/share.js @@ -21,8 +21,8 @@ jQuery(function(){ var title = escape(jQuery('title').text()); var twit = 'http://twitter.com/home?status='+title+'%20'+url; var facebook = 'http://www.facebook.com/sharer.php?u='+url; - var buzz = 'https://plus.google.com/share?url='+url; - var tbar = '
Share
Share on TwitterShare on facebookShare on Buzz
'; + var gplus = 'https://plus.google.com/share?url='+url; + var tbar = '
Share
Share on TwitterShare on facebookShare on Google Plus
'; // Add the share tool bar. jQuery('body').append(tbar); var st = jQuery('#socialdrawer'); From 457ef24c0456d4cf0f3b2553f984ec5246fb21a8 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 21 Sep 2012 22:01:51 -0500 Subject: [PATCH 02/78] added missing patch, thanks Niphlod --- VERSION | 2 +- gluon/widget.py | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/VERSION b/VERSION index 44f1be1a..486b127c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 09:37:29) stable +Version 2.0.9 (2012-09-21 22:01:45) stable diff --git a/gluon/widget.py b/gluon/widget.py index 890080e6..670583ed 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -955,6 +955,19 @@ def check_existent_app(options,appname): if os.path.isdir(os.path.join(options.folder, 'applications', appname)): return True +def get_code_for_scheduler(app, options): + if len(app) == 1 or app[1] == None: + code = "from gluon import current;current._scheduler.loop()" + else: + code = "from gluon import current;current._scheduler.group_names = ['%s'];" + code += "current._scheduler.loop()" + code = code % ("','".join(app[1:])) + app_ = app[0] + if not check_existent_app(options, app_): + print "Application '%s' doesn't exist, skipping" % (app_) + return None, None + return app_, code + def start_schedulers(options): try: from multiprocessing import Process @@ -965,20 +978,21 @@ def start_schedulers(options): apps = [(app.strip(), None) for app in options.scheduler.split(',')] if options.scheduler_groups: apps = options.scheduler_groups + code = "from gluon import current;current._scheduler.loop()" + logging.getLogger().setLevel(options.debuglevel) + if len(apps) == 1: + app_, code = get_code_for_scheduler(apps[0], options) + if not app_: + return + print 'starting single-scheduler for "%s"...' % app_ + run(app_,True,True,None,False,code) + return for app in apps: - if len(app) == 1 or app[1] == None: - code = "from gluon import current;current._scheduler.loop()" - else: - code = "from gluon import current;current._scheduler.group_names = ['%s'];" - code += "current._scheduler.loop()" - code = code % ("','".join(app[1:])) - app_ = app[0] - if not check_existent_app(options, app_): - print "Application '%s' doesn't exist, skipping" % (app_) + app_, code = get_code_for_scheduler(app, options) + if not app_: continue print 'starting scheduler for "%s"...' % app_ args = (app_,True,True,None,False,code) - logging.getLogger().setLevel(options.debuglevel) p = Process(target=run, args=args) processes.append(p) print "Currently running %s scheduler processes" % (len(processes)) From 480dea23adc7d8c0272148a73651aa87a7b332e1 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 21 Sep 2012 22:12:17 -0500 Subject: [PATCH 03/78] moved entropy JS in PasswordWidget but the source should be moved in separate file --- VERSION | 2 +- applications/welcome/views/default/user.html | 90 +------------------- gluon/sqlhtml.py | 90 +++++++++++++++++++- gluon/validators.py | 4 + 4 files changed, 95 insertions(+), 91 deletions(-) diff --git a/VERSION b/VERSION index 486b127c..bf2638f2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:01:45) stable +Version 2.0.9 (2012-09-21 22:12:11) stable diff --git a/applications/welcome/views/default/user.html b/applications/welcome/views/default/user.html index ef00c0e6..47acab1f 100644 --- a/applications/welcome/views/default/user.html +++ b/applications/welcome/views/default/user.html @@ -15,92 +15,4 @@ pass - +//--> diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 5e345f7c..f2382e04 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -433,6 +433,94 @@ class PasswordWidget(FormWidget): DEFAULT_PASSWORD_DISPLAY = 8*('*') + js = """ + function calc_entropy(mystring) { + /*" calculate a simple entropy for a given string "*/ + var lowerset = 'abcdefghijklmnopqrstuvwxyz'; + var upperset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + var numberset = '0123456789'; + var sym1set = '!@#$\%^&*()'; + var sym2set = '~`-_=+[]{}\\|;:\\'",.<>?/'; + var otherset = '0123456789abcdefghijklmnopqrstuvwxyz' + var alphabet = 0; + var other = {}; + var seen = {}; + var lastset = null; + var mystringlist = mystring.split(''); + for (var i=0;i Date: Fri, 21 Sep 2012 22:14:08 -0500 Subject: [PATCH 04/78] fixed share Google+, thanks nicozanf --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bf2638f2..29f9d279 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:12:11) stable +Version 2.0.9 (2012-09-21 22:14:03) stable From e0fc61932d0d1ba259868c9e0cefe07dad418f7b Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 21 Sep 2012 22:23:45 -0500 Subject: [PATCH 05/78] broken long lines in minify --- VERSION | 2 +- gluon/contrib/minify/minify.py | 28 ++++++++++++++++++---------- gluon/globals.py | 3 ++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/VERSION b/VERSION index 29f9d279..43cdc7da 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:14:03) stable +Version 2.0.9 (2012-09-21 22:23:39) stable diff --git a/gluon/contrib/minify/minify.py b/gluon/contrib/minify/minify.py index 012c9611..54aa3784 100644 --- a/gluon/contrib/minify/minify.py +++ b/gluon/contrib/minify/minify.py @@ -60,16 +60,18 @@ def minify(files, path_info, folder, optimize_css, optimize_js, processed = [] for k,filename in enumerate(files): if not filename.startswith('/') or \ - any(filename.endswith(x) for x in ignore_concat): + any(filename.endswith(x) \ + for x in ignore_concat): new_files.append(filename) continue - abs_filename = os.path.join(folder,'static', - filename[len(static_path)+1:]) + abs_filename = os.path.join( + folder,'static', filename[len(static_path)+1:]) if filename.lower().endswith('.css'): processed.append(filename) - spath_info, sfilename = path_info.split('/'), filename.split('/') + spath_info, sfilename = \ + path_info.split('/'), filename.split('/') u = 0 for i,a in enumerate(sfilename): try: @@ -80,7 +82,8 @@ def minify(files, path_info, folder, optimize_css, optimize_js, pass if concat_css: contents = read_binary_file(abs_filename) - replacement = '../'*len(spath_info[u:]) + '/'.join(sfilename[u:-1]) + '/' + replacement = '../'*len(spath_info[u:]) + \ + '/'.join(sfilename[u:-1]) + '/' contents = fix_links(contents, replacement) if minify_css: css.append(cssmin.cssmin(contents)) @@ -91,9 +94,12 @@ def minify(files, path_info, folder, optimize_css, optimize_js, elif filename.lower().endswith('.js'): processed.append(filename) if concat_js: - contents = read_binary_file(abs_filename) - if minify_js and not filename.endswith('.min.js') and \ - not any(filename.endswith(x) for x in ignore_minify): + contents = read_binary_file(abs_filename) + + if minify_js and \ + not filename.endswith('.min.js') and \ + not any(filename.endswith(x) \ + for x in ignore_minify): js.append(jsmin.jsmin(contents)) else: js.append(contents) @@ -104,7 +110,8 @@ def minify(files, path_info, folder, optimize_css, optimize_js, css = '\n\n'.join(contents for contents in css) if not inline_css: temppath = os.path.join(folder,'static',temp) - if not os.path.exists(temppath): os.mkdir(temppath) + if not os.path.exists(temppath): + os.mkdir(temppath) dest = "compressed_%s.css" % dest_key tempfile = os.path.join(temppath, dest) write_binary_file(tempfile,css) @@ -118,7 +125,8 @@ def minify(files, path_info, folder, optimize_css, optimize_js, js = ('js:inline',js) else: temppath = os.path.join(folder,'static',temp) - if not os.path.exists(temppath): os.mkdir(temppath) + if not os.path.exists(temppath): + os.mkdir(temppath) dest = "compressed_%s.js" % dest_key tempfile = os.path.join(folder,'static',temp,dest) write_binary_file(tempfile,js) diff --git a/gluon/globals.py b/gluon/globals.py index ccaab79f..b153ee90 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -241,7 +241,8 @@ class Response(Storage): files = [] for item in self.files: - if not item in files: files.append(item) + if not item in files: + files.append(item) if have_minify and (self.optimize_css or self.optimize_js): # cache for 5 minutes by default key = hashlib.md5(repr(files)).hexdigest() From e4c63769f2ff2585d8a05e73d658ab80052e8de0 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 21 Sep 2012 22:29:55 -0500 Subject: [PATCH 06/78] reverted 4077 because distinct on and groupby are not equivalent. Moreover distinct on is supported only by postgresql because potentially non-deterministic and should be discouraged. Thanks Alexander --- VERSION | 2 +- gluon/dal.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 43cdc7da..2c33c26b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:23:39) stable +Version 2.0.9 (2012-09-21 22:29:49) stable diff --git a/gluon/dal.py b/gluon/dal.py index 857bcf84..4e5c5226 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -1457,8 +1457,6 @@ class BaseAdapter(ConnectionPool): having = args_get('having', False) limitby = args_get('limitby', False) for_update = args_get('for_update', False) - if not distinct is True and not distinct is False and not groupby: - distinct, groupby = False, distinct if self.can_select_for_update is False and for_update is True: raise SyntaxError, 'invalid select attribute: for_update' if distinct is True: From 28b94eceb2dcdc75c8ada223aa55f445ffed4af7 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 21 Sep 2012 22:49:45 -0500 Subject: [PATCH 07/78] formstyle='inline' for forms with single field --- VERSION | 2 +- gluon/sqlhtml.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2c33c26b..3886a680 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:29:49) stable +Version 2.0.9 (2012-09-21 22:49:39) stable diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index f2382e04..efe4a763 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -770,6 +770,16 @@ def formstyle_divs(form, fields): table.append(DIV(_label, _controls, _help, _id=id)) return table +def formstyle_inline(form, fields): + ''' divs only ''' + if len(fields)!=2: + raise RuntimeError, "Not possible" + id, label, controls, help = fields[0] + submit_button = fields[1][2] + return CAT(DIV(controls,_style='display:inline'), + submit_button) + + def formstyle_ul(form, fields): ''' unordered list ''' table = UL() @@ -895,6 +905,7 @@ class SQLFORM(FORM): divs = formstyle_divs, ul = formstyle_ul, bootstrap = formstyle_bootstrap, + inline = formstyle_inline, )) FIELDNAME_REQUEST_DELETE = 'delete_this_record' From 93ce59f65baa89c611560801efbd80d6d145ee7e Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 22 Sep 2012 09:52:08 -0500 Subject: [PATCH 08/78] moved entropy js back to user.html --- VERSION | 2 +- applications/welcome/views/default/user.html | 92 ++++++++++++++++++++ gluon/sqlhtml.py | 90 +------------------ 3 files changed, 94 insertions(+), 90 deletions(-) diff --git a/VERSION b/VERSION index 3886a680..3c256ede 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-21 22:49:39) stable +Version 2.0.9 (2012-09-22 09:52:01) stable diff --git a/applications/welcome/views/default/user.html b/applications/welcome/views/default/user.html index 47acab1f..eb6f9b06 100644 --- a/applications/welcome/views/default/user.html +++ b/applications/welcome/views/default/user.html @@ -15,4 +15,96 @@ pass + diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index efe4a763..e63a909d 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -433,94 +433,6 @@ class PasswordWidget(FormWidget): DEFAULT_PASSWORD_DISPLAY = 8*('*') - js = """ - function calc_entropy(mystring) { - /*" calculate a simple entropy for a given string "*/ - var lowerset = 'abcdefghijklmnopqrstuvwxyz'; - var upperset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - var numberset = '0123456789'; - var sym1set = '!@#$\%^&*()'; - var sym2set = '~`-_=+[]{}\\|;:\\'",.<>?/'; - var otherset = '0123456789abcdefghijklmnopqrstuvwxyz' - var alphabet = 0; - var other = {}; - var seen = {}; - var lastset = null; - var mystringlist = mystring.split(''); - for (var i=0;i Date: Sat, 22 Sep 2012 09:54:53 -0500 Subject: [PATCH 09/78] restored comments in boostrap_css.css --- VERSION | 2 +- .../welcome/static/css/web2py_bootstrap.css | 100 ++++++++---------- 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/VERSION b/VERSION index 3c256ede..be9ea6d2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-22 09:52:01) stable +Version 2.0.9 (2012-09-22 09:54:49) stable diff --git a/applications/welcome/static/css/web2py_bootstrap.css b/applications/welcome/static/css/web2py_bootstrap.css index 36e9bf0e..ad3e8385 100644 --- a/applications/welcome/static/css/web2py_bootstrap.css +++ b/applications/welcome/static/css/web2py_bootstrap.css @@ -1,8 +1,8 @@ -//======================================================= -// CUSTOM RULES -//======================================================= +/*============================================================= + CUSTOM RULES +==============================================================*/ -body{height:auto;} // to avoid vertical scroll bar +body{height:auto;} /* to avoid vertical scroll bar */ div.flash.flash-center{left:25%;right:25%;} div.flash.flash-top,div.flash.flash-top:hover{ position:relative; @@ -36,18 +36,16 @@ div.flash.flash-top,div.flash.flash-top:hover{ font-size:20px; font-weight:300; } -// auth navbar - primitive style +/* auth navbar - primitive style */ .auth_navbar,.auth_navbar a{color:inherit;} -.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); // ie7 doesn't support inherit -} -.auth_navbar a{white-space:nowrap;} // to avoid the nav split on more lines +.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */} +.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */ .auth_navbar a:hover{color:white;text-decoration:none;} ul#navbar>.auth_navbar{ display:inline-block; padding:5px; } - -// form errors message box customization +/* form errors message box customization */ div.error_wrapper{margin-bottom:9px;} div.error{ border-radius: 4px; @@ -55,9 +53,8 @@ div.error{ -moz-border-radius: 4px; -webkit-border-radius: 4px; } - -// below rules are only for formstyle = bootstrap -// trying to make errors look like bootstrap ones +/* below rules are only for formstyle = bootstrap +trying to make errors look like bootstrap ones */ div.controls .error_wrapper{ display:inline-block; margin-bottom:0; @@ -70,46 +67,44 @@ div.controls .error{ border:none; padding:0; margin:0; - //display:inline; // uncommenting this, the animation effect is lost + //display:inline; /* uncommenting this, the animation effect is lost */ } div.controls .inline-help{color:#3A87AD;} div.controls .error_wrapper+.inline-help{margin-left:-99999px;} - -// beautify brand +/* beautify brand */ .navbar-inverse .brand{color:#c6cecc;} .navbar-inverse .brand b{display:inline-block;margin-top:-1px;} .navbar-inverse .brand b>span{font-size:22px;color:white} .navbar-inverse .brand:hover b>span{color:white} -// beautify web2py link in navbar +/* beautify web2py link in navbar */ span.highlighted{color:#d8d800;} .open span.highlighted{color:#ffff00;} -//=========================================================== -// OVERRIDING WEB2PY.CSS RULES -//=========================================================== +/*============================================================= + OVERRIDING WEB2PY.CSS RULES +==============================================================*/ -// reset to default +/* reset to default */ a{white-space:normal;} li{margin-bottom:0;} textarea,button{display:block;} -// reset ul padding +/*reset ul padding */ ul#navbar{padding:0;} -// label aligned to related input +/* label aligned to related input */ td.w2p_fl,td.w2p_fc {padding:0;} #web2py_user_form td{vertical-align:middle;} -//========================================================== -// OVERRIDING BOOTSTRAP.CSS RULES -//========================================================== +/*============================================================= + OVERRIDING BOOTSTRAP.CSS RULES +==============================================================*/ -// because web2py handles this via js +/* because web2py handles this via js */ .hidden{visibility:visible;} - -// right folder for bootstrap black images/icons +/* right folder for bootstrap black images/icons */ [class^="icon-"],[class*=" icon-"]{ background-image:url("../images/glyphicons-halflings.png") } -// right folder for bootstrap white images/icons +/* right folder for bootstrap white images/icons */ .icon-white, .nav-tabs > .active > a > [class^="icon-"], .nav-tabs > .active > a > [class*=" icon-"], @@ -125,20 +120,20 @@ td.w2p_fl,td.w2p_fc {padding:0;} .dropdown-menu > .active > a > [class*=" icon-"] { background-image:url("../images/glyphicons-halflings-white.png"); } -// bootstrap has a label as input's wrapper while web2py has a div +/* bootstrap has a label as input's wrapper while web2py has a div */ div>input[type="radio"],div>input[type="checkbox"]{margin:0;} -// bootstrap has button instead of input +/* bootstrap has button instead of input */ input[type="button"], input[type="submit"]{margin-right:8px;} -//=========================================================== -// SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS -//=========================================================== +/*============================================================= +RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS +==============================================================*/ -// when formstyle=table3cols +/*when formstyle=table3cols*/ tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;} td.w2p_fw div>label{vertical-align:middle;} td.w2p_fc {padding-bottom:5px;} -// when formstyle=divs +/*when formstyle=divs*/ div#auth_user_remember__row{margin-top:4px;} div#auth_user_remember__row>.w2p_fl{display:none;} div#auth_user_remember__row>.w2p_fw{min-height:39px;} @@ -151,8 +146,7 @@ div.w2p_fc{ padding-left:5px; margin-top:-8px; } - -// when formstyle=ul +/*when formstyle=ul*/ form>ul{ list-style:none; margin:0; @@ -160,30 +154,28 @@ form>ul{ li#auth_user_remember__row{margin-top:4px;} li#auth_user_remember__row>.w2p_fl{display:none;} li#auth_user_remember__row>.w2p_fw{min-height:39px;} - -// when formstyle=bootstrap +/*when formstyle=bootstrap*/ #auth_user_remember__row label.checkbox{display:block;} span.inline-help{display:inline-block;} input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;} - -// when recaptcha is used +/*when recaptcha is used*/ #recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;} td>#recaptcha{margin-bottom:6px;} div>#recaptcha{margin-bottom:9px;} -//========================================================== -// OTHER RULES -//========================================================== +/*============================================================= + OTHER RULES +==============================================================*/ .navbar-inner{ - position:relative; // unnecessary + position:relative; /*unnecessary ??*/ } - -// fixed alignment in forms with list:string +/* Massimo Di Pierro fixed alignment in forms with list:string */ form table tr{margin-bottom:9px;} td.w2p_fw ul{margin-left:0px;} -// web2py_console in grid and smartgrid +/* web2py_console in grid and smartgrid */ +.hidden{visibility:visible;} .web2py_console input{ display: inline-block; margin-bottom: 0; @@ -203,12 +195,12 @@ td.w2p_fw ul{margin-left:0px;} margin:3px 0 0 2px; } .web2py_grid form table{width:auto;} -// auth_user_remember checkbox extrapadding in IE fix +/* auth_user_remember checkbox extrapadding in IE fix */ .ie-lte9 input#auth_user_remember.checkbox {padding-left:0;} -//=========================================================== -// MEDIA QUERIES -//=========================================================== +/*============================================================= + MEDIA QUERIES +==============================================================*/ @media only screen and (max-width:979px){ body{padding-top:0px;} From 56acb685e9cfced96d6e659b5f66dae039ee2f96 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 22 Sep 2012 10:11:17 -0500 Subject: [PATCH 10/78] removed some duplication of code in dal.py, thanks Mart --- VERSION | 2 +- applications/welcome/static/css/web2py.css | 4 +- gluon/dal.py | 147 +++------------------ 3 files changed, 23 insertions(+), 130 deletions(-) diff --git a/VERSION b/VERSION index be9ea6d2..039e6b2b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-22 09:54:49) stable +Version 2.0.9 (2012-09-22 10:11:13) stable diff --git a/applications/welcome/static/css/web2py.css b/applications/welcome/static/css/web2py.css index ac04a0f0..1ad43fd0 100644 --- a/applications/welcome/static/css/web2py.css +++ b/applications/welcome/static/css/web2py.css @@ -61,7 +61,7 @@ input[type=text],input[type=password],select{width:300px; margin-right:5px} border-top:1px #DEDEDE solid; } .header { - // background:; + /* background:; */ } @@ -182,7 +182,7 @@ div.error { * will look better with the declarations below * if needed to remove base.css consider keeping these following lines in some css file. */ -// .web2py_table {border:1px solid #ccc} +/* .web2py_table {border:1px solid #ccc} */ .web2py_paginator {} .web2py_grid {width:100%} .web2py_grid table {width:100%} diff --git a/gluon/dal.py b/gluon/dal.py index 4e5c5226..f5c686a9 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -5167,22 +5167,6 @@ class MongoDBAdapter(NoSQLAdapter): items = [self.expand(item, first.type) for item in second] return {self.expand(first) : {"$in" : items} } - def LIKE(self, first, second): - #escaping regex operators? - return {self.expand(first) : ('%s' % self.expand(second, 'string').replace('%','/'))} - - def STARTSWITH(self, first, second): - #escaping regex operators? - return {self.expand(first) : ('/^%s/' % self.expand(second, 'string'))} - - def ENDSWITH(self, first, second): - #escaping regex operators? - return {self.expand(first) : ('/%s^/' % self.expand(second, 'string'))} - - def CONTAINS(self, first, second): - #There is a technical difference, but mongodb doesn't support that, but the result will be the same - return {self.expand(first) : ('/%s/' % self.expand(second, 'string'))} - def EQ(self,first,second): result = {} #if second is None: @@ -5256,41 +5240,30 @@ class MongoDBAdapter(NoSQLAdapter): raise NotImplementedError, "This is not possible in NoSQL, but can be simulated with a wrapper." return '%s ON %s' % (self.expand(first), self.expand(second)) + # + # BLOW ARE TWO IMPLEMENTATIONS OF THE SAME FUNCITONS + # WHICH ONE IS BEST? + # + def COMMA(self, first, second): return '%s, %s' % (self.expand(first), self.expand(second)) - def bulk_insert(self, table, items): - return [self.insert(table,item) for item in items] + def LIKE(self, first, second): + #escaping regex operators? + return {self.expand(first) : ('%s' % self.expand(second, 'string').replace('%','/'))} - #TODO This will probably not work:( - def NOT(self, first): - result = {} - result["$not"] = self.expand(first) - return result + def STARTSWITH(self, first, second): + #escaping regex operators? + return {self.expand(first) : ('/^%s/' % self.expand(second, 'string'))} - def AND(self,first,second): - f = self.expand(first) - s = self.expand(second) - f.update(s) - return f + def ENDSWITH(self, first, second): + #escaping regex operators? + return {self.expand(first) : ('/%s^/' % self.expand(second, 'string'))} - def OR(self,first,second): - # pymongo expects: .find( {'$or' : [{'name':'1'}, {'name':'2'}] } ) - result = {} - f = self.expand(first) - s = self.expand(second) - result['$or'] = [f,s] - return result + def CONTAINS(self, first, second): + #There is a technical difference, but mongodb doesn't support that, but the result will be the same + return {self.expand(first) : ('/%s/' % self.expand(second, 'string'))} - def BELONGS(self, first, second): - if isinstance(second, str): - return {self.expand(first) : {"$in" : [ second[:-1]]} } - elif second==[] or second==(): - return {1:0} - items = [self.expand(item, first.type) for item in second] - return {self.expand(first) : {"$in" : items} } - - #TODO verify full compatibilty with official SQL Like operator def LIKE(self, first, second): import re return {self.expand(first) : {'$regex' : re.escape(self.expand(second, 'string')).replace('%','.*')}} @@ -5314,89 +5287,9 @@ class MongoDBAdapter(NoSQLAdapter): #TODO contains operators need to be transformed to Regex return {self.expand(first) : {' $regex' : ".*" + re.escape(self.expand(second, 'string')) + ".*"}} - def EQ(self,first,second): - result = {} - #if second is None: - #return '(%s == null)' % self.expand(first) - #return '(%s == %s)' % (self.expand(first),self.expand(second,first.type)) - result[self.expand(first)] = self.expand(second) - return result - - def NE(self, first, second=None): - print "in NE" - result = {} - result[self.expand(first)] = {'$ne': self.expand(second)} - return result - - def LT(self,first,second=None): - if second is None: - raise RuntimeError, "Cannot compare %s < None" % first - print "in LT" - result = {} - result[self.expand(first)] = {'$lt': self.expand(second)} - return result - - def LE(self,first,second=None): - if second is None: - raise RuntimeError, "Cannot compare %s <= None" % first - print "in LE" - result = {} - result[self.expand(first)] = {'$lte': self.expand(second)} - return result - - def GT(self,first,second): - print "in GT" - result = {} - result[self.expand(first)] = {'$gt': self.expand(second)} - return result - - def GE(self,first,second=None): - if second is None: - raise RuntimeError, "Cannot compare %s >= None" % first - print "in GE" - result = {} - result[self.expand(first)] = {'$gte': self.expand(second)} - return result - - #TODO javascript has math - def ADD(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '%s + %s' % (self.expand(first), self.expand(second, first.type)) - - #TODO javascript has math - def SUB(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '(%s - %s)' % (self.expand(first), self.expand(second, first.type)) - - #TODO javascript has math - def MUL(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '(%s * %s)' % (self.expand(first), self.expand(second, first.type)) - #TODO javascript has math - - def DIV(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '(%s / %s)' % (self.expand(first), self.expand(second, first.type)) - #TODO javascript has math - def MOD(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '(%s %% %s)' % (self.expand(first), self.expand(second, first.type)) - - #TODO javascript can do this - def AS(self, first, second): - raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry" - return '%s AS %s' % (self.expand(first), second) - - #We could implement an option that simulates a full featured SQL database. But I think the option should be set explicit or implemented as another library. - def ON(self, first, second): - raise NotImplementedError, "This is not possible in NoSQL, but can be simulated with a wrapper." - return '%s ON %s' % (self.expand(first), self.expand(second)) - - #TODO is this used in mongodb? - def COMMA(self, first, second): - return '%s, %s' % (self.expand(first), self.expand(second)) - - + # + # END REDUNDANCY + # class IMAPAdapter(NoSQLAdapter): drivers = ('imaplib',) From 4d6598c645980ed033a8b6dffadc3d14b6037411 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 22 Sep 2012 11:19:14 -0500 Subject: [PATCH 11/78] fixed typo in validators --- VERSION | 2 +- gluon/validators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 039e6b2b..a6b55e7f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-22 10:11:13) stable +Version 2.0.9 (2012-09-22 11:19:10) stable diff --git a/gluon/validators.py b/gluon/validators.py index a105ff56..dbf59fc5 100644 --- a/gluon/validators.py +++ b/gluon/validators.py @@ -512,7 +512,7 @@ class IS_IN_DB(Validator): def count(values, s=self.dbset, f=field): return s(f.belongs(map(int,values))).count() if isinstance(self.dbset.db._adapter, GoogleDatastoreAdapter): - range_ids = range(0,len(ids),30) + range_ids = range(0,len(values),30) total = sum(count(values[i:i+30]) for i in range_ids) if total == len(values): return (values, None) From 69a2e76c3ce39276b21acd62150af24cdacebc96 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 23 Sep 2012 14:07:50 -0500 Subject: [PATCH 12/78] entropy check code in web2py.js, thanks Niphlod --- VERSION | 2 +- applications/admin/static/js/web2py.js | 56 +++++++++--- applications/examples/static/js/web2py.js | 56 +++++++++--- applications/welcome/static/js/web2py.js | 52 ++++++++--- applications/welcome/views/default/user.html | 91 +------------------- gluon/sqlhtml.py | 20 +++-- 6 files changed, 142 insertions(+), 135 deletions(-) diff --git a/VERSION b/VERSION index a6b55e7f..c8c7db93 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-22 11:19:10) stable +Version 2.0.9 (2012-09-23 14:07:45) stable diff --git a/applications/admin/static/js/web2py.js b/applications/admin/static/js/web2py.js index 9a2e208c..e323398a 100644 --- a/applications/admin/static/js/web2py.js +++ b/applications/admin/static/js/web2py.js @@ -39,7 +39,7 @@ function web2py_ajax_init(target) { function web2py_event_handlers() { var doc = jQuery(document) - doc.on('click', '.flash', function(e){jQuery(this).fadeOut('slow'); e.preventDefault();}); + doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();}); doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();}); doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();}); var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?"; @@ -55,7 +55,7 @@ function web2py_event_handlers() { jQuery(function() { var flash = jQuery('.flash'); flash.hide(); - if(flash.html()) flash.slideDown(); + if(flash.html()) flash.append('×').slideDown(); web2py_ajax_init(document); web2py_event_handlers(); }); @@ -67,20 +67,20 @@ function web2py_trap_form(action,target) { form.submit(function(e){ jQuery('.flash').hide().html(''); web2py_ajax_page('post',action,form.serialize(),target); - e.preventDefault(); + e.preventDefault(); }); }); } function web2py_trap_link(target) { jQuery('#'+target+' a.w2p_trap').each(function(i){ - var link=jQuery(this); - link.click(function(e) { - jQuery('.flash').hide().html(''); - web2py_ajax_page('get',link.attr('href'),[],target); - e.preventDefault(); - }); - }); + var link=jQuery(this); + link.click(function(e) { + jQuery('.flash').hide().html(''); + web2py_ajax_page('get',link.attr('href'),[],target); + e.preventDefault(); + }); + }); } function web2py_ajax_page(method, action, data, target) { @@ -101,9 +101,9 @@ function web2py_ajax_page(method, action, data, target) { web2py_trap_link(target); web2py_ajax_init('#'+target); if(command) - eval(decodeURIComponent(command)); + eval(decodeURIComponent(command)); if(flash) - jQuery('.flash').html(decodeURIComponent(flash)).slideDown(); + jQuery('.flash').html(decodeURIComponent(flash)).slideDown(); } }); } @@ -151,7 +151,7 @@ function web2py_component(action, target, timeout, times){ } } else { // run once (no timeout specified) - element.reload_counter = Infinity; + element.reload_counter = Infinity; web2py_ajax_page('get', action, null, target); } }); } @@ -165,3 +165,33 @@ function web2py_comet(url,onmessage,onopen,onclose) { } else return false; // not supported } + +function web2py_calc_entropy(mystring) { + //calculate a simple entropy for a given string + var csets = new Array( + 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/', + '0123456789abcdefghijklmnopqrstuvwxyz'); + var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); + for (var i=0;i×').slideDown(); web2py_ajax_init(document); web2py_event_handlers(); }); @@ -67,20 +67,20 @@ function web2py_trap_form(action,target) { form.submit(function(e){ jQuery('.flash').hide().html(''); web2py_ajax_page('post',action,form.serialize(),target); - e.preventDefault(); + e.preventDefault(); }); }); } function web2py_trap_link(target) { jQuery('#'+target+' a.w2p_trap').each(function(i){ - var link=jQuery(this); - link.click(function(e) { - jQuery('.flash').hide().html(''); - web2py_ajax_page('get',link.attr('href'),[],target); - e.preventDefault(); - }); - }); + var link=jQuery(this); + link.click(function(e) { + jQuery('.flash').hide().html(''); + web2py_ajax_page('get',link.attr('href'),[],target); + e.preventDefault(); + }); + }); } function web2py_ajax_page(method, action, data, target) { @@ -101,9 +101,9 @@ function web2py_ajax_page(method, action, data, target) { web2py_trap_link(target); web2py_ajax_init('#'+target); if(command) - eval(decodeURIComponent(command)); + eval(decodeURIComponent(command)); if(flash) - jQuery('.flash').html(decodeURIComponent(flash)).slideDown(); + jQuery('.flash').html(decodeURIComponent(flash)).slideDown(); } }); } @@ -151,7 +151,7 @@ function web2py_component(action, target, timeout, times){ } } else { // run once (no timeout specified) - element.reload_counter = Infinity; + element.reload_counter = Infinity; web2py_ajax_page('get', action, null, target); } }); } @@ -165,3 +165,33 @@ function web2py_comet(url,onmessage,onopen,onclose) { } else return false; // not supported } + +function web2py_calc_entropy(mystring) { + //calculate a simple entropy for a given string + var csets = new Array( + 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + '0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/', + '0123456789abcdefghijklmnopqrstuvwxyz'); + var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); + for (var i=0;i?/', + '0123456789abcdefghijklmnopqrstuvwxyz'); + var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); + for (var i=0;i - diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index e63a909d..2fbf3c14 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -28,7 +28,7 @@ from dal import DAL, Field, Table, Row, CALLABLETYPES, smart_query, \ from storage import Storage from utils import md5_hash from validators import IS_EMPTY_OR, IS_NOT_EMPTY, IS_LIST_OF, IS_DATE, \ - IS_DATETIME, IS_INT_IN_RANGE, IS_FLOAT_IN_RANGE + IS_DATETIME, IS_INT_IN_RANGE, IS_FLOAT_IN_RANGE, IS_STRONG import datetime import urllib @@ -442,14 +442,23 @@ class PasswordWidget(FormWidget): see also: :meth:`FormWidget.widget` """ - + # detect if attached a IS_STRONG with entropy default=dict( _type='password', _value=(value and cls.DEFAULT_PASSWORD_DISPLAY) or '', ) attr = cls._attributes(field, default, **attributes) + output = CAT(INPUT(**attr)) - return INPUT(**attr) + # deal with entropy check! + requires = field.requires + if not isinstance(requires,(list,tuple)): requires = [requires] + is_strong = [r for r in requires if isinstance(r, IS_STRONG)] + if is_strong: + output.append(SCRIPT("web2py_validate_entropy(jQuery('#%s'),%s);" \ + % (attr['_id'],is_strong[0].entropy))) + # end entropy check + return output class UploadWidget(FormWidget): @@ -2713,8 +2722,3 @@ class ExporterXML(ExportClass): out.write('\n') out.write('') return str(out.getvalue()) - - - - - From 5f647a46b856fa6b1935d0d5b6935a028036ebcc Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 23 Sep 2012 14:37:50 -0500 Subject: [PATCH 13/78] moved layout.js in web2py_bootstrap.js and include_files(extensions=[...]), thanks Jeremy --- VERSION | 2 +- .../welcome/static/js/web2py_bootstrap.js | 23 +++++++++++++++ applications/welcome/views/layout.html | 28 ++----------------- gluon/globals.py | 18 +++++++++--- 4 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 applications/welcome/static/js/web2py_bootstrap.js diff --git a/VERSION b/VERSION index c8c7db93..0b83584a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-23 14:07:45) stable +Version 2.0.9 (2012-09-23 14:37:46) stable diff --git a/applications/welcome/static/js/web2py_bootstrap.js b/applications/welcome/static/js/web2py_bootstrap.js new file mode 100644 index 00000000..8c762296 --- /dev/null +++ b/applications/welcome/static/js/web2py_bootstrap.js @@ -0,0 +1,23 @@ +// this code improves bootstrap menus and adds dropdown support +jQuery(function(){ + jQuery('.nav>li>a').each(function(){ + if(jQuery(this).parent().find('ul').length) + jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append(''); + }); + jQuery('.nav li li').each(function(){ + if(jQuery(this).find('ul').length) + jQuery(this).addClass('dropdown-submenu'); + }); + if(jQuery(document).width()>=980) { + jQuery('ul.nav a.dropdown-toggle').parent().hover(function() { + mi = jQuery(this).addClass('open'); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400); + }, function() { + mi = jQuery(this); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')}); + }); + } + jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');}); + // make all buttons bootstrap buttons + jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn'); +}); diff --git a/applications/welcome/views/layout.html b/applications/welcome/views/layout.html index 19225730..576903c9 100644 --- a/applications/welcome/views/layout.html +++ b/applications/welcome/views/layout.html @@ -39,7 +39,7 @@ - {{ + {{ response.files.append(URL('static','css/web2py.css')) response.files.append(URL('static','css/bootstrap.min.css')) response.files.append(URL('static','css/bootstrap-responsive.min.css')) @@ -146,32 +146,8 @@ - + - + web2py™