py2jquery = local_import('py2jquery') manager = py2jquery.Manager(globals()) ####### ## Load jQuery from a CDN. # Bandwidth is precious, and we're lazy so... # Let the google serve it anyways! ### #Here you have a couple of options # google_load(name, version) will use googles, jsapi to load the javascript, (google_load does not have dependency checking) # require_cdn(name) will directly link to the file on the cdn. (recommended for hosting with google, as google_load causes document.ready issues) # require(name) will download the remote js and host it locally # include(source) will add a script src= (js) or link (css) to the file, either local or remote {{ # Lets use googles loading function. manager.google_load("jquery", "1.3.2") manager.google_load("jqueryui", "1.7.2") # I don't like jsapi, as it creates overhead, and messes with document.ready. # But I still want a cdn to deliver my content! manager.require_cdn("jquery") manager.require_cdn("jquery.ui") # will also include ui-darkness css link hosted on google cdn manager.require_cdn("jquery.ui.theme.darkness") # stylesheet from google cdn # Ok so a cdn is cool, but I have tons of bandwidth, and would like to save google some mula. # I want my own copy of the files. manager.require("jquery") manager.require("jquery.ui") # does not include stylesheet }} #### # So you have dependency checking? ### # So, basically, this is so code gets included in the required order. # jquery.ui will not be linked until jquery is linked. Providing a clear chain of order # You can get away with being explicit, (however it is recommended to be implicit) {{ manager.require("jquery.ui") #this will first include jquery, then jqueryui }} #or {{ manager.require("jquery.rating") #this will include jquery first, but does not depend on jquery.ui manager.require("jquery.ui") # this will not include jquery (already has been included), but will include all of jquery.ui }} # Mix and match it. {{ manager.require_cdn("jquery") manager.require("jquery.ui") # To use jquery.ui locally, you must manually specify # your own themeroller stylesheet with manager.include(URL()) }} ####### ## Load jQuery plugins. # Load supported jQuery plugins and ready them for use # Lets say we want to use the py2jquery rating widget, and we # want to keep it up to date with the latest version, and we want it # to be downloaded to a subfolder (subfolder and upgrade are supported for all require() and require_cdn() ### {{manager.require("jquery.rating", subfolder="js/", upgrade=True)}} ## # Generate our xml. # This can be called as many times as you want. # It is suggested once inside of and then again before the # end of your page just before (just in case you need to render # any javascript from your view!!) {{=manager.xml(False)}} # False means don't minify the output # default - True ###### ## Now that that is out of the way, on to the examples! ### ##################################### # ## Add an event to a dom element # ##################################### # web2py helper def index(): adiv = DIV("Click Me", _id='click_me') # Create a click event # that is bound to adiv # and executes an alert dialog box. # if is_function is True, then the event will be wrapped in a javascript function event = Event("click", adiv, Script(js.alert("Hello World")), is_function=True) ### # Add an event, if you specifiy optional parameter True, it will # include the script in jQuery(document).on_ready() function. manager.add(event, True) return dict(adiv=adiv) ##################################################### def index(): ## # You can pass any Script object to events, however, if an event is to be wrapped in a function # it must be added with manager.add() adiv = DIV("Click Me", _id='click_me') say_hello = Script(alert("Hello World!", is_function=True)) event = Event("click", adiv, say_hello) manager.add(say_hello) # Just add the function, don't call it manager.add(event, True) # Add the event, and bind it on document_ready ##################################################### ##################################### # ## Lets add in some AJAX to get the text from the server! # ##################################### def index(): adiv = DIV("Click Me", _id='click_me') ## To generate the URL you must pass the request object. # the handle can be either a url string or a function reference. # By default the response from the server is eval'd ajax = Call(handle_it, uuid='my_callback', is_function=True, request=request) # Create our confirmation script. # Parameters: message, if_ok, if_cancel # if_ok and if_cancel must be a javascript string or Script object. confirm = Confirm("Are you sure you want to contact the server?", ajax) # Bind our event and call confirm. # Any jquery event can be used. event = Event("click", adiv, confirm) ## It is a good idea to specify a uuid for any Script object. # This will allow each script to be unique when wrapped with a function. # This also allows for multiple subscriptions, such as two click events # on the same DOM element. manager.add(ajax) manager.add(event, True) # Notice, you don't need to add the Script if it is not a function. return dict(adiv=adiv) def handle_it(): # Using a JavaScript generator, return the alert. return alert("Hello World From web2py!") ##################################### # ## What about a timer that bugs you until you click the text!? # ##################################### def index(): adiv = DIV("Click Me to stop the nagging!", _id='click_me') nag = Script(alert("Hey Bud, How ya doin?")) # Timers are really simple. # Call a Script object at each timout # timeout is in ms. nag_timer = Interval(nag, 10000) # Delay timers work the same! # nag_timer = Delay(nag, 10000) # They only run once. # You can even access the timers javascript variable id # if you need to js_variable_name = nag_timer.var.timer_id # You can also set the timeout later!! nag_timer.var.timer_id.value = 15000 # So now lets stop the timer! stop_it = StopTimer(nag_timer) # default event is click # I am currently working on a way to # wrap two scripts so the event would call them both. # So you could call stop_it and display a message saying I'll stop event = Event(event_obj=adiv, call=stop_it, rebind=True) # if you specify rebind=True, event will use jQuery.live instead of jQuery.bind # So now we add our scripts to the page manager.add(nag_timer, True) # Start when page loads manager.add(event, True) return dict(adiv=adiv) ##################################### # ## What about jqueryui! ## This is in progress to pythonify jqueryui! ## dialogs will work like this in future # # Dialog(title="Hello", content=DIV("world"), etc...) # ##################################### def index(): adiv = DIV("CLICK ME", _id='click_me') call = Call(handle_it, request=request, is_function=True) event = Event("click", a, call, is_function=True) manager.add(call) manager.add(event, True) return dict(adiv=adiv) def handle_it(): return 'jQuery("#click_me").append("
");' + \ 'jQuery("#dialog").html("%s");' % str(request.now) + \ 'jQuery("#dialog").dialog({ title: "Server Time"});' ##################################### ##################################### # ## What about star ratings!???? ## Easy! With jquery.rating # (customly made for py2jquery, mainly for easy ajax/callback integration)! # since jquery.ui.rating does not have good ajax support with multiple widgets and database bindings. # Downgrade to if javascript is disabled is in progress. ##################################### ###### ## Use star rating widget with FORM ### # in db.py db.define_table("comments", Field("name", "string"), Field("rating", "integer"), Field("content", "text"),) db.comments.rating.requires = IS_IN_SET(range(0,5)) db.comments.rating.label = "Please rate the quality of this site on a scale of 1-5" db.comments.content.label = "Please let us know how we could improve this website" # and the moment of truth db.comments.rating.widget = Rating.form_widget # Now, any FORM created with the database will display the Rating widget, its as easy as that! # Try it out on appadmin or on custom forms! def index(): form = SQLFORM(db.comments) if form.accepts(request.vars, session): response.flash = "Thanks!" else: response.flash = "Welcome!" return dict(form=form) ###### ## That was easy... But I have multiple objects on one page that I want rated, using their db.id ### # Our model db.define_table("blog_post", Field("title"), Field("content", "text")) db.define_table("post_ratings", Field("id_blog_post", db.blog_post), Field("score", "integer")) db.post_ratings.score.requires = IS_IN_SET(range(0,5)) # We also need the average for our ratings # Hopefully .avg() functions will be implemented in the DAL soon. def avg_post_rating(id_blog_post): ratings = db(db.blog_post.id == id_blog_post).select() total = count = average = 0 for rating in ratings: total += rating.score count += 1 if count == 0: average = -1 else: average = total / count return average # in db.py (or other model) # Declare a rating widget set, that will make ajax calls to a function # Args that will be passed to the function are /dbid/value/ where dbid is unique for that widget and value is the star clicked on. rating = Rating(manager, URL(r=request, c='default', f='record_rating')) ### If you want to disable events (rollovers/click/etc) # on this set of rating widgets # set disabled=True rating = Rating(manager, _class='diabled-rating-widgets', disabled=True) # In our controller # ex: default.py # This function must return an integer representing the new value score of the rating widget. def record_rating(): dbid = int(request.args(0)) or None value = int(request.args(1)) or None if not value or not dbid: return 0 try: db.post_ratings.insert(id_blog_post=dbid, score=value) except: pass return avg_post_rating(dbid) ###### ## Whew, ok setup is out of the way! ## Now how do I render my widgets!? ### # Example: # If value is 0, no stars will display, if dbid is None, it will not make an ajax callback. # >>> xml = rating.widget(value=3, number=5, dbid=None) def index(): posts = db(db.blog_post.id > 0).select() return dict(posts=posts) # And in our view {{for post in posts:}}
  • {{=post.title}}
  • {{=XML(rating.widget(value=avg_post_rating(post.id), number=5, dbid=post.id))}}
  • {{=post.content}}
  • # Wow... makes rating easy with web2py! # Download test welcome app: # Does not exist yet. # http://thadeusb.com/code/py2jquery.welcome.w2p ##################################### # ## MORE TO COME! ## I am working on this every day, and am open ## to suggestions and patches! # #####################################