Commits

Wojciech Walczak  committed baee82c Merge

Add basic JQuery code for adding/displaying comments

  • Participants
  • Parent commits 2e04fbd, edec5eb

Comments (0)

Files changed (6)

File doc/ext/autosummary.rst

 
 .. note::
    
-   You can use the :dir:`autosummary` directive in the stub pages.  However,
-   stub pages are not generated automatically recursively.
+   You can use the :dir:`autosummary` directive in the stub pages.
+   Stub pages are generated also based on these directives.

File sphinx/builders/webapp/templates/html/comments.html

-<a name="comments" href="#" id="1">XXX</a>
+<!--<a name="comment_{{ paragraph_id }}" href="#" id="{{ paragraph_id }}">XXX</a>-->
+<span name="paragraph" value="{{ paragraph_id }}"></span>
 </p>
-<div class="x1" style="display: none;">
-   <br />[comments]<br /><br />
-  <form id="commentForm" action="add_comment" method="post"> 
+<div class="x{{ paragraph_id }}" style="display: none;">
+   <br />
 
+   <div class="comments_for_{{ paragraph_id }}">
+
+   </div>
+
+   <br /><br />
+   <form id="commentForm" action="add_comment" method="post"> 
+     <input name="paragraph_id" value="{{ paragraph_id }}" style="display: none;">
      Name: <input type="text" name="name" /><br />
      E-mail: <input type="text" name="email" /><br />
      WWW: <input type="text" name="www" /><br />
         </select>
         <br />
         Paragraph: <textarea name="paragraph"></textarea><br />
-        I agree to publish my fix on a license X: <input type="checkbox" value="1"> 
+        I agree to publish my fix on a license X: <input type="checkbox" name="licence" value="1"> 
         <br />
      </div>
      <br>

File sphinx/builders/webapp/webapp.py

 import cPickle
 from os import path
 
+from hashlib import md5
+
 from sphinx.builders.html import SerializingHTMLBuilder
 from sphinx.errors import SphinxError
 from sphinx.writers.html import HTMLTranslator
         Copy the files (defined in 'files' tuple) from sphinx/webapp/templates/
         to self.outdir.
         """
+        dirs = ('html', 'comments', 'diffs')
         files = ('server.py', 'html/openid.html')
         templates_dir = path.join(path.dirname(__file__), 'templates')
-        os.mkdir(path.join(self.outdir, 'html'))
+
+        for d in dirs:
+            try:
+                os.mkdir(path.join(self.outdir, d))
+            except Exception, err:
+                raise SphinxError(err)
+
         for f in files:
-            afile = path.join(templates_dir, f)
-            shutil.copyfile(afile, path.join(self.outdir, f))
+            try:
+                afile = path.join(templates_dir, f)
+                shutil.copyfile(afile, path.join(self.outdir, f))
+            except Exception, err:
+                raise SphinxError(err)
 
         src_dir = path.join(path.dirname(__file__), '../../themes/basic/static')
         dst_dir = path.join(self.outdir, 'public/_static')
     def depart_paragraph(self, node):
         comm_template = self.templ_env.get_template('comments.html')
         HTMLTranslator.depart_paragraph(self, node)
+        body = ''.join(self.body)
+        md5sum = md5(body.encode('utf8')).hexdigest()
         if not self.should_be_compact_paragraph(node):
-           self.body.append(comm_template.render({}))
+           self.body.append(comm_template.render({ 'paragraph_id': md5sum }))

File sphinx/ext/autosummary/generate.py

     # remove possible duplicates
     items = dict([(item, True) for item in items]).keys()
 
+    # keep track of new files
+    new_files = []
+
     # write
     for name, path, template_name in sorted(items):
         if path is None:
         if os.path.isfile(fn):
             continue
 
+        new_files.append(fn)
+
         f = open(fn, 'w')
 
         try:
                           if x in include_public or not x.startswith('_')]
                 return public, items
 
-            info = {}
+            ns = {}
 
             if doc.objtype == 'module':
-                info['members'] = dir(obj)
-                info['functions'], info['all_functions'] = \
+                ns['members'] = dir(obj)
+                ns['functions'], ns['all_functions'] = \
                                    get_members(obj, 'function')
-                info['classes'], info['all_classes'] = \
+                ns['classes'], ns['all_classes'] = \
                                  get_members(obj, 'class')
-                info['exceptions'], info['all_exceptions'] = \
+                ns['exceptions'], ns['all_exceptions'] = \
                                    get_members(obj, 'exception')
             elif doc.objtype == 'class':
-                info['members'] = dir(obj)
-                info['methods'], info['all_methods'] = \
+                ns['members'] = dir(obj)
+                ns['methods'], ns['all_methods'] = \
                                  get_members(obj, 'method', ['__init__'])
-                info['attributes'], info['all_attributes'] = \
+                ns['attributes'], ns['all_attributes'] = \
                                  get_members(obj, 'attribute')
 
             parts = name.split('.')
                 mod_name = '.'.join(parts[:-2])
                 cls_name = parts[-2]
                 obj_name = '.'.join(parts[-2:])
-                info['class'] = cls_name
+                ns['class'] = cls_name
             else:
                 mod_name, obj_name = '.'.join(parts[:-1]), parts[-1]
 
-            info['fullname'] = name
-            info['module'] = mod_name
-            info['objname'] = obj_name
-            info['name'] = parts[-1]
+            ns['fullname'] = name
+            ns['module'] = mod_name
+            ns['objname'] = obj_name
+            ns['name'] = parts[-1]
 
-            info['objtype'] = doc.objtype
-            info['underline'] = len(name) * '='
+            ns['objtype'] = doc.objtype
+            ns['underline'] = len(name) * '='
 
-            rendered = template.render(**info)
+            rendered = template.render(**ns)
             f.write(rendered)
         finally:
             f.close()
 
+    # descend recursively to new files
+    if new_files:
+        generate_autosummary_docs(new_files, output_dir=output_dir,
+                                  suffix=suffix, warn=warn, info=info,
+                                  base_path=base_path, builder=builder,
+                                  template_dir=template_dir)
+
 
 # -- Finding documented entries in files ---------------------------------------
 

File sphinx/themes/basic/static/comments.js

+
+function check_for_comments(id) {
+   var c_path = location.protocol + "//" + location.host + "/comments/" + id;
+   $.getJSON(c_path, function(data) {
+      if(data.length>0) {
+         $("span[value*=" + id + "]").append('<a name="comment_'
+                                             + id
+                                             + '" href="#" id="'
+                                             + id
+                                             + '">'
+                                             + data.length
+                                             + ' comments</a>');
+      }
+   });
+}
+
+function load_comments(id) {
+   var c_path = location.protocol + "//" + location.host + "/comments/" + id;
+   $.getJSON(c_path, function(data) {
+       for(i=0; i<data.length; i++) {
+          $('div[class*=comments_for_' + id + ']').append(
+             "<div style='background-color: lightgreen; border: solid 1px red;'>"+
+             "Name: <a href='" + data[i].url + "'>" + data[i].name + "</a>" +
+             "<br />" +
+             "Comment: <br>" +
+             data[i].comment +
+             "</div><br>");
+       }
+   });
+}
+
+
 $(document).ready(function() {
+   $("span[name*=paragraph]").each(function() {
+      var id = $(this).attr("value");
+      var comments = check_for_comments(id);
+      if(comments === undefined) {
+         $("span[value*=" + id + "]").append('<a name="comment_' + id + '" href="#" id="' + id + '">No comments</a>');
+      }
+   });
+
    // show/hide the comments/post form on the page
-   $("a[name*=comments]").click(function(){
+   $("a[name*=comment_]").click(function() {
        $('showhide,div.x'+this.id).toggle();
+       // load comments for paragraph only if an appropriate div is visible
+       var isVisible = $('div.x'+this.id).is(':visible');
+       if(isVisible) {
+          load_comments(this.id);
+       }
    });
 });
 
 $(document).ready(function() { 
-   // bind 'myForm' and provide a simple callback function 
-   $('#myForm').ajaxForm(function() { 
-     alert("Thank you for your comment!"); 
+   // bind 'commentForm' and provide a simple callback function 
+   $('#commentForm').ajaxForm(function() { 
+     var cid = $('input[name*=paragraph_id]').attr("value");
+     load_comments(cid);
    }); 
 }); 
 

File sphinx/web/middleware/appserver.py

     :license: BSD, see LICENSE for details.
 """
 
+import json
+import cPickle
+from hashlib import md5
 import locale
 from os import path
-from cPickle import loads
 
 from jinja2 import Environment, FileSystemLoader, Template
 from webob import Request, Response
 
 from sphinx.application import TemplateBridge
+from sphinx.errors import SphinxError
 from sphinx.theming import Theme
 
 # it's here only temporarily, until I get all the theming problems resolved
 </html>
 """
 
+def load_comments(paragraph_id):
+    try:
+        w = open('comments/%s' % (paragraph_id), 'rb')
+        data = json.load(w)
+        w.close()
+    except Exception, err:
+        return 'No comments yet.'
+    return data
+    
+
+def save_comments(paragraph_id, data):
+    try:
+        w = open('comments/%s' % (paragraph_id), 'wb')
+        json.dump(data, w)
+        w.close()
+    except Exception, err:
+        raise SphinxError(err)
+
+
 class AppServer(object):
-    def __init__(self, www_dir, theme):
+    def __init__(self, www_dir='public/', theme=None):
         self.env = None
         self.www_dir = www_dir
         self.template_vals = {}
         resp = Response(content_type='text/html', charset='utf8')
         resp.status = 404
 
-        if req.path == '/':
-            rel_file = 'index.html'
-        else:
-            rel_file = req.path[1:]
-
-        # HTML files are being kept as '.pkl' files
-        if rel_file.endswith('.html'):
-            rel_file = rel_file.strip('.html') + '.pkl'
-
-        # XXX: '../../../etc/passwd' bug? ;-)
-        file_path = path.join(self.www_dir, rel_file)
-
+        file_path = self.findFile(req)
 
         if req.path == '/add_comment':
-            resp.status = 200
-            resp.body = 'dzieks'
-
-
-        if path.isfile(file_path):
+            resp = self.doAddComment(req, resp)
+        elif path.isfile(file_path):
             try:
-                if req.path.endswith('.html'):
-                    file_contents = loads(open(file_path).read())['body']
+                if file_path.endswith('.pkl'):
+                    file_contents = cPickle.loads(open(file_path).read())['body']
                 else:
-                    file_contents = ''.join(open(file_path).read())
+                    file_contents = open(file_path, 'rb').read()
             except:
                 file_contents = '<html><body>doHTMLFile(): 404!</body></html>'
 
 
         return resp(environ, start_response)
 
+
+    def findFile(self, req):
+        if req.path == '/':
+            rel_file = 'index.html'
+        else:
+            rel_file = req.path[1:]
+
+        # this is a comments db file
+        if rel_file.startswith('comments/'):
+            file_path = path.join(self.www_dir, '../'+rel_file)
+            return file_path
+
+        # HTML files are being kept as '.pkl' files
+        if rel_file.endswith('.html'):
+            rel_file = rel_file.strip('.html') + '.pkl'
+
+        # XXX: '../../../etc/passwd' bug? ;-)
+        file_path = path.join(self.www_dir, rel_file)
+       
+        return file_path
+
+    def doAddComment(self, req, resp):
+        p_id = req.POST['paragraph_id']
+        
+        if path.exists('comments/' + p_id):
+            data = load_comments(p_id)
+        else:
+            data = []
+
+        data.append(dict(req.POST))
+        save_comments(p_id, data)
+
+        resp.status = 200
+        resp.body = 'dzieks'
+        return resp
+
     def doHTMLFile(self, environ, file_contents):
         req = Request(environ)
         r = Response(content_type='text/html', charset='utf8')