mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Make websupport builder inherit from serializing builder, remove separate WebSupportApp.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import os
|
||||
import pickle
|
||||
import cPickle as pickle
|
||||
|
||||
from docutils.utils import Reporter
|
||||
|
||||
|
||||
@@ -9,31 +9,43 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import cPickle as pickle
|
||||
from os import path
|
||||
import posixpath
|
||||
import shutil
|
||||
|
||||
from docutils.io import StringOutput
|
||||
|
||||
from sphinx.jinja2glue import BuiltinTemplateLoader
|
||||
from sphinx.util.osutil import os_path, relative_uri, ensuredir, copyfile
|
||||
from sphinx.util.jsonimpl import dumps as dump_json
|
||||
from sphinx.util.websupport import is_commentable
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.builders.html import PickleHTMLBuilder
|
||||
from sphinx.builders.versioning import VersioningBuilderMixin
|
||||
from sphinx.writers.websupport import WebSupportTranslator
|
||||
|
||||
|
||||
class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
class WebSupportBuilder(PickleHTMLBuilder, VersioningBuilderMixin):
|
||||
"""
|
||||
Builds documents for the web support package.
|
||||
"""
|
||||
name = 'websupport'
|
||||
out_suffix = '.fpickle'
|
||||
|
||||
def init(self):
|
||||
StandaloneHTMLBuilder.init(self)
|
||||
PickleHTMLBuilder.init(self)
|
||||
VersioningBuilderMixin.init(self)
|
||||
# templates are needed for this builder, but the serializing
|
||||
# builder does not initialize them
|
||||
self.init_templates()
|
||||
if not isinstance(self.templates, BuiltinTemplateLoader):
|
||||
raise RuntimeError('websupport builder must be used with '
|
||||
'the builtin templates')
|
||||
# add our custom JS
|
||||
self.script_files.append('_static/websupport.js')
|
||||
|
||||
def set_webinfo(self, staticdir, virtual_staticdir, search, storage):
|
||||
self.staticdir = staticdir
|
||||
self.virtual_staticdir = virtual_staticdir
|
||||
self.search = search
|
||||
self.storage = storage
|
||||
|
||||
def init_translator_class(self):
|
||||
self.translator_class = WebSupportTranslator
|
||||
@@ -46,9 +58,9 @@ class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
|
||||
self.cur_docname = docname
|
||||
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
|
||||
self.imgpath = '/' + posixpath.join(self.app.staticdir, '_images')
|
||||
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, '_images')
|
||||
self.post_process_images(doctree)
|
||||
self.dlpath = '/' + posixpath.join(self.app.staticdir, '_downloads')
|
||||
self.dlpath = '/' + posixpath.join(self.virtual_staticdir, '_downloads')
|
||||
self.docwriter.write(doctree, destination)
|
||||
self.docwriter.assemble_parts()
|
||||
body = self.docwriter.parts['fragment']
|
||||
@@ -58,11 +70,8 @@ class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
self.index_page(docname, doctree, ctx.get('title', ''))
|
||||
self.handle_page(docname, ctx, event_arg=doctree)
|
||||
|
||||
def get_target_uri(self, docname, typ=None):
|
||||
return docname
|
||||
|
||||
def load_indexer(self, docnames):
|
||||
self.indexer = self.app.search
|
||||
self.indexer = self.search
|
||||
self.indexer.init_indexing(changed=docnames)
|
||||
|
||||
def handle_page(self, pagename, addctx, templatename='page.html',
|
||||
@@ -75,11 +84,13 @@ class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
|
||||
def pathto(otheruri, resource=False,
|
||||
baseuri=self.get_target_uri(pagename)):
|
||||
if not resource:
|
||||
if resource and '://' in otheruri:
|
||||
return otheruri
|
||||
elif not resource:
|
||||
otheruri = self.get_target_uri(otheruri)
|
||||
return relative_uri(baseuri, otheruri) or '#'
|
||||
else:
|
||||
return '/' + posixpath.join(self.app.staticdir, otheruri)
|
||||
return '/' + posixpath.join(self.virtual_staticdir, otheruri)
|
||||
ctx['pathto'] = pathto
|
||||
ctx['hasdoc'] = lambda name: name in self.env.all_docs
|
||||
ctx['encoding'] = self.config.html_output_encoding
|
||||
@@ -90,47 +101,41 @@ class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
self.app.emit('html-page-context', pagename, templatename,
|
||||
ctx, event_arg)
|
||||
|
||||
# Create a dict that will be pickled and used by webapps.
|
||||
css = '<link rel="stylesheet" href="%s" type=text/css />' % \
|
||||
pathto('_static/pygments.css', 1)
|
||||
doc_ctx = {'body': ctx.get('body', ''),
|
||||
'title': ctx.get('title', ''),
|
||||
'css': css,
|
||||
'js': self._make_js(ctx)}
|
||||
# Partially render the html template to proved a more useful ctx.
|
||||
# create a dict that will be pickled and used by webapps
|
||||
doc_ctx = {
|
||||
'body': ctx.get('body', ''),
|
||||
'title': ctx.get('title', ''),
|
||||
}
|
||||
# partially render the html template to get at interesting macros
|
||||
template = self.templates.environment.get_template(templatename)
|
||||
template_module = template.make_module(ctx)
|
||||
if hasattr(template_module, 'sidebar'):
|
||||
doc_ctx['sidebar'] = template_module.sidebar()
|
||||
if hasattr(template_module, 'relbar'):
|
||||
doc_ctx['relbar'] = template_module.relbar()
|
||||
for item in ['sidebar', 'relbar', 'script', 'css']:
|
||||
if hasattr(template_module, item):
|
||||
doc_ctx[item] = getattr(template_module, item)()
|
||||
|
||||
if not outfilename:
|
||||
outfilename = path.join(self.outdir, 'pickles',
|
||||
os_path(pagename) + self.out_suffix)
|
||||
|
||||
ensuredir(path.dirname(outfilename))
|
||||
f = open(outfilename, 'wb')
|
||||
try:
|
||||
pickle.dump(doc_ctx, f, pickle.HIGHEST_PROTOCOL)
|
||||
finally:
|
||||
f.close()
|
||||
self.dump_context(doc_ctx, outfilename)
|
||||
|
||||
# if there is a source file, copy the source file for the
|
||||
# "show source" link
|
||||
if ctx.get('sourcename'):
|
||||
source_name = path.join(self.app.builddir, self.app.staticdir,
|
||||
source_name = path.join(self.staticdir,
|
||||
'_sources', os_path(ctx['sourcename']))
|
||||
ensuredir(path.dirname(source_name))
|
||||
copyfile(self.env.doc2path(pagename), source_name)
|
||||
|
||||
def handle_finish(self):
|
||||
StandaloneHTMLBuilder.handle_finish(self)
|
||||
PickleHTMLBuilder.handle_finish(self)
|
||||
VersioningBuilderMixin.finish(self)
|
||||
|
||||
# move static stuff over to separate directory
|
||||
directories = ['_images', '_static']
|
||||
for directory in directories:
|
||||
src = path.join(self.outdir, directory)
|
||||
dst = path.join(self.app.builddir, self.app.staticdir, directory)
|
||||
dst = path.join(self.staticdir, directory)
|
||||
if path.isdir(src):
|
||||
if path.isdir(dst):
|
||||
shutil.rmtree(dst)
|
||||
@@ -138,23 +143,3 @@ class WebSupportBuilder(StandaloneHTMLBuilder, VersioningBuilderMixin):
|
||||
|
||||
def dump_search_index(self):
|
||||
self.indexer.finish_indexing()
|
||||
|
||||
def _make_js(self, ctx):
|
||||
def make_script(file):
|
||||
path = ctx['pathto'](file, 1)
|
||||
return '<script type="text/javascript" src="%s"></script>' % path
|
||||
|
||||
opts = {
|
||||
'URL_ROOT': ctx.get('url_root', ''),
|
||||
'VERSION': ctx['release'],
|
||||
'COLLAPSE_INDEX': False,
|
||||
'FILE_SUFFIX': '',
|
||||
'HAS_SOURCE': ctx['has_source']
|
||||
}
|
||||
scripts = [make_script(file) for file in ctx['script_files']]
|
||||
scripts.append(make_script('_static/websupport.js'))
|
||||
return '\n'.join([
|
||||
'<script type="text/javascript">'
|
||||
'var DOCUMENTATION_OPTIONS = %s;' % dump_json(opts),
|
||||
'</script>'
|
||||
] + scripts)
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
|
||||
(sidebars != []) %}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{# XXX necessary? #}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
|
||||
{%- macro relbar() %}
|
||||
<div class="related">
|
||||
@@ -78,24 +84,7 @@
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
|
||||
{{ metatags }}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
{%- block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{%- endblock %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
{%- if not embedded %}
|
||||
{%- macro script() %}
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '{{ url_root }}',
|
||||
@@ -108,6 +97,26 @@
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro css() %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
|
||||
{{ metatags }}
|
||||
{%- block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{%- endblock %}
|
||||
{{ css() }}
|
||||
{%- if not embedded %}
|
||||
{{ script() }}
|
||||
{%- if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml"
|
||||
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{#
|
||||
basic/searchresults.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template for the body of the search results page.
|
||||
|
||||
@@ -17,20 +17,20 @@
|
||||
<input type="submit" value="search" />
|
||||
<span id="search-progress" style="padding-left: 10px"></span>
|
||||
</form>
|
||||
{% if search_performed %}
|
||||
<h2>Search Results</h2>
|
||||
{% if not search_results %}
|
||||
<p>Your search did not match any results.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{%- if search_performed %}
|
||||
<h2>Search Results</h2>
|
||||
{%- if not search_results %}
|
||||
<p>Your search did not match any results.</p>
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
<div id="search-results">
|
||||
{% if search_results %}
|
||||
{%- if search_results %}
|
||||
<ul class="search">
|
||||
{% for href, caption, context in search_results %}
|
||||
<li><a href="{{ href }}?highlight={{ q }}">{{ caption }}</a>
|
||||
<li><a href="{{ docroot }}{{ href }}/?highlight={{ q }}">{{ caption }}</a>
|
||||
<div class="context">{{ context|e }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
|
||||
@@ -214,10 +214,18 @@
|
||||
* Add a comment via ajax and insert the comment into the comment tree.
|
||||
*/
|
||||
function addComment(form) {
|
||||
// Disable the form that is being submitted.
|
||||
form.find('textarea,input').attr('disabled', 'disabled');
|
||||
var node_id = form.find('input[name="node"]').val();
|
||||
var parent_id = form.find('input[name="parent"]').val();
|
||||
var text = form.find('textarea[name="comment"]').val();
|
||||
var proposal = form.find('textarea[name="proposal"]').val();
|
||||
|
||||
if (text == '') {
|
||||
showError('Please enter a comment.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the form that is being submitted.
|
||||
form.find('textarea,input').attr('disabled', 'disabled');
|
||||
|
||||
// Send the comment to the server.
|
||||
$.ajax({
|
||||
@@ -227,8 +235,8 @@
|
||||
data: {
|
||||
node: node_id,
|
||||
parent: parent_id,
|
||||
text: form.find('textarea[name="comment"]').val(),
|
||||
proposal: form.find('textarea[name="proposal"]').val()
|
||||
text: text,
|
||||
proposal: proposal
|
||||
},
|
||||
success: function(data, textStatus, error) {
|
||||
// Reset the form.
|
||||
@@ -311,7 +319,7 @@
|
||||
$('#cm' + id).fadeOut('fast');
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError("Oops, there was a problem accepting the comment.");
|
||||
showError('Oops, there was a problem accepting the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -328,7 +336,7 @@
|
||||
});
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError("Oops, there was a problem rejecting the comment.");
|
||||
showError('Oops, there was a problem rejecting the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -354,7 +362,7 @@
|
||||
div.data('comment', comment);
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError("Oops, there was a problem deleting the comment.");
|
||||
showError('Oops, there was a problem deleting the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -395,7 +403,7 @@
|
||||
var classes = link.attr('class').split(/\s+/);
|
||||
for (var i=0; i<classes.length; i++) {
|
||||
if (classes[i] != 'sort-option') {
|
||||
by = classes[i];
|
||||
by = classes[i].substring(2);
|
||||
}
|
||||
}
|
||||
setComparator();
|
||||
@@ -464,7 +472,7 @@
|
||||
url: opts.processVoteURL,
|
||||
data: d,
|
||||
error: function(request, textStatus, error) {
|
||||
showError("Oops, there was a problem casting that vote.");
|
||||
showError('Oops, there was a problem casting that vote.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -589,7 +597,8 @@
|
||||
|
||||
function showError(message) {
|
||||
$(document.createElement('div')).attr({'class': 'popup-error'})
|
||||
.append($(document.createElement('h1')).text(message))
|
||||
.append($(document.createElement('div'))
|
||||
.attr({'class': 'error-header'}).text(message))
|
||||
.appendTo('body')
|
||||
.fadeIn("slow")
|
||||
.delay(2000)
|
||||
@@ -642,12 +651,12 @@
|
||||
};
|
||||
|
||||
var opts = jQuery.extend({
|
||||
processVoteURL: '/process_vote',
|
||||
addCommentURL: '/add_comment',
|
||||
getCommentsURL: '/get_comments',
|
||||
acceptCommentURL: '/accept_comment',
|
||||
rejectCommentURL: '/reject_comment',
|
||||
deleteCommentURL: '/delete_comment',
|
||||
processVoteURL: '/_process_vote',
|
||||
addCommentURL: '/_add_comment',
|
||||
getCommentsURL: '/_get_comments',
|
||||
acceptCommentURL: '/_accept_comment',
|
||||
rejectCommentURL: '/_reject_comment',
|
||||
deleteCommentURL: '/_delete_comment',
|
||||
commentImage: '/static/_static/comment.png',
|
||||
closeCommentImage: '/static/_static/comment-close.png',
|
||||
loadingImage: '/static/_static/ajax-loader.gif',
|
||||
@@ -727,7 +736,7 @@
|
||||
|
||||
var popupTemplate = '\
|
||||
<div class="sphinx-comments" id="sc<%id%>">\
|
||||
<h1>Comments</h1>\
|
||||
<div class="comment-header">Comments</div>\
|
||||
<form method="post" id="cf<%id%>" class="comment-form" action="/docs/add_comment">\
|
||||
<textarea name="comment" cols="80"></textarea>\
|
||||
<p class="propose-button">\
|
||||
@@ -744,12 +753,12 @@
|
||||
<input type="hidden" name="parent" value="" />\
|
||||
<p class="sort-options">\
|
||||
Sort by:\
|
||||
<a href="#" class="sort-option rating">top</a>\
|
||||
<a href="#" class="sort-option ascage">newest</a>\
|
||||
<a href="#" class="sort-option age">oldest</a>\
|
||||
<a href="#" class="sort-option byrating">top</a>\
|
||||
<a href="#" class="sort-option byascage">newest</a>\
|
||||
<a href="#" class="sort-option byage">oldest</a>\
|
||||
</p>\
|
||||
</form>\
|
||||
<h3 id="cn<%id%>">loading comments... <img src="<%loadingImage%>" alt="" /></h3>\
|
||||
<div class="comment-loading" id="cn<%id%>">loading comments... <img src="<%loadingImage%>" alt="" /></div>\
|
||||
<ul id="cl<%id%>" class="comment-ul"></ul>\
|
||||
</div>';
|
||||
|
||||
|
||||
@@ -24,29 +24,35 @@ from sphinx.websupport.search import BaseSearch, SEARCH_ADAPTERS
|
||||
from sphinx.websupport.storage import StorageBackend
|
||||
|
||||
|
||||
class WebSupportApp(Sphinx):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.staticdir = kwargs.pop('staticdir', None)
|
||||
self.builddir = kwargs.pop('builddir', None)
|
||||
self.search = kwargs.pop('search', None)
|
||||
self.storage = kwargs.pop('storage', None)
|
||||
Sphinx.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class WebSupport(object):
|
||||
"""The main API class for the web support package. All interactions
|
||||
with the web support package should occur through this class.
|
||||
"""
|
||||
def __init__(self, srcdir='', builddir='', datadir='', search=None,
|
||||
storage=None, status=sys.stdout, warning=sys.stderr,
|
||||
moderation_callback=None, staticdir='static',
|
||||
docroot=''):
|
||||
def __init__(self,
|
||||
srcdir=None, # only required for building
|
||||
builddir='', # the dir with data/static/doctrees subdirs
|
||||
datadir=None, # defaults to builddir/data
|
||||
staticdir=None, # defaults to builddir/static
|
||||
doctreedir=None, # defaults to builddir/doctrees
|
||||
search=None, # defaults to no search
|
||||
storage=None, # defaults to SQLite in datadir
|
||||
status=sys.stdout,
|
||||
warning=sys.stderr,
|
||||
moderation_callback=None,
|
||||
docroot='',
|
||||
staticroot='static',
|
||||
):
|
||||
# directories
|
||||
self.srcdir = srcdir
|
||||
self.builddir = builddir
|
||||
self.outdir = path.join(builddir, 'data')
|
||||
self.datadir = datadir or self.outdir
|
||||
self.staticdir = staticdir.strip('/')
|
||||
self.staticdir = staticdir or path.join(self.builddir, 'static')
|
||||
self.doctreedir = staticdir or path.join(self.builddir, 'doctrees')
|
||||
# web server virtual paths
|
||||
self.staticroot = staticroot.strip('/')
|
||||
self.docroot = docroot.strip('/')
|
||||
|
||||
self.status = status
|
||||
self.warning = warning
|
||||
self.moderation_callback = moderation_callback
|
||||
@@ -55,6 +61,8 @@ class WebSupport(object):
|
||||
self._init_search(search)
|
||||
self._init_storage(storage)
|
||||
|
||||
self._globalcontext = None
|
||||
|
||||
self._make_base_comment_options()
|
||||
|
||||
def _init_storage(self, storage):
|
||||
@@ -103,19 +111,27 @@ class WebSupport(object):
|
||||
It will also save node data to the database.
|
||||
"""
|
||||
if not self.srcdir:
|
||||
raise errors.SrcdirNotSpecifiedError( \
|
||||
'No srcdir associated with WebSupport object')
|
||||
doctreedir = path.join(self.outdir, 'doctrees')
|
||||
app = WebSupportApp(self.srcdir, self.srcdir,
|
||||
self.outdir, doctreedir, 'websupport',
|
||||
search=self.search, status=self.status,
|
||||
warning=self.warning, storage=self.storage,
|
||||
staticdir=self.staticdir, builddir=self.builddir)
|
||||
raise RuntimeError('No srcdir associated with WebSupport object')
|
||||
app = Sphinx(self.srcdir, self.srcdir, self.outdir, self.doctreedir,
|
||||
'websupport', status=self.status, warning=self.warning)
|
||||
app.builder.set_webinfo(self.staticdir, self.staticroot,
|
||||
self.search, self.storage)
|
||||
|
||||
self.storage.pre_build()
|
||||
app.build()
|
||||
self.storage.post_build()
|
||||
|
||||
def get_globalcontext(self):
|
||||
"""Load and return the "global context" pickle."""
|
||||
if not self._globalcontext:
|
||||
infilename = path.join(self.datadir, 'globalcontext.pickle')
|
||||
f = open(infilename, 'rb')
|
||||
try:
|
||||
self._globalcontext = pickle.load(f)
|
||||
finally:
|
||||
f.close()
|
||||
return self._globalcontext
|
||||
|
||||
def get_document(self, docname, username='', moderator=False):
|
||||
"""Load and return a document from a pickle. The document will
|
||||
be a dict object which can be used to render a template::
|
||||
@@ -146,28 +162,35 @@ class WebSupport(object):
|
||||
* **relbar**: A div containing links to related documents
|
||||
* **title**: The title of the document
|
||||
* **css**: Links to css files used by Sphinx
|
||||
* **js**: Javascript containing comment options
|
||||
* **script**: Javascript containing comment options
|
||||
|
||||
This raises :class:`~sphinx.websupport.errors.DocumentNotFoundError`
|
||||
if a document matching `docname` is not found.
|
||||
|
||||
:param docname: the name of the document to load.
|
||||
"""
|
||||
infilename = path.join(self.datadir, 'pickles', docname + '.fpickle')
|
||||
docpath = path.join(self.datadir, 'pickles', docname)
|
||||
if path.isdir(docpath):
|
||||
infilename = docpath + '/index.fpickle'
|
||||
else:
|
||||
infilename = docpath + '.fpickle'
|
||||
|
||||
try:
|
||||
f = open(infilename, 'rb')
|
||||
except IOError:
|
||||
raise errors.DocumentNotFoundError(
|
||||
'The document "%s" could not be found' % docname)
|
||||
try:
|
||||
document = pickle.load(f)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
document = pickle.load(f)
|
||||
comment_opts = self._make_comment_options(username, moderator)
|
||||
comment_metadata = self.storage.get_metadata(docname, moderator)
|
||||
|
||||
document['js'] = '\n'.join([comment_opts,
|
||||
self._make_metadata(comment_metadata),
|
||||
document['js']])
|
||||
document['script'] = '\n'.join([comment_opts,
|
||||
self._make_metadata(comment_metadata),
|
||||
document['script']])
|
||||
return document
|
||||
|
||||
def get_search_results(self, q):
|
||||
@@ -181,9 +204,12 @@ class WebSupport(object):
|
||||
:param q: the search query
|
||||
"""
|
||||
results = self.search.query(q)
|
||||
ctx = {'search_performed': True,
|
||||
'search_results': results,
|
||||
'q': q}
|
||||
ctx = {
|
||||
'q': q,
|
||||
'search_performed': True,
|
||||
'search_results': results,
|
||||
'docroot': '../', # XXX
|
||||
}
|
||||
document = self.get_document('search')
|
||||
document['body'] = self.results_template.render(ctx)
|
||||
document['title'] = 'Search Results'
|
||||
@@ -359,17 +385,17 @@ class WebSupport(object):
|
||||
|
||||
if self.docroot != '':
|
||||
comment_urls = [
|
||||
('addCommentURL', 'add_comment'),
|
||||
('getCommentsURL', 'get_comments'),
|
||||
('processVoteURL', 'process_vote'),
|
||||
('acceptCommentURL', 'accept_comment'),
|
||||
('rejectCommentURL', 'reject_comment'),
|
||||
('deleteCommentURL', 'delete_comment')
|
||||
('addCommentURL', '_add_comment'),
|
||||
('getCommentsURL', '_get_comments'),
|
||||
('processVoteURL', '_process_vote'),
|
||||
('acceptCommentURL', '_accept_comment'),
|
||||
('rejectCommentURL', '_reject_comment'),
|
||||
('deleteCommentURL', '_delete_comment')
|
||||
]
|
||||
for key, value in comment_urls:
|
||||
self.base_comment_opts[key] = \
|
||||
'/' + posixpath.join(self.docroot, value)
|
||||
if self.staticdir != 'static':
|
||||
if self.staticroot != 'static':
|
||||
static_urls = [
|
||||
('commentImage', 'comment.png'),
|
||||
('closeCommentImage', 'comment-close.png'),
|
||||
@@ -382,7 +408,7 @@ class WebSupport(object):
|
||||
]
|
||||
for key, value in static_urls:
|
||||
self.base_comment_opts[key] = \
|
||||
'/' + posixpath.join(self.staticdir, '_static', value)
|
||||
'/' + posixpath.join(self.staticroot, '_static', value)
|
||||
|
||||
def _make_comment_options(self, username, moderator):
|
||||
"""Helper method to create the parts of the COMMENT_OPTIONS
|
||||
@@ -391,8 +417,6 @@ class WebSupport(object):
|
||||
:param username: The username of the user making the request.
|
||||
:param moderator: Whether the user making the request is a moderator.
|
||||
"""
|
||||
# XXX parts is not used?
|
||||
#parts = [self.base_comment_opts]
|
||||
rv = self.base_comment_opts.copy()
|
||||
if username:
|
||||
rv.update({
|
||||
|
||||
@@ -9,18 +9,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
__all__ = ['DocumentNotFoundError', 'SrcdirNotSpecifiedError',
|
||||
'UserNotAuthorizedError', 'CommentNotAllowedError',
|
||||
'NullSearchException']
|
||||
|
||||
class DocumentNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class SrcdirNotSpecifiedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UserNotAuthorizedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class WebSupportTranslator(HTMLTranslator):
|
||||
node.attributes['classes'].append(self.comment_class)
|
||||
|
||||
def add_db_node(self, node):
|
||||
storage = self.builder.app.storage
|
||||
storage = self.builder.storage
|
||||
if not storage.has_node(node.uid):
|
||||
storage.add_node(id=node.uid,
|
||||
document=self.builder.cur_docname,
|
||||
|
||||
@@ -65,7 +65,7 @@ class NullStorage(StorageBackend):
|
||||
@with_support(storage=NullStorage())
|
||||
def test_no_srcdir(support):
|
||||
"""Make sure the correct exception is raised if srcdir is not given."""
|
||||
raises(SrcdirNotSpecifiedError, support.build)
|
||||
raises(RuntimeError, support.build)
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
|
||||
Reference in New Issue
Block a user