# HG changeset patch # User amit # Date 1288168151 -19800 # Node ID de4a2ed2f34b78c521904304b3fba5174461461f # Parent f5e18f8ed036af570d31366c281cd4254299cab1 Adding readme files diff -r f5e18f8ed036 -r de4a2ed2f34b README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,25 @@ +.. -*- restructuredtext -*- + +================= +README for sphinx-simplecomment +================= + +The Project +=========== + +The project is inspired by django book and hg book. It allows us +to comment on sphinx documentation. + +Installing +========== + +Add the html files of SPHINX PROJECT in setting at the variable SPHINX_PROJECT + +do + +python manage.py syncdb +python manage runserver + + + + diff -r f5e18f8ed036 -r de4a2ed2f34b hsbook_back.js --- a/hsbook_back.js Fri Oct 15 15:59:28 2010 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -function qid(id) { - return id.replace(/([.:])/g, "\\$1"); -} - -function beforeComment(formData, jqForm, options) { - var form=jqForm[0]; - - if (form.comment.textLength.toString()=='0') { - $("span.comment_error").empty().append( - " Your comment is empty"); - return false; - } - if (form.name.textLength.toString()=='0') { - $("span.comment_error").empty().append( - " Please provide a name"); - return false; - } - $(options.target + " span.comment_error").empty().after( - ""); - $("input[@name=submit]").attr("disabled", true); -} - -function ajaxifyForm(id) { - -// $('#form_func_1').replaceWith('something'); - - var substring=id.substr(9); - $('#form_'+substring).ajaxForm({beforeSubmit: beforeComment, - success: function(){ loadComments(id);} - - });} - - -function toggleComment(id) { - $("#toggle_" + qid(id)).nextAll().toggle(); - return false; -} - - -function loadComments(id) -{ - - var substring=id.substr(9); - $('#comments_'+substring).load("http://127.0.0.1:8000/single/"+ substring +'/',function() { ajaxifyForm(id);} - ); - -} - - - - -function loadAllComments() { - $("a.commenttoggle").each(function() { - var id = $(this).attr("pid"); - if (id) { - loadComments(id); - } - }); -} - - - -$(document).ready(function() { - function loading(id) { - return " " + - "

Loading...." + - ""; - } - -$("p[@id]").each(function() { - $(this).append(loading($(this).attr("id"))); - }); - - -var url_string=window.location.pathname; -var temp = new Array(); -temp = url_string.split('/'); -var chap_name=temp[temp.length-1].split('.')[0]; - -jQuery.getJSON("http://127.0.0.1:8000/count/"+chap_name, function(data) { - - $("span.comment").each(function(data_val) { - var id = $(this).attr("id"); - var substring=id.substr(9); - - $(this).replaceWith("" + data.count[substring] +' comments'+ ""); - - }); - - - }); - - }); - - - - - - - - - - - - - diff -r f5e18f8ed036 -r de4a2ed2f34b simplecomment.py --- a/simplecomment.py Fri Oct 15 15:59:28 2010 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sphinx.builders.webapp - ~~~~~~~~~~~~~~~~~~~~~~ - - A web application builder. - - :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import os -import sys -import codecs -import shutil -import cPickle -from os import path -from hashlib import md5 -from types import ListType, TupleType -import re - - -import jinja2 as j2 - -#from mercurial import commands, ui -#from mercurial.hg import repository - -from sphinx.builders.html import StandaloneHTMLBuilder -from sphinx.errors import SphinxError -from sphinx.web.dbutils import PidDb -from sphinx.web.webconfig import WebConfig -from sphinx.writers.html import HTMLTranslator - - - - - - -class SimpleCommentHTMLBuilder(StandaloneHTMLBuilder): - """ Static html pages with paragraph ids. - """ - def init(self): - self.app.add_javascript('simplecomment.js') - self.id_file_loc=os.path.join(self.outdir,'paragraph_id.py') - self.id_file=open(self.id_file_loc,'w') - self.beginning="p_list= " - self.id_dictionary={} - - StandaloneHTMLBuilder.init(self) - - def get_target_uri(self, docname, typ=None): - return docname + self.link_suffix - - def write_doc(self, docname, doctree): - StandaloneHTMLBuilder.write_doc(self, docname, doctree) - - def prepare_writing(self, docnames): - StandaloneHTMLBuilder.prepare_writing(self, docnames) - - def finish(self): - StandaloneHTMLBuilder.finish(self) - self.add_pids_to_paragraphs() - self.id_file.write(self.beginning+str(self.id_dictionary)) - - - def add_pids_to_paragraphs(self): - all_files=[] - for path,dir,filenames in os.walk(self.outdir): - for filename in filenames: - all_files.append(os.path.join(path, filename)) - - for element in all_files : - if element.split('.')[1]=='html': - self.id_list=[] - self.taggen(element) - self.id_dictionary[self.chapter.split('/')[-1]]=self.id_list - - else : - pass - - def retag(self,s): - self.biggest_id += 1 - id_name="%s_%x" % (self.chapter.split('/')[-1],self.biggest_id) - self.id_list.append(id_name) - - return '

' %id_name - - - - - def taggen(self,html_file_name): - tagged = re.compile('

]*>', re.M) - self.biggest_id=0 - self.chapter=html_file_name.split('.')[0] - - try: - f = open(html_file_name).read() - f1 = re.sub('

',self.retag, f ) - - - if f1 != f: - tmpname = html_file_name+ '.tmp' - fp = open(tmpname, 'w') - fp.write(f1) - fp.close() - os.rename(tmpname,html_file_name) - - except IOError: - pass - - - diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/settings.py --- a/sphinx_django/settings.py Fri Oct 15 15:59:28 2010 +0530 +++ b/sphinx_django/settings.py Wed Oct 27 13:59:11 2010 +0530 @@ -1,4 +1,5 @@ # Django settings for sphinx_django project. +import os DEBUG = True TEMPLATE_DEBUG = DEBUG @@ -66,16 +67,17 @@ ROOT_URLCONF = 'sphinx_django.urls' - +templates=os.path.join(os.getcwd(),'templates') TEMPLATE_DIRS = ( - "/home/amit/review/sphinx_django/templates/" + templates # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) - +# Path of your sphinx static files +SPHINX_PROJECT = '/home/amit/review/sttp_com/_build/html' INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/settings.pyc Binary file sphinx_django/settings.pyc has changed diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/settings.py~ --- a/sphinx_django/settings.py~ Fri Oct 15 15:59:28 2010 +0530 +++ b/sphinx_django/settings.py~ Wed Oct 27 13:59:11 2010 +0530 @@ -1,4 +1,5 @@ # Django settings for sphinx_django project. +import os DEBUG = True TEMPLATE_DEBUG = DEBUG @@ -65,6 +66,9 @@ ROOT_URLCONF = 'sphinx_django.urls' + + + TEMPLATE_DIRS = ( "/home/amit/review/sphinx_django/templates/" @@ -72,7 +76,8 @@ # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) - +# Path of your sphinx static files +SPHINX_PROJECT = 'SPHINX STATIC FILES' INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/sphinxcomment/views.py --- a/sphinx_django/sphinxcomment/views.py Fri Oct 15 15:59:28 2010 +0530 +++ b/sphinx_django/sphinxcomment/views.py Wed Oct 27 13:59:11 2010 +0530 @@ -10,10 +10,12 @@ from django.template import Context from django.template.loader import get_template from django.utils.simplejson import dumps - +from django.conf import settings +from os.path import join, splitext +from BeautifulSoup import BeautifulSoup as bss, Tag -placeholder_string = open('paragraph_id.py').read() -exec placeholder_string +#placeholder_string = open('paragraph_id.py').read() +#exec placeholder_string def dump_queries(): # requires settings.DEBUG to be set to True in order to work @@ -38,46 +40,36 @@ def comments_by_chapter(chapter): objs = {} - try: - para_list=p_list[chapter] - - for paragraph_id in para_list: - objs[paragraph_id]=[] - - except: - para_list=[] - - for paragraph_id in para_list: - print chapter ,paragraph_id - for c in Comment.objects.filter(element__chapter_name=chapter,element__paragraph_id=paragraph_id).order_by('date'): - - objs[paragraph_id].append(c) + for c in Comment.objects.filter(element__chapter_name=chapter).order_by('date'): + objs.setdefault(c.element.paragraph_id, []).append(c) + return objs + -def chapter(request): - template = get_template('comment.html') - resp = {} - for elt, comments in comments_by_chapter(chapter).iteritems(): - print elt ,comments - form = CommentForm(initial={ - 'paragraph_id': elt, - 'name': name - }) - resp[elt] = template.render(Context({ - 'paragraph_id': elt, - 'form': form, - 'length': len(comments), - 'query': comments, - })) - return HttpResponse(dumps(resp), mimetype='application/json') +# def chapter(request): +# template = get_template('comment.html') +# resp = {} +# for elt, comments in comments_by_chapter(chapter).iteritems(): +# print elt ,comments +# form = CommentForm(initial={ +# 'paragraph_id': elt, +# 'name': name +# }) +# resp[elt] = template.render(Context({ +# 'paragraph_id': elt, +# 'form': form, +# 'length': len(comments), +# 'query': comments, +# })) +# return HttpResponse(dumps(resp), mimetype='application/json') def chapter_count(request,chapter_name): print chapter_name @@ -98,7 +90,7 @@ if paragraph_id[-1]=='/': paragraph_id=paragraph_id[:-1] queryset = Comment.objects.filter(element=paragraph_id) - print paragraph_id + print len(queryset) if form is None: form = CommentForm(initial={ 'paragraph_id': paragraph_id, @@ -163,8 +155,27 @@ string="

test comment

" return HttpResponse(string,mimetype="text/plain") - - +def page(req, path): + if splitext(path)[1] == '.html': + soup = bss(open(join(settings.SPHINX_PROJECT, path)).read()) + head = soup.find('head') + first_script = Tag(soup, 'script') + first_script['src'] = "../_static/simplecomment.js" + first_script['type'] = "text/javascript" + second_script = Tag(soup, 'script') + second_script['src'] = "../_static/jquery.form.js" + second_script['type'] = "text/javascript" + head.insert(-1, first_script) + head.insert(-1, second_script) + counter = 0 + page_identity = path.split('.')[0].replace('/', '_') + for p in soup.findAll('p'): + p['id'] = '%s_%s' %(page_identity, counter) + counter += 1 + return HttpResponse(str(soup)) + else: + return HttpResponse(open(join(settings.SPHINX_PROJECT, path)).read()) + #return HttpResponse(dumps(string),mimetype="text/plain") #test= csrf_exempt(test) diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/sphinxcomment/views.pyc Binary file sphinx_django/sphinxcomment/views.pyc has changed diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/sphinxcomment/views.py~ --- a/sphinx_django/sphinxcomment/views.py~ Fri Oct 15 15:59:28 2010 +0530 +++ b/sphinx_django/sphinxcomment/views.py~ Wed Oct 27 13:59:11 2010 +0530 @@ -10,10 +10,12 @@ from django.template import Context from django.template.loader import get_template from django.utils.simplejson import dumps - +from django.conf import settings +from os.path import join, splitext +from BeautifulSoup import BeautifulSoup as bss, Tag -placeholder_string = open('paragraph_id.py').read() -exec placeholder_string +#placeholder_string = open('paragraph_id.py').read() +#exec placeholder_string def dump_queries(): # requires settings.DEBUG to be set to True in order to work @@ -38,44 +40,36 @@ def comments_by_chapter(chapter): objs = {} - try: - para_list=p_list[chapter] - - for paragraph_id in para_list: - objs[paragraph_id]=[] + for c in Comment.objects.filter(element__chapter_name=chapter).order_by('date'): + objs.setdefault(c.element.paragraph_id, []).append(c) + - except: - para_list=[] + + + return objs - for paragraph_id in para_list: - - for c in Comment.objects.filter(element__chapter_name=chapter,element__paragraph_id=paragraph_id).order_by('date'): - - objs[paragraph_id].append(c) - - return objs -def chapter(request): - template = get_template('comment.html') - resp = {} - for elt, comments in comments_by_chapter(chapter).iteritems(): - print elt ,comments - form = CommentForm(initial={ - 'paragraph_id': elt, - 'name': name - }) - resp[elt] = template.render(Context({ - 'paragraph_id': elt, - 'form': form, - 'length': len(comments), - 'query': comments, - })) - return HttpResponse(dumps(resp), mimetype='application/json') +# def chapter(request): +# template = get_template('comment.html') +# resp = {} +# for elt, comments in comments_by_chapter(chapter).iteritems(): +# print elt ,comments +# form = CommentForm(initial={ +# 'paragraph_id': elt, +# 'name': name +# }) +# resp[elt] = template.render(Context({ +# 'paragraph_id': elt, +# 'form': form, +# 'length': len(comments), +# 'query': comments, +# })) +# return HttpResponse(dumps(resp), mimetype='application/json') def chapter_count(request,chapter_name): print chapter_name @@ -93,9 +87,10 @@ return HttpResponse(dumps(resp), mimetype='application/json') def single(request,paragraph_id, form=None, newid=None): - paragraph_id=paragraph_id[:-1] + if paragraph_id[-1]=='/': + paragraph_id=paragraph_id[:-1] queryset = Comment.objects.filter(element=paragraph_id) - print paragraph_id + print len(queryset) if form is None: form = CommentForm(initial={ 'paragraph_id': paragraph_id, @@ -119,11 +114,13 @@ def submit(request, paragraph_id): + try: element = get_object_or_404(Element, paragraph_id=paragraph_id) except Http404: + #creating chapter name from paragraph_id surely there is a better way using the context but i do not know as yet chapter_id='_'.join(paragraph_id.split('_')[0:-1]) - chapter_name=chapter_id.replace('_','/') + chapter_name=chapter_id[-1::-1].replace('_','/',1)[-1::-1] element=Element(chapter_name=chapter_name,paragraph_id=paragraph_id) element.save() print element.chapter_name @@ -158,8 +155,27 @@ string="

test comment

" return HttpResponse(string,mimetype="text/plain") - - +def page(req, path): + if splitext(path)[1] == '.html': + soup = bss(open(join(settings.SPHINX_PROJECT, path)).read()) + head = soup.find('head') + first_script = Tag(soup, 'script') + first_script['src'] = "_static/simplecomment.js" + first_script['type'] = "text/javascript" + second_script = Tag(soup, 'script') + second_script['src'] = "_static/jquery.form.js" + second_script['type'] = "text/javascript" + head.insert(-1, first_script) + head.insert(-1, second_script) + counter = 0 + page_identity = path.split('.')[0].replace('/', '_') + for p in soup.findAll('p'): + p['id'] = '%s_%s' %(page_identity, counter) + counter += 1 + return HttpResponse(str(soup)) + else: + return HttpResponse(open(join(settings.SPHINX_PROJECT, path)).read()) + #return HttpResponse(dumps(string),mimetype="text/plain") #test= csrf_exempt(test) diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/#comments.js# --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/#comments.js# Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,587 @@ +/* + * Java Script/JQuery glue for server-side Python code and the comments/fixes + * stuff which is being served along with the documentation. + * + * :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + * Below is a short description of the main functions used to make the tool + * work. Internal functions are not listed here. + * + ** + *** checking/downloading/printing/adding comments and fixes **************** + ** + * + * load_comments(id) -> check if database file with comments for paragraph 'id' + * exists on the server; if yes, invoke comments_found() + * function; if not, invoke no_comments() function. + * + * load_fixes(id) -> check if database file with fixes for paragraph 'id' + * exists on the server; if yes, invoke fixes_found() + * function; if not, invoke no_fixes() function. + * + * no_comments(id) -> insert a link ('No comments') to the post form after + * the paragraph 'id'. + * + * no_fixes(id) -> insert a link ('No fixes') to the post form after the + * 'No comments' string. + * + * comments_found(id) -> download the comments database file for paragraph 'id' + * and print it under the paragraph. + * + * fixes_found(id) -> download the fixes database file for paragraph 'id' + * and print it under the paragraph. + * + * print_comments(id, data) -> print comments collected in an array 'data' + * under the paragraph 'id'. + * 'data' is an array of objects; every object + * has properties like 'name', 'score', 'comment'. + * This function also prints a link at the end + * of paragraph with a number of comments hidden + * (i.e. "3 Comments"). + * + * print_fixes(id, data) -> print fixes collected in an array 'data' under + * the paragraph 'id'. + * The description for print_comments() applies. + * + * add_new_comment(id) -> ajaxify a comment post form for paragraph 'id' + * and reload comments (with load_comments() function). + * This function also validates the form and resets + * it on successful submit. + * + ** + *** displaying/hiding areas ************************************************* + ** + * + * show_hide_comments(id) -> hide fixes area, show comments area and make sure + * that the main comments/fixes area is shown + * + * show_hide_fixes(id) -> hide comments area, show fixes area and make sure + * that the main comments/fixes area is shown + * + * show_hide_submitFixFields(id) -> show/hide additional fields in the post + * form for fixes view (when 'I would like + * to submit a patch' checkbox is 'true') + * and fill them with data if needed + * + * + ** + *** rating comments/fixes *************************************************** + ** + * + * comments_up_down(id, comment_no, up_down, db) + * -> send a GET request to the server with three parameters: + * - id: paragraph id, + * - comment_no: a number of a comment to score, + * - up_down: two values possible: 'up' or 'down' + * depending on what kind of action should + * be taken ('up' means score+=1, and down + * means score-=1). + * + ** + *** sorting comments/fixes ************************************************ + ** + * + * sort_comments(id, by, db) -> sort comments for paragraph 'id' by 'by' argument + * (two values for 'by' are possible at the moment: + * 'score' and 'date'). The sorting order changes + * automatically from increasing to decreasing with + * every sort. + * + * + ** + *** threading ************************************************************ + ** + * + * new_thread(id) -> make a particular comment a new thread before submitting + * it + * + * reply_to(id, comment_no) -> make a comment a reply to comment 'comment_no' + * + ** + *** developer's actions *************************************************** + ** + * + * delete_comment(db, id, comment_no) -> delete entry from database 'db' + * located in 'id' file under + * 'comment_no' index + * + * commit_fix(node, id, fix_no) -> commit a fix located in 'id' file under + * 'fix_no' index to the repository + * + ** + *** general-use functions ************************************************ + ** + * + * empty_comments(id) -> empty the comments area + * + * empty_fixes(id) -> empty the fixes area + * + * is_developer() -> returns true when developer rights should be granted + * and false when the rights should not be granted. + * At jQuery level it's only about displaying some + * additional/developer-only-options. Real authorization + * is going on on webapp (appserver.py) level. + */ + +comments_path = "/comments/"; +fixes_path = "/fixes/"; +_db = undefined; + +// *** checking/downloading/printing/adding comments ************************ + +function load_generic(what, id, error_func, success_func) { + // if the div was filled with the comments before, empty it before appending + if(_db == 'comments') { + empty_comments(id); + } else { + empty_fixes(id); + } + + // 'what' -> 'comments_path' or 'fixes_path' variables; + var c_path = location.protocol + "//" + location.host + what + id; + $.ajax({ url: c_path, + type: 'HEAD', + error: function() { error_func(id) }, + success: function() { success_func(id)} + }); +} + +function load_comments(id) { + return load_generic(comments_path, id, no_comments, comments_found) +} + +function load_fixes(id) { + return load_generic(fixes_path, id, no_fixes, fixes_found) +} + +function get_load_cf(db) { + if(db == 'comments' || db == comments_path) { + return load_comments; + } + return load_fixes; +} + +////////////////////// + +function not_found_generic(what, id) { + // 'what' -> 'comment' or 'fix' strings + plural = what=='comment'?'comments':'fixes'; + $("a[name*=" + what + "_" + id + "]").replaceWith( + 'No ' + plural + '' + + ''); +} + +function no_comments(id) { + not_found_generic('comment', id); +} + +function no_fixes(id) { + not_found_generic('fix', id); +} + +////////////////////////////// + +function found_generic(what, id, print_func) { + var c_path = location.protocol + "//" + location.host + what + id + "?id=" + id; + $.getJSON(c_path, function(data) { + print_func(id, data); + }); +} + +function comments_found(id) { + found_generic(comments_path, id, print_comments); +} + +function fixes_found(id) { + found_generic(fixes_path, id, print_fixes); +} + +/////////////////////////////// + +function print_generic(what, id, data) { + var c_flag = (what == 'comments') ? true : false; + var singular = (what == 'comments') ? 'comment' : 'fix'; + var isdev = is_developer(); + var node = $('div[class=submitFixFields_' + id + ']').attr('value'); + + if(what == 'comments') { + empty_comments(id); + } else { + empty_fixes(id); + } + + // A 'factory' function which generates '+' and '-' buttons for every comment. + // 'what' is a kind of database (db for comments or for fixes) + // 'id' is a paragraph id. + // 'comment_no' is a place of a comment in the list of comments for given + // paragraph. + // 'up_down' is passed to POST method. It should be 'up' or 'down'. + // 'sign' is what's displayed on the button, by default it's '+' or '-'. + function rate_comment_up_down_button(what, id, comment_no, up_down, sign) { + return ' ' + sign + ' ' + } + + // in fixes view - show proposed diff + function proposed_fix(c_flag, paragraph) { + if(!c_flag) { + return '' + + '' + + 'Fix: ' + paragraph + + '' + + '' + + " " + } + return ''; + } + + // for every comment/fix generate a 'Reply' button + function link_reply_to(id, comment_no) { + return 'Comment no.: ' + data[i].comment_no + + ' (reply).' + } + + /* */ + function delete_comment_button(db, id, comment_no) { + return 'delete' + } + + function commit_button(node, id, fix_no) { + return 'commit' + } + + function developers_actions(what, id, data, i) { + return '' + + '' + + 'Admin actions: ' + + delete_comment_button(what, id, data[i].comment_no) + + ', ' + + commit_button(node, id, data[i].comment_no) + + '.' + + '' + + '' + } + /* */ + + // add the comments for paragraph + for(i=0; i" + + "" + + "" + + "Name: " + data[i].name + ". " + + "(" + get_date(commentDate) + ")" + + '' + + '' + + '' + + '' + + ' Score: ' + data[i].score + '' + + rate_comment_up_down_button(what, id, data[i].comment_no, 'up', '+') + + rate_comment_up_down_button(what, id, data[i].comment_no, 'down', '-') + + '. ' + + link_reply_to(id, data[i].comment_no) + + '' + + '' + + (isdev ? developers_actions(what, id, data, i) : '') + + ' ' + + proposed_fix(c_flag, data[i].paragraph_diff) + + "" + + "" + + 'Comment: ' + data[i].comment + + "" + + "" + + "
"); + } + + // add a button for showing/hiding the comments and post form + $("a[name*=" + singular + "_" + id + "]").replaceWith( + '' + + data.length + ' ' + what + '' + + ''); + + if(what == 'comments') { + hide_fixes(id); + show_comments(id); + } else { + hide_comments(id); + show_fixes(id); + } +} + + +function print_comments(id, data) { + print_generic('comments', id, data); +} + +function print_fixes(id, data) { + print_generic('fixes', id, data); +} + +///////////////////////////// + +function add_new_comment(id) { + function validate(formData, jqForm, options) { + var form = jqForm[0]; + if(!form.name.value) { + alert("Please provide your name"); + return false; + } else if(!form.comment.value) { + alert("Please provide your comment"); + return false; + } else if(form.submitFix.checked && !form.licence.checked) { + alert("You have to agree to publish your fix on our licence!"); + return false; + } + + if(form.submitFix.checked) { + _db = 'fixes'; + } else { + _db = 'comments'; + } + } + + function form_reset() { + $('#commentForm_' + id).resetForm() + new_thread(id); + if(_db == 'comments') { + load_comments(id); + } else { + load_fixes(id); + } + } + + // bind 'commentForm' and provide a simple callback function + $('#commentForm_' + id).ajaxForm({ + beforeSubmit: validate, + success: form_reset + }); +} + +////////////////////////////// + +function hide_main_div(id) { + $('div.x' + id).css('display', 'none'); +} + +function show_main_div(id) { + $('div.x' + id).css('display', 'block'); +} + +function hide_submitFixFields(id) { + $('div.submitFixFields_' + id).css('display', 'none'); +} + +function show_submitFixFields(id) { + node = $('div[class=submitFixFields_' + id + ']').attr('value'); + fill_paragraph_from_repo(node, id); + $('input[name=submitFix]').attr('checked', true); + $('div.submitFixFields_' + id).css('display', 'block'); + _db = 'fixes'; + +} + +function hide_comments(id) { + $('input[name=submitFix]').attr('checked', false); + $('div.comments_for_' + id).css('display', 'none'); +} + +function hide_fixes(id) { + $('div.fixes_for_' + id).css('display', 'none'); + hide_submitFixFields(id); +} + +function show_comments(id) { + $('input[name=submitFix]').attr('checked', false); + $('div.comments_for_' + id).css('display', 'block'); + _db = 'comments'; +} + +function show_fixes(id) { + $('div.fixes_for_' + id).css('display', 'block'); + show_submitFixFields(id); +} + +function mainDivIsHidden(id) { + return $('div.x' + id).is(':hidden'); +} + +function show_menu_hide(what, id) { + function sort_comments_by_button(what, id, by) { + return '' + by + '' + } + + sort_hide_menu = '
' + + 'Hide' + + '' + + ' Sort by: ' + + sort_comments_by_button(what, id, 'date') + + ', ' + + sort_comments_by_button(what, id, 'score') + + ', ' + + sort_comments_by_button(what, id, 'thread') + + '.' + + '

' + + $('div[class=hide_menu_' + id + ']').replaceWith(sort_hide_menu); +} + +function show_hide_comments(id) { + show_menu_hide('comments', id); + hide_fixes(id); + show_comments(id); + + if(mainDivIsHidden(id)) { + show_main_div(id); + } +} + +function show_hide_fixes(id) { + show_menu_hide('fixes', id); + hide_comments(id); + show_fixes(id); + + if(mainDivIsHidden(id)) { + show_main_div(id); + } +} + +function show_hide_submitFixFields(id) { + // show or hide more form fields when 'i would like to submit a fix' is true + var fixes_area_hidden = $('div.submitFixFields_'+id).is(':hidden'); + if(fixes_area_hidden) { + show_submitFixFields(id); + } else { + hide_submitFixFields(id); + } +} + +function fill_paragraph_from_repo(node, id) { + var p_path = location.protocol + "//" + location.host + + "/get_paragraph?node=" + node + "&id=" + id; + $.getJSON(p_path, function(data) { + $('textarea[name=paragraph_' + id + ']').replaceWith( + ''); + $('textarea[name=paragraph_orig_' + id + ']').replaceWith( + ''); + + }); + +} + +// *** rating comments ****************************************************** + +function comments_up_down(id, comment_no, up_down, db) { + // request for a 'score' change + load_func = get_load_cf(db); + var rate_path = location.protocol + "//" + location.host + "/rate_comment"; + $.ajax({ url: rate_path, + type: 'GET', + data: "id=" + id + "&comment_no=" + comment_no + "&up_down=" + up_down + "&db=" + db, + success: function() { load_func(id)} + }); +} + +// *** developer actions **************************************************** + +function delete_comment(db, id, comment_no) { + load_func = get_load_cf(db); + var rate_path = location.protocol + "//" + location.host + "/delete_comment"; + $.ajax({ url: rate_path, + type: 'GET', + data: "id=" + id + "&cno=" + comment_no + "&db=" + db, + success: function() { load_func(id)} + }); +} + +function commit_fix(node, id, fix_no) { + var c_path = location.protocol + "//" + location.host + "/commit_fix"; + $.ajax({ url: c_path, + type: 'GET', + data: "node=" + node + "&id=" + id + "&fix_no=" + fix_no, + success: function() { load_func(id)} + }); +} + +// *** sorting comments ***************************************************** + +function sort_comments(id, by, db) { + // request for a sort of comments, display json data structure ('data') + var c_path = location.protocol + "//" + location.host + + "/sort_comments?id=" + id + "&by=" + by + "&db=" + db; + $.getJSON(c_path, function(data) { + if(db=='comments') { + print_comments(id, data); + } else { + print_fixes(id, data); + } + }); +} + +// *** general-use functions *********************************************** + +function empty_comments(id) { + $('div[class=comments_for_' + id + ']').replaceWith('
'); +} + +function empty_fixes(id) { + $('div[class=fixes_for_' + id + ']').replaceWith('
'); +} + +function is_developer() { + var isdev_path = location.protocol + "//" + location.host + "/isdeveloper"; + http = new XMLHttpRequest(); + http.open('HEAD', isdev_path, false); + http.send(null); + return http.status!=404; +} + +function get_date(d) { + var month=["January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December"]; + var t_date = d.getDate(); // Returns the day of the month + var t_mon = d.getMonth(); // Returns the month as a digit + var t_year = d.getFullYear(); // Returns 4 digit year + var t_hour = d.getHours(); // Returns hours + var t_min = d.getMinutes(); // Returns minutes + var t_sec = d.getSeconds(); // Returns seocnds + return t_hour + ':' + + (t_min < 10 ? '0' : '') + t_min + + ', ' + month[t_mon] + ' ' + t_date + ' ' + t_year +} + +// *** threading ********************************************************** + +function reply_to(id, comment_no) { + $('span[name=replyto_' + id + ']').replaceWith('' + comment_no + ''); + $('textarea[name=replyto_' + id + ']').replaceWith(''); +} + +function new_thread(id) { + $('span[name=replyto_' + id + ']').replaceWith('new thread'); + $('textarea[name=replyto_' + id + ']').replaceWith(''); +} + +$(document).ready(function() { + // load the comments for each paragraph when the DOM is ready + $("span[name*=paragraph]").each(function() { + var id = $(this).attr('value'); + load_comments(id); + load_fixes(id); + }); +}); diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/basic.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/basic.css Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,405 @@ +/** + * Sphinx stylesheet -- basic theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +img { + border: 0; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +/* -- other body styles ----------------------------------------------------- */ + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlight { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/comments.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/comments.js Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,587 @@ +/* + * Java Script/JQuery glue for server-side Python code and the comments/fixes + * stuff which is being served along with the documentation. + * + * :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + * Below is a short description of the main functions used to make the tool + * work. Internal functions are not listed here. + * + ** + *** checking/downloading/printing/adding comments and fixes **************** + ** + * + * load_comments(id) -> check if database file with comments for paragraph 'id' + * exists on the server; if yes, invoke comments_found() + * function; if not, invoke no_comments() function. + * + * load_fixes(id) -> check if database file with fixes for paragraph 'id' + * exists on the server; if yes, invoke fixes_found() + * function; if not, invoke no_fixes() function. + * + * no_comments(id) -> insert a link ('No comments') to the post form after + * the paragraph 'id'. + * + * no_fixes(id) -> insert a link ('No fixes') to the post form after the + * 'No comments' string. + * + * comments_found(id) -> download the comments database file for paragraph 'id' + * and print it under the paragraph. + * + * fixes_found(id) -> download the fixes database file for paragraph 'id' + * and print it under the paragraph. + * + * print_comments(id, data) -> print comments collected in an array 'data' + * under the paragraph 'id'. + * 'data' is an array of objects; every object + * has properties like 'name', 'score', 'comment'. + * This function also prints a link at the end + * of paragraph with a number of comments hidden + * (i.e. "3 Comments"). + * + * print_fixes(id, data) -> print fixes collected in an array 'data' under + * the paragraph 'id'. + * The description for print_comments() applies. + * + * add_new_comment(id) -> ajaxify a comment post form for paragraph 'id' + * and reload comments (with load_comments() function). + * This function also validates the form and resets + * it on successful submit. + * + ** + *** displaying/hiding areas ************************************************* + ** + * + * show_hide_comments(id) -> hide fixes area, show comments area and make sure + * that the main comments/fixes area is shown + * + * show_hide_fixes(id) -> hide comments area, show fixes area and make sure + * that the main comments/fixes area is shown + * + * show_hide_submitFixFields(id) -> show/hide additional fields in the post + * form for fixes view (when 'I would like + * to submit a patch' checkbox is 'true') + * and fill them with data if needed + * + * + ** + *** rating comments/fixes *************************************************** + ** + * + * comments_up_down(id, comment_no, up_down, db) + * -> send a GET request to the server with three parameters: + * - id: paragraph id, + * - comment_no: a number of a comment to score, + * - up_down: two values possible: 'up' or 'down' + * depending on what kind of action should + * be taken ('up' means score+=1, and down + * means score-=1). + * + ** + *** sorting comments/fixes ************************************************ + ** + * + * sort_comments(id, by, db) -> sort comments for paragraph 'id' by 'by' argument + * (two values for 'by' are possible at the moment: + * 'score' and 'date'). The sorting order changes + * automatically from increasing to decreasing with + * every sort. + * + * + ** + *** threading ************************************************************ + ** + * + * new_thread(id) -> make a particular comment a new thread before submitting + * it + * + * reply_to(id, comment_no) -> make a comment a reply to comment 'comment_no' + * + ** + *** developer's actions *************************************************** + ** + * + * delete_comment(db, id, comment_no) -> delete entry from database 'db' + * located in 'id' file under + * 'comment_no' index + * + * commit_fix(node, id, fix_no) -> commit a fix located in 'id' file under + * 'fix_no' index to the repository + * + ** + *** general-use functions ************************************************ + ** + * + * empty_comments(id) -> empty the comments area + * + * empty_fixes(id) -> empty the fixes area + * + * is_developer() -> returns true when developer rights should be granted + * and false when the rights should not be granted. + * At jQuery level it's only about displaying some + * additional/developer-only-options. Real authorization + * is going on on webapp (appserver.py) level. + */ + +comments_path = "/comments/"; +fixes_path = "/fixes/"; +_db = undefined; + +// *** checking/downloading/printing/adding comments ************************ + +function load_generic(what, id, error_func, success_func) { + // if the div was filled with the comments before, empty it before appending + if(_db == 'comments') { + empty_comments(id); + } else { + empty_fixes(id); + } + + // 'what' -> 'comments_path' or 'fixes_path' variables; + var c_path = location.protocol + "//" + location.host + what + id; + $.ajax({ url: c_path, + type: 'HEAD', + error: function() { error_func(id) }, + success: function() { success_func(id)} + }); +} + +function load_comments(id) { + return load_generic(comments_path, id, no_comments, comments_found) +} + +function load_fixes(id) { + return load_generic(fixes_path, id, no_fixes, fixes_found) +} + +function get_load_cf(db) { + if(db == 'comments' || db == comments_path) { + return load_comments; + } + return load_fixes; +} + +////////////////////// + +function not_found_generic(what, id) { + // 'what' -> 'comment' or 'fix' strings + plural = what=='comment'?'comments':'fixes'; + $("a[name*=" + what + "_" + id + "]").replaceWith( + 'No ' + plural + '' + + ''); +} + +function no_comments(id) { + not_found_generic('comment', id); +} + +function no_fixes(id) { + not_found_generic('fix', id); +} + +////////////////////////////// + +function found_generic(what, id, print_func) { + var c_path = location.protocol + "//" + location.host + what + id + "?id=" + id; + $.getJSON(c_path, function(data) { + print_func(id, data); + }); +} + +function comments_found(id) { + found_generic(comments_path, id, print_comments); +} + +function fixes_found(id) { + found_generic(fixes_path, id, print_fixes); +} + +/////////////////////////////// + +function print_generic(what, id, data) { + var c_flag = (what == 'comments') ? true : false; + var singular = (what == 'comments') ? 'comment' : 'fix'; + var isdev = is_developer(); + var node = $('div[class=submitFixFields_' + id + ']').attr('value'); + + if(what == 'comments') { + empty_comments(id); + } else { + empty_fixes(id); + } + + // A 'factory' function which generates '+' and '-' buttons for every comment. + // 'what' is a kind of database (db for comments or for fixes) + // 'id' is a paragraph id. + // 'comment_no' is a place of a comment in the list of comments for given + // paragraph. + // 'up_down' is passed to POST method. It should be 'up' or 'down'. + // 'sign' is what's displayed on the button, by default it's '+' or '-'. + function rate_comment_up_down_button(what, id, comment_no, up_down, sign) { + return ' ' + sign + ' ' + } + + // in fixes view - show proposed diff + function proposed_fix(c_flag, paragraph) { + if(!c_flag) { + return '' + + '' + + 'Fix: ' + paragraph + + '' + + '' + + " " + } + return ''; + } + + // for every comment/fix generate a 'Reply' button + function link_reply_to(id, comment_no) { + return 'Comment no.: ' + data[i].comment_no + + ' (reply).' + } + + /* */ + function delete_comment_button(db, id, comment_no) { + return 'delete' + } + + function commit_button(node, id, fix_no) { + return 'commit' + } + + function developers_actions(what, id, data, i) { + return '' + + '' + + 'Admin actions: ' + + delete_comment_button(what, id, data[i].comment_no) + + ', ' + + commit_button(node, id, data[i].comment_no) + + '.' + + '' + + '' + } + /* */ + + // add the comments for paragraph + for(i=0; i" + + "" + + "" + + "Name: " + data[i].name + ". " + + "(" + get_date(commentDate) + ")" + + '' + + '' + + '' + + '' + + ' Score: ' + data[i].score + '' + + rate_comment_up_down_button(what, id, data[i].comment_no, 'up', '+') + + rate_comment_up_down_button(what, id, data[i].comment_no, 'down', '-') + + '. ' + + link_reply_to(id, data[i].comment_no) + + '' + + '' + + (isdev ? developers_actions(what, id, data, i) : '') + + ' ' + + proposed_fix(c_flag, data[i].paragraph_diff) + + "" + + "" + + 'Comment: ' + data[i].comment + + "" + + "" + + "
"); + } + + // add a button for showing/hiding the comments and post form + $("a[name*=" + singular + "_" + id + "]").replaceWith( + '' + + data.length + ' ' + what + '' + + ''); + + if(what == 'comments') { + hide_fixes(id); + show_comments(id); + } else { + hide_comments(id); + show_fixes(id); + } +} + + +function print_comments(id, data) { + print_generic('comments', id, data); +} + +function print_fixes(id, data) { + print_generic('fixes', id, data); +} + +///////////////////////////// + +function add_new_comment(id) { + function validate(formData, jqForm, options) { + var form = jqForm[0]; + if(!form.name.value) { + alert("Please provide your name"); + return false; + } else if(!form.comment.value) { + alert("Please provide your comment"); + return false; + } else if(form.submitFix.checked && !form.licence.checked) { + alert("You have to agree to publish your fix on our licence!"); + return false; + } + + if(form.submitFix.checked) { + _db = 'fixes'; + } else { + _db = 'comments'; + } + } + + function form_reset() { + $('#commentForm_' + id).resetForm() + new_thread(id); + if(_db == 'comments') { + load_comments(id); + } else { + load_fixes(id); + } + } + + // bind 'commentForm' and provide a simple callback function + $('#commentForm_' + id).ajaxForm({ + beforeSubmit: validate, + success: form_reset + }); +} + +////////////////////////////// + +function hide_main_div(id) { + $('div.x' + id).css('display', 'none'); +} + +function show_main_div(id) { + $('div.x' + id).css('display', 'block'); +} + +function hide_submitFixFields(id) { + $('div.submitFixFields_' + id).css('display', 'none'); +} + +function show_submitFixFields(id) { + node = $('div[class=submitFixFields_' + id + ']').attr('value'); + fill_paragraph_from_repo(node, id); + $('input[name=submitFix]').attr('checked', true); + $('div.submitFixFields_' + id).css('display', 'block'); + _db = 'fixes'; + +} + +function hide_comments(id) { + $('input[name=submitFix]').attr('checked', false); + $('div.comments_for_' + id).css('display', 'none'); +} + +function hide_fixes(id) { + $('div.fixes_for_' + id).css('display', 'none'); + hide_submitFixFields(id); +} + +function show_comments(id) { + $('input[name=submitFix]').attr('checked', false); + $('div.comments_for_' + id).css('display', 'block'); + _db = 'comments'; +} + +function show_fixes(id) { + $('div.fixes_for_' + id).css('display', 'block'); + show_submitFixFields(id); +} + +function mainDivIsHidden(id) { + return $('div.x' + id).is(':hidden'); +} + +function show_menu_hide(what, id) { + function sort_comments_by_button(what, id, by) { + return '' + by + '' + } + + sort_hide_menu = '
' + + 'Hide' + + '' + + ' Sort by: ' + + sort_comments_by_button(what, id, 'date') + + ', ' + + sort_comments_by_button(what, id, 'score') + + ', ' + + sort_comments_by_button(what, id, 'thread') + + '.' + + '

' + + $('div[class=hide_menu_' + id + ']').replaceWith(sort_hide_menu); +} + +function show_hide_comments(id) { + show_menu_hide('comments', id); + hide_fixes(id); + show_comments(id); + + if(mainDivIsHidden(id)) { + show_main_div(id); + } +} + +function show_hide_fixes(id) { + show_menu_hide('fixes', id); + hide_comments(id); + show_fixes(id); + + if(mainDivIsHidden(id)) { + show_main_div(id); + } +} + +function show_hide_submitFixFields(id) { + // show or hide more form fields when 'i would like to submit a fix' is true + var fixes_area_hidden = $('div.submitFixFields_'+id).is(':hidden'); + if(fixes_area_hidden) { + show_submitFixFields(id); + } else { + hide_submitFixFields(id); + } +} + +function fill_paragraph_from_repo(node, id) { + var p_path = location.protocol + "//" + location.host + + "/get_paragraph?node=" + node + "&id=" + id; + $.getJSON(p_path, function(data) { + $('textarea[name=paragraph_' + id + ']').replaceWith( + ''); + $('textarea[name=paragraph_orig_' + id + ']').replaceWith( + ''); + + }); + +} + +// *** rating comments ****************************************************** + +function comments_up_down(id, comment_no, up_down, db) { + // request for a 'score' change + load_func = get_load_cf(db); + var rate_path = location.protocol + "//" + location.host + "/rate_comment"; + $.ajax({ url: rate_path, + type: 'GET', + data: "id=" + id + "&comment_no=" + comment_no + "&up_down=" + up_down + "&db=" + db, + success: function() { load_func(id)} + }); +} + +// *** developer actions **************************************************** + +function delete_comment(db, id, comment_no) { + load_func = get_load_cf(db); + var rate_path = location.protocol + "//" + location.host + "/delete_comment"; + $.ajax({ url: rate_path, + type: 'GET', + data: "id=" + id + "&cno=" + comment_no + "&db=" + db, + success: function() { load_func(id)} + }); +} + +function commit_fix(node, id, fix_no) { + var c_path = location.protocol + "//" + location.host + "/commit_fix"; + $.ajax({ url: c_path, + type: 'GET', + data: "node=" + node + "&id=" + id + "&fix_no=" + fix_no, + success: function() { load_func(id)} + }); +} + +// *** sorting comments ***************************************************** + +function sort_comments(id, by, db) { + // request for a sort of comments, display json data structure ('data') + var c_path = location.protocol + "//" + location.host + + "/sort_comments?id=" + id + "&by=" + by + "&db=" + db; + $.getJSON(c_path, function(data) { + if(db=='comments') { + print_comments(id, data); + } else { + print_fixes(id, data); + } + }); +} + +// *** general-use functions *********************************************** + +function empty_comments(id) { + $('div[class=comments_for_' + id + ']').replaceWith('
'); +} + +function empty_fixes(id) { + $('div[class=fixes_for_' + id + ']').replaceWith('
'); +} + +function is_developer() { + var isdev_path = location.protocol + "//" + location.host + "/isdeveloper"; + http = new XMLHttpRequest(); + http.open('HEAD', isdev_path, false); + http.send(null); + return http.status!=404; +} + +function get_date(d) { + var month=["January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December"]; + var t_date = d.getDate(); // Returns the day of the month + var t_mon = d.getMonth(); // Returns the month as a digit + var t_year = d.getFullYear(); // Returns 4 digit year + var t_hour = d.getHours(); // Returns hours + var t_min = d.getMinutes(); // Returns minutes + var t_sec = d.getSeconds(); // Returns seocnds + return t_hour + ':' + + (t_min < 10 ? '0' : '') + t_min + + ', ' + month[t_mon] + ' ' + t_date + ' ' + t_year +} + +// *** threading ********************************************************** + +function reply_to(id, comment_no) { + $('span[name=replyto_' + id + ']').replaceWith('' + comment_no + ''); + $('textarea[name=replyto_' + id + ']').replaceWith(''); +} + +function new_thread(id) { + $('span[name=replyto_' + id + ']').replaceWith('new thread'); + $('textarea[name=replyto_' + id + ']').replaceWith(''); +} + +$(document).ready(function() { + // load the comments for each paragraph when the DOM is ready + $("span[name*=paragraph]").each(function() { + var id = $(this).attr('value'); + load_comments(id); + load_fixes(id); + }); +}); diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/default.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/default.css Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,219 @@ +/** + * Sphinx stylesheet -- default theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} \ No newline at end of file diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/doctools.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/doctools.js Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,232 @@ +/// XXX: make it cross browser + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger + */ +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", + "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {} +} + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +} + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +} + +/** + * small function to check if an array contains + * a given item. + */ +jQuery.contains = function(arr, item) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == item) + return true; + } + return false; +} + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this) + }); + } + } + return this.each(function() { + highlight(this); + }); +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initModIndex(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can savely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlight'); + }); + }, 10); + $('') + .appendTo($('.sidebar .this-page-menu')); + } + }, + + /** + * init the modindex toggle buttons + */ + initModIndex : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + console.log($('tr.cg-' + idnum).toggle()); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); + $('span.highlight').removeClass('highlight'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/file.png Binary file sphinx_django/static/file.png has changed diff -r f5e18f8ed036 -r de4a2ed2f34b sphinx_django/static/jquery.form.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphinx_django/static/jquery.form.js Wed Oct 27 13:59:11 2010 +0530 @@ -0,0 +1,643 @@ +/* + * jQuery Form Plugin + * version: 2.28 (10-MAY-2009) + * @requires jQuery v1.2.2 or later + * + * Examples and documentation at: http://malsup.com/jquery/form/ + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ +;(function($) { + +/* + Usage Note: + ----------- + Do not use both ajaxSubmit and ajaxForm on the same form. These + functions are intended to be exclusive. Use ajaxSubmit if you want + to bind your own submit handler to the form. For example, + + $(document).ready(function() { + $('#myForm').bind('submit', function() { + $(this).ajaxSubmit({ + target: '#output' + }); + return false; // <-- important! + }); + }); + + Use ajaxForm when you want the plugin to manage all the event binding + for you. For example, + + $(document).ready(function() { + $('#myForm').ajaxForm({ + target: '#output' + }); + }); + + When using ajaxForm, the ajaxSubmit function will be invoked for you + at the appropriate time. +*/ + +/** + * ajaxSubmit() provides a mechanism for immediately submitting + * an HTML form using AJAX. + */ +$.fn.ajaxSubmit = function(options) { + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) + if (!this.length) { + log('ajaxSubmit: skipping submit process - no element selected'); + return this; + } + + if (typeof options == 'function') + options = { success: options }; + + var url = $.trim(this.attr('action')); + if (url) { + // clean url (don't include hash vaue) + url = (url.match(/^([^#]+)/)||[])[1]; + } + url = url || window.location.href || '' + + options = $.extend({ + url: url, + type: this.attr('method') || 'GET' + }, options || {}); + + // hook for manipulating the form data before it is extracted; + // convenient for use with rich editors like tinyMCE or FCKEditor + var veto = {}; + this.trigger('form-pre-serialize', [this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); + return this; + } + + // provide opportunity to alter form data before it is serialized + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSerialize callback'); + return this; + } + + var a = this.formToArray(options.semantic); + if (options.data) { + options.extraData = options.data; + for (var n in options.data) { + if(options.data[n] instanceof Array) { + for (var k in options.data[n]) + a.push( { name: n, value: options.data[n][k] } ); + } + else + a.push( { name: n, value: options.data[n] } ); + } + } + + // give pre-submit callback an opportunity to abort the submit + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSubmit callback'); + return this; + } + + // fire vetoable 'validate' event + this.trigger('form-submit-validate', [a, this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); + return this; + } + + var q = $.param(a); + + if (options.type.toUpperCase() == 'GET') { + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; + options.data = null; // data is null for 'get' + } + else + options.data = q; // data is the query string for 'post' + + var $form = this, callbacks = []; + if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); + if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); + + // perform a load on the target only if dataType is not provided + if (!options.dataType && options.target) { + var oldSuccess = options.success || function(){}; + callbacks.push(function(data) { + $(options.target).html(data).each(oldSuccess, arguments); + }); + } + else if (options.success) + callbacks.push(options.success); + + options.success = function(data, status) { + for (var i=0, max=callbacks.length; i < max; i++) + callbacks[i].apply(options, [data, status, $form]); + }; + + // are there files to upload? + var files = $('input:file', this).fieldValue(); + var found = false; + for (var j=0; j < files.length; j++) + if (files[j]) + found = true; + + var multipart = false; +// var mp = 'multipart/form-data'; +// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); + + // options.iframe allows user to force iframe mode + if (options.iframe || found || multipart) { + // hack to fix Safari hang (thanks to Tim Molendijk for this) + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d + if (options.closeKeepAlive) + $.get(options.closeKeepAlive, fileUpload); + else + fileUpload(); + } + else + $.ajax(options); + + // fire 'notify' event + this.trigger('form-submit-notify', [this, options]); + return this; + + + // private function for handling file uploads (hat tip to YAHOO!) + function fileUpload() { + var form = $form[0]; + + if ($(':input[name=submit]', form).length) { + alert('Error: Form elements must not be named "submit".'); + return; + } + + var opts = $.extend({}, $.ajaxSettings, options); + var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); + + var id = 'jqFormIO' + (new Date().getTime()); + var $io = $('