19
23
def add_dict(newdict, curdict, plugin):
24
"""Deeply merge curdict into newdict."""
20
25
for key in curdict:
21
if key not in newdict:
23
26
if isinstance(curdict[key], dict):
27
if key not in newdict:
28
newdict[key] = HelpTree(newdict, key, {})
24
29
add_dict(newdict[key], curdict[key], plugin)
26
newdict[key] = os.path.join(plugin, curdict[key])
31
newdict[key] = HelpEntry(newdict, key, os.path.join(plugin, curdict[key]))
29
class HelpView(XHTMLView):
34
class HelpTreeView(XHTMLView):
30
38
"""Shows the help file for the specified path."""
39
def authorize(self, req):
40
return req.user is not None
42
def populate(self, req, ctx):
43
self.plugin_styles[Plugin] = ['help.css']
46
ctx['context'] = self.context
47
ctx['HelpTree'] = HelpTree
48
ctx['HelpEntry'] = HelpEntry
50
class HelpEntryView(XHTMLView):
32
52
template = 'helpview.html'
34
def __init__(self, req, path):
35
self.paths = path.split('/')
54
"""Shows the help file for the specified path."""
37
55
def authorize(self, req):
38
56
return req.user is not None
40
58
def populate(self, req, ctx):
41
59
self.plugin_styles[Plugin] = ['help.css']
43
helpfile = generate_toc(req.config.plugin_index[ViewPlugin], req)
45
for path in self.paths:
47
helpfile = helpfile[path]
48
except (KeyError, TypeError):
49
# Traversal failed. We 404.
52
if not isinstance(helpfile, basestring):
53
# It's a virtual directory.
56
ctx['helpfile'] = helpfile
59
class HelpToCView(XHTMLView):
60
"""Displays the help Table of Contents."""
64
def authorize(self, req):
65
return req.user is not None
67
def populate(self, req, ctx):
68
ctx['toc'] = generate_toc(req.config.plugin_index[ViewPlugin], req)
61
ctx['helpfile'] = self.context.file
64
def __init__(self, parent, name, tree):
65
super(HelpTree, self).__init__(tree)
69
class HelpEntry(object):
70
def __init__(self, parent, name, file):
75
@forward_route(ApplicationRoot, '+help')
76
def root_to_helptree(root):
77
return generate_toc(root.config.plugin_index[ViewPlugin])
79
@forward_route(HelpTree, argc=1)
80
def helptree_to_help(help, subhelp_name):
82
return help[subhelp_name]
84
# No help entry of that name
87
@reverse_route(HelpTree)
88
def helptree_url(helptree):
89
if helptree.parent is None:
90
return (ROOT, '+help')
91
return (helptree.parent, helptree.name)
93
@reverse_route(HelpEntry)
94
def helpentry_url(helpentry):
95
return (helpentry.parent, helpentry.name)
97
class HelpBreadcrumb(object):
98
def __init__(self, req, context):
100
self.context = context
104
return self.req.publisher.generate(self.context)
108
return self.context.name
110
class HelpTreeBreadcrumb(HelpBreadcrumb):
113
return dict((item.name, self.req.publisher.generate(item))
114
for item in self.context.values())
71
116
class Plugin(ViewPlugin, MediaPlugin):
72
117
"""The plugin for viewing help files."""
75
('+help', HelpToCView),
76
('+help/*path', HelpView)
118
forward_routes = (root_to_helptree, helptree_to_help)
119
reverse_routes = (helptree_url, helpentry_url)
121
views = [(HelpTree, '+index', HelpTreeView),
122
(HelpEntry, '+index', HelpEntryView)]
124
breadcrumbs = {HelpEntry: HelpBreadcrumb,
125
HelpTree: HelpTreeBreadcrumb,
80
129
('help', 'Help', 'Get help with IVLE', 'help.png', '+help', 100)