Posted By

morningcatmedia on 09/10/10


Tagged

ajax google app


Versions (?)

Google App Ajax Post Comment


 / Published in: Python
 

  1. # Four files
  2. # app.yaml
  3. # Index.html
  4. # Base.html
  5. # helloworld.py
  6.  
  7.  
  8. # app.yaml
  9. application: helloworld
  10.  
  11. version: 1
  12.  
  13. runtime: python
  14.  
  15. api_version: 1
  16.  
  17.  
  18.  
  19. handlers:
  20. - url: /static
  21. static_dir: static
  22.  
  23.  
  24. - url: /stylesheets
  25.  
  26. static_dir: stylesheets
  27.  
  28.  
  29.  
  30. - url: /.*
  31.  
  32. script: helloworld.py
  33.  
  34. # Index.html This is the Django template
  35. {% extends "base.html" %}
  36.  
  37. {% block main %}
  38. <div><input type="submit" onclick="onAddSuccess()" value="List Guestbook"></div>
  39.  
  40. {% endblock %}
  41.  
  42.  
  43. {% block form %}
  44. {% if logged %}
  45.  
  46. <form action="/sign" enctype="multipart/form-data" method="post">
  47. <div><textarea id="content" name="content" rows="3" cols="60"></textarea></div>
  48.  
  49. {% for type_val in type %}
  50.  
  51. <div><input type="radio" name="type" value="{{type_val}}">{{type_val}}</div>
  52.  
  53. {% endfor %}
  54. <input type="file" name="img" id="img" >
  55. <div><input type="submit" value="Sign Guestbook"></div>
  56. </form>
  57. {% endif %}
  58. <a href="{{ url }}">{{ url_linktext }}</a>
  59. {% endblock %}
  60.  
  61. ######################################
  62. # Below is base.html
  63. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  64.  
  65. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  66.  
  67.  
  68.  
  69.  
  70.  
  71. <html>
  72.  
  73. <head>
  74.  
  75. <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
  76.  
  77. <script type="text/javascript" src="./static/json.js"></script>
  78.  
  79. <script type="text/javascript">
  80.  
  81.  
  82.  
  83. //
  84.  
  85. // As mentioned at http://en.wikipedia.org/wiki/XMLHttpRequest
  86.  
  87. //
  88.  
  89. if( !window.XMLHttpRequest ) XMLHttpRequest = function()
  90.  
  91. {
  92.  
  93. try{ return new ActiveXObject("Msxml2.XMLHTTP.6.0") }catch(e){}
  94.  
  95. try{ return new ActiveXObject("Msxml2.XMLHTTP.3.0") }catch(e){}
  96.  
  97. try{ return new ActiveXObject("Msxml2.XMLHTTP") }catch(e){}
  98.  
  99. try{ return new ActiveXObject("Microsoft.XMLHTTP") }catch(e){}
  100.  
  101. throw new Error("Could not find an XMLHttpRequest alternative.")
  102.  
  103. };
  104.  
  105.  
  106.  
  107. //
  108.  
  109. // Makes an AJAX request to a local server function w/ optional arguments
  110.  
  111. //
  112.  
  113. // functionName: the name of the server's AJAX function to call
  114.  
  115. // opt_argv: an Array of arguments for the AJAX function
  116.  
  117. //
  118.  
  119.  
  120.  
  121. function GetRequest(function_name, opt_argv) {
  122.  
  123. // If optional arguments was not provided, create it as empty
  124.  
  125. if (!opt_argv)
  126.  
  127. opt_argv = new Array();
  128.  
  129.  
  130.  
  131. // Find if the last arg is a callback function; save it
  132.  
  133. var callback = null;
  134.  
  135. var len = opt_argv.length;
  136.  
  137. if (len > 0 && typeof opt_argv[len-1] == 'function') {
  138.  
  139. callback = opt_argv[len-1];
  140.  
  141. opt_argv.length--;
  142.  
  143. }
  144.  
  145. var async = (callback != null);
  146.  
  147.  
  148.  
  149. // Encode the arguments in to a URI
  150.  
  151. var query = 'action=' + encodeURIComponent(function_name);
  152.  
  153. for (var i = 0; i < opt_argv.length; i++) {
  154.  
  155. var key = 'arg' + i;
  156.  
  157. var val = JSON.stringify(opt_argv[i]);
  158.  
  159. query += '&' + key + '=' + encodeURIComponent(val);
  160.  
  161. }
  162.  
  163. query += '&time=' + new Date().getTime(); // IE cache workaround
  164.  
  165.  
  166.  
  167. // See http://en.wikipedia.org/wiki/XMLHttpRequest to make this cross-browser compatible
  168.  
  169. var req = new XMLHttpRequest();
  170.  
  171.  
  172.  
  173. // Create a 'GET' request w/ an optional callback handler
  174.  
  175. req.open('GET', '/list?' + query, async);
  176.  
  177. //req.open('GET', '/list', async);
  178.  
  179.  
  180.  
  181. if (async) {
  182.  
  183. req.onreadystatechange = function() {
  184.  
  185. if(req.readyState == 4 && req.status == 200) {
  186.  
  187. var response = null;
  188.  
  189. try {
  190.  
  191. response = JSON.parse(req.responseText);
  192.  
  193. } catch (e) {
  194.  
  195. response = req.responseText;
  196.  
  197. }
  198.  
  199. callback(response);
  200.  
  201. }
  202.  
  203. }
  204.  
  205. }
  206.  
  207.  
  208.  
  209. // Make the actual request
  210.  
  211. req.send(null);
  212.  
  213. }
  214.  
  215.  
  216.  
  217. function PostRequest(function_name, opt_argv) {
  218.  
  219.  
  220.  
  221. if (!opt_argv)
  222.  
  223. opt_argv = new Array();
  224.  
  225.  
  226.  
  227. // Find if the last arg is a callback function; save it
  228.  
  229. var callback = null;
  230.  
  231. var len = opt_argv.length;
  232.  
  233. if (len > 0 && typeof opt_argv[len-1] == 'function') {
  234.  
  235. callback = opt_argv[len-1];
  236.  
  237. opt_argv.length--;
  238.  
  239. }
  240.  
  241. var async = (callback != null);
  242.  
  243.  
  244.  
  245. // Build an Array of parameters, w/ function_name being the first parameter
  246.  
  247. var params = new Array(function_name);
  248.  
  249. for (var i = 0; i < opt_argv.length; i++) {
  250.  
  251. params.push(opt_argv[i]);
  252.  
  253. }
  254.  
  255. var body = JSON.stringify(params);
  256.  
  257.  
  258.  
  259. // Create an XMLHttpRequest 'POST' request w/ an optional callback handler
  260.  
  261. var req = new XMLHttpRequest();
  262.  
  263.  
  264.  
  265. req.open('POST', '/rpc', async);
  266.  
  267.  
  268.  
  269. req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  270.  
  271. req.setRequestHeader("Content-length", body.length);
  272.  
  273. req.setRequestHeader("Connection", "close");
  274.  
  275.  
  276.  
  277. if (async) {
  278.  
  279. req.onreadystatechange = function() {
  280.  
  281. if(req.readyState == 4 && req.status == 200) {
  282.  
  283. var response = null;
  284.  
  285. try {
  286.  
  287. response = JSON.parse(req.responseText);
  288.  
  289. } catch (e) {
  290.  
  291. response = req.responseText;
  292.  
  293. }
  294.  
  295. callback(response);
  296.  
  297. }
  298.  
  299. }
  300.  
  301. }
  302.  
  303.  
  304.  
  305. // Make the actual request
  306.  
  307. req.send(body);
  308.  
  309.  
  310.  
  311. }
  312.  
  313.  
  314.  
  315. // Adds a stub function that will pass the arguments to the AJAX call
  316.  
  317. function InstallPostFunction(obj, functionName) {
  318.  
  319. obj[functionName] = function() { PostRequest(functionName, arguments); }
  320.  
  321. }
  322.  
  323.  
  324.  
  325. // Adds a stub function that will pass the arguments to the AJAX call
  326.  
  327. function InstallGetFunction(obj, functionName) {
  328.  
  329. obj[functionName] = function() { GetRequest(functionName, arguments); }
  330.  
  331. }
  332.  
  333.  
  334.  
  335.  
  336.  
  337. </script>
  338.  
  339. <script type="text/javascript">
  340.  
  341.  
  342.  
  343. // Server object that will contain the callable methods
  344.  
  345. var server = {};
  346.  
  347. var newsrv = {};
  348.  
  349. // Insert 'Add' as the name of a callable method
  350.  
  351. // Add will add the record to the database
  352.  
  353. InstallPostFunction(server, 'Add');
  354.  
  355. InstallGetFunction(newsrv, 'list');
  356.  
  357.  
  358.  
  359. // Handy "macro"
  360.  
  361. function $(id){
  362.  
  363. return document.getElementById(id);
  364.  
  365. }
  366.  
  367.  
  368.  
  369. // Client function that calls a server rpc and provides a callback
  370.  
  371. // For this application, doAdd will Post the entry
  372.  
  373.  
  374.  
  375. function doAdd() {
  376.  
  377. server.Add($('content').value, $('img').value, onAddSuccess);
  378.  
  379. }
  380.  
  381.  
  382.  
  383. // Callback for after a successful doAdd
  384.  
  385. function onAddSuccess() {
  386.  
  387. newsrv.list($('content').value, $('img').value,onGetSuccess);
  388.  
  389. }
  390.  
  391.  
  392.  
  393. function onGetSuccess(newresponse) {
  394.  
  395. document.getElementById('result').innerHTML = newresponse;
  396.  
  397. }
  398.  
  399. </script>
  400.  
  401. </head>
  402.  
  403. <body onLoad="onAddSuccess()">
  404.  
  405.  
  406.  
  407. <div>
  408.  
  409. {% block form %}
  410.  
  411. {% endblock %}
  412.  
  413. </div>
  414.  
  415. <div>
  416.  
  417. {% block main %}
  418.  
  419. {% endblock %}
  420.  
  421. </div>
  422.  
  423.  
  424. <div id="result">
  425.  
  426.  
  427.  
  428. </div>
  429.  
  430.  
  431.  
  432.  
  433.  
  434. </body>
  435.  
  436. </html>
  437.  
  438. ######################################
  439. # Below is helloworld.py
  440. import cgi
  441.  
  442. import os
  443.  
  444. import datetime
  445.  
  446. import logging
  447.  
  448.  
  449.  
  450. from google.appengine.api import users
  451.  
  452. from google.appengine.ext import webapp
  453.  
  454. from google.appengine.ext.webapp.util import run_wsgi_app
  455.  
  456. from google.appengine.ext import db
  457.  
  458. from google.appengine.ext.webapp import template
  459.  
  460. from google.appengine.api import images
  461.  
  462. from google.appengine.api import memcache
  463.  
  464. from django.utils import simplejson
  465.  
  466.  
  467.  
  468. class Greeting(db.Model):
  469.  
  470. author = db.UserProperty()
  471.  
  472. content = db.StringProperty(multiline=True)
  473.  
  474. date = db.DateTimeProperty(auto_now_add=True)
  475.  
  476. type = db.StringProperty(indexed=False)
  477.  
  478. avatar = db.BlobProperty(default=None)
  479.  
  480. usremail = db.EmailProperty()
  481.  
  482.  
  483.  
  484. class MainPage(webapp.RequestHandler):
  485.  
  486. def get(self):
  487.  
  488. self.render_form()
  489.  
  490. stats = memcache.get_stats()
  491.  
  492.  
  493.  
  494. #self.response.out.write("<b>Cache Hits:%s</b><br>" % stats['hits'])
  495.  
  496. #self.response.out.write("<b>Cache Misses:%s</b><br><br>" % stats['misses'])
  497.  
  498.  
  499.  
  500.  
  501.  
  502. def render_form(self):
  503.  
  504. greetings_query = Greeting.all().order('-date')
  505.  
  506. #greetings_query=db.GqlQuery("SELECT * FROM Greeting WHERE content >= :1 AND content < :2", "ccc", u"abc" + u"\ufffd")
  507.  
  508. greetings = greetings_query.fetch(10)
  509.  
  510. type = set(["cat", "dog", "bird"])
  511.  
  512. logged = False
  513.  
  514.  
  515.  
  516. if users.get_current_user():
  517.  
  518. logged = True
  519.  
  520. url = users.create_logout_url(self.request.uri)
  521.  
  522. url_linktext = 'Logout'
  523.  
  524. else:
  525.  
  526. logged = False
  527.  
  528. url = users.create_login_url(self.request.uri)
  529.  
  530. url_linktext = 'Login to comment'
  531.  
  532.  
  533.  
  534. template_values = {
  535.  
  536. 'greetings': greetings,
  537.  
  538. 'url': url,
  539.  
  540. 'url_linktext': url_linktext,
  541.  
  542. 'logged': logged,
  543.  
  544. }
  545.  
  546.  
  547.  
  548. path = os.path.join(os.path.dirname(__file__), 'index.html')
  549.  
  550. self.response.out.write(template.render(path, template_values))
  551.  
  552.  
  553.  
  554.  
  555.  
  556. class Guestbook(webapp.RequestHandler):
  557.  
  558. def post(self, *args):
  559.  
  560. greeting = Greeting()
  561.  
  562.  
  563.  
  564. if users.get_current_user():
  565.  
  566. greeting.author = users.get_current_user()
  567.  
  568.  
  569.  
  570. greeting.content = self.request.get('content')
  571.  
  572. greeting.type = self.request.get('type')
  573.  
  574.  
  575.  
  576. if self.request.get('img'):
  577.  
  578. picture = self.request.get('img')
  579.  
  580. avatar = images.resize(self.request.get("img"), 32, 32)
  581.  
  582. greeting.avatar = db.Blob(avatar)
  583.  
  584. greeting.put()
  585.  
  586. self.redirect('/')
  587.  
  588.  
  589.  
  590. def get(self):
  591. # Here we need to put the memcache call
  592. # greetings = memcache.get("greetings")
  593. # if greetings is not None:
  594. # return greetings
  595. # else:
  596.  
  597. greetings_query = Greeting.all().order('-date')
  598.  
  599. #greetings_query=db.GqlQuery("SELECT * FROM Greeting WHERE content >= :1 AND content < :2", "ccc", u"abc" + u"\ufffd")
  600.  
  601. greetings = greetings_query.fetch(10)
  602.  
  603. logged = False
  604.  
  605.  
  606.  
  607. if users.get_current_user():
  608.  
  609. logged = True
  610.  
  611. url = users.create_logout_url(self.request.uri)
  612.  
  613. url_linktext = 'Logout'
  614.  
  615. else:
  616.  
  617. logged = False
  618.  
  619. url = users.create_login_url(self.request.uri)
  620.  
  621. url_linktext = 'Login to comment'
  622.  
  623.  
  624.  
  625. for greeting in greetings:
  626.  
  627. self.response.out.write("<p>")
  628.  
  629. self.response.out.write(greeting.content)
  630.  
  631. #self.response.out.write(greeting.avatar)
  632.  
  633. self.response.out.write('<img src=http://localhost:8080/img?img_id='+str(greeting.key())+' </img>')
  634.  
  635. self.response.out.write("</p>")
  636.  
  637.  
  638.  
  639. class Image (webapp.RequestHandler):
  640.  
  641. def get(self):
  642.  
  643. greeting = db.get(self.request.get("img_id"))
  644.  
  645. if greeting.avatar:
  646.  
  647. self.response.headers['Content-Type'] = "image/png"
  648.  
  649. self.response.out.write(greeting.avatar)
  650.  
  651. else:
  652.  
  653. self.response.out.write("No image")
  654.  
  655.  
  656.  
  657.  
  658.  
  659. #RPC Functions
  660.  
  661.  
  662.  
  663. class RPCHandler(webapp.RequestHandler):
  664.  
  665. """ Allows the functions defined in the RPCMethods class to be RPCed."""
  666.  
  667. def __init__(self):
  668.  
  669. webapp.RequestHandler.__init__(self)
  670.  
  671. self.methods = RPCMethods()
  672.  
  673.  
  674.  
  675. def post(self, *args):
  676.  
  677. args = simplejson.loads(self.request.body)
  678.  
  679. func, args = args[0], args[1:]
  680.  
  681.  
  682.  
  683. if func[0] == '_':
  684.  
  685. self.error(403) # access denied
  686.  
  687. return
  688.  
  689.  
  690.  
  691. func = getattr(self.methods, func, None)
  692.  
  693. if not func:
  694.  
  695. self.error(404) # file not found
  696.  
  697. return
  698.  
  699.  
  700.  
  701. result = func(*args)
  702.  
  703. self.response.out.write(simplejson.dumps(result))
  704.  
  705.  
  706.  
  707. def get(self):
  708.  
  709. func = None
  710.  
  711.  
  712.  
  713. action = self.request.get('action')
  714.  
  715. if action:
  716.  
  717. if action[0] == '_':
  718.  
  719. self.error(403) # access denied
  720.  
  721. return
  722.  
  723. else:
  724.  
  725. func = getattr(self.methods, action, None)
  726.  
  727.  
  728.  
  729. if not func:
  730.  
  731. self.error(404) # file not found
  732.  
  733. return
  734.  
  735.  
  736.  
  737. args = ()
  738.  
  739. while True:
  740.  
  741. key = 'arg%d' % len(args)
  742.  
  743. val = self.request.get(key)
  744.  
  745. if val:
  746.  
  747. args += (simplejson.loads(val),)
  748.  
  749. else:
  750.  
  751. break
  752.  
  753. result = func(*args)
  754.  
  755. self.response.out.write(simplejson.dumps(result))
  756.  
  757.  
  758.  
  759.  
  760.  
  761. class RPCMethods():
  762.  
  763. """ Defines the methods that can be RPCed.
  764.  
  765. NOTE: Do not allow remote callers access to private/protected "_*" methods.
  766.  
  767. """
  768.  
  769.  
  770.  
  771. def Add(self, *args):
  772.  
  773. greeting = Greeting()
  774.  
  775. greeting.content = args[0]
  776.  
  777. #Can't do this since I need upload the image via ajax, and that's not allowed.
  778.  
  779. #greeting.avatar = args[1]
  780.  
  781.  
  782.  
  783. greeting.put()
  784.  
  785.  
  786.  
  787. return True
  788.  
  789.  
  790.  
  791. #**********
  792.  
  793.  
  794.  
  795.  
  796.  
  797. def main():
  798.  
  799. application = webapp.WSGIApplication(
  800.  
  801. [('/', MainPage),
  802.  
  803. ('/img',Image),
  804.  
  805. ('/rpc', RPCHandler),
  806.  
  807. ('/list',Guestbook),
  808.  
  809. ('/sign',Guestbook),
  810.  
  811. ],
  812.  
  813. debug=True)
  814.  
  815. run_wsgi_app(application)
  816.  
  817.  
  818.  
  819. if __name__ == "__main__":
  820.  
  821. main()

Report this snippet  

You need to login to post a comment.