diff -r 058bb3dc685f -r 0b59724cb3f2 cubicweb/web/views/wdoc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/web/views/wdoc.py Sat Jan 16 13:48:51 2016 +0100 @@ -0,0 +1,231 @@ +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of CubicWeb. +# +# CubicWeb is free software: you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) +# any later version. +# +# CubicWeb is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with CubicWeb. If not, see . +"""inline help system, rendering ReST files in the `wdoc` subdirectory of +CubicWeb and cubes + +""" +__docformat__ = "restructuredtext en" + +from itertools import chain +from os.path import join +from bisect import bisect_right +from datetime import date + +from logilab.common.changelog import ChangeLog +from logilab.common.date import strptime, todate +from logilab.common.registry import yes +from logilab.mtconverter import CHARSET_DECL_RGX + +from cubicweb.predicates import match_form_params +from cubicweb.view import StartupView +from cubicweb.uilib import rest_publish +from cubicweb.web import NotFound, action +from cubicweb import _ + +# table of content management ################################################# + +try: + from xml.etree.ElementTree import parse +except ImportError: + from elementtree.ElementTree import parse + +def build_toc_index(node, index): + try: + nodeidx = node.attrib['resource'] + assert not nodeidx in index, nodeidx + index[nodeidx] = node + except KeyError: + pass + for child in node: + build_toc_index(child, index) + child.parent = node + +def get_insertion_point(section, index): + if section.attrib.get('insertafter'): + snode = index[section.attrib['insertafter']] + node = snode.parent + idx = node.getchildren().index(snode) + 1 + elif section.attrib.get('insertbefore'): + snode = index[section.attrib['insertbefore']] + node = snode.parent + idx = node.getchildren().index(snode) + elif 'appendto' in section.attrib: + node = index[section.attrib['appendto']] + idx = None + else: + node, idx = None, None + return node, idx + +def build_toc(config): + alltocfiles = reversed(tuple(config.locate_all_files('toc.xml'))) + maintoc = parse(next(alltocfiles)).getroot() + maintoc.parent = None + index = {} + build_toc_index(maintoc, index) + # insert component documentation into the tree according to their toc.xml + # file + for fpath in alltocfiles: + toc = parse(fpath).getroot() + for section in toc: + node, idx = get_insertion_point(section, index) + if node is None: + continue + if idx is None: + node.append(section) + else: + node.insert(idx, section) + section.parent = node + build_toc_index(section, index) + return index + +def title_for_lang(node, lang): + fallback_title = None + for title in node.findall('title'): + title_lang = title.attrib['{http://www.w3.org/XML/1998/namespace}lang'] + if title_lang == lang: + return unicode(title.text) + if title_lang == 'en': + fallback_title = unicode(title.text) + return fallback_title + +def subsections(node): + return [child for child in node if child.tag == 'section'] + +# help views ################################################################## + +class InlineHelpView(StartupView): + __select__ = match_form_params('fid') + __regid__ = 'wdoc' + title = _('site documentation') + + def call(self): + fid = self._cw.form['fid'] + vreg = self._cw.vreg + for lang in chain((self._cw.lang, vreg.property_value('ui.language')), + vreg.config.available_languages()): + rid = '%s_%s.rst' % (fid, lang) + resourcedir = vreg.config.locate_doc_file(rid) + if resourcedir: + break + else: + raise NotFound + self.tocindex = build_toc(vreg.config) + try: + node = self.tocindex[fid] + except KeyError: + node = None + else: + self.navigation_links(node) + self.w(u'
') + self.w(u'

%s

' % (title_for_lang(node, self._cw.lang))) + data = open(join(resourcedir, rid)).read() + self.w(rest_publish(self, data)) + if node is not None: + self.subsections_links(node) + self.w(u'
') + self.navigation_links(node) + + def navigation_links(self, node): + req = self._cw + parent = node.parent + if parent is None: + return + brothers = subsections(parent) + self.w(u'
\n') + previousidx = brothers.index(node) - 1 + if previousidx >= 0: + self.navsection(brothers[previousidx], 'prev') + self.navsection(parent, 'up') + nextidx = brothers.index(node) + 1 + if nextidx < len(brothers): + self.navsection(brothers[nextidx], 'next') + self.w(u'
\n') + + navinfo = {'prev': ('', 'data/previous.png', _('i18nprevnext_previous')), + 'next': ('', 'data/next.png', _('i18nprevnext_next')), + 'up': ('', 'data/up.png', _('i18nprevnext_up'))} + + def navsection(self, node, navtype): + htmlclass, imgpath, msgid = self.navinfo[navtype] + self.w(u'' % htmlclass) + self.w(u'%s : ' % self._cw._(msgid)) + self.w(u'%s' % ( + self._cw.build_url('doc/'+node.attrib['resource']), + title_for_lang(node, self._cw.lang))) + self.w(u'\n') + + def subsections_links(self, node, first=True): + sub = subsections(node) + if not sub: + return + if first: + self.w(u'
') + self.w(u'\n') + + + +class InlineHelpImageView(StartupView): + __regid__ = 'wdocimages' + __select__ = match_form_params('fid') + binary = True + templatable = False + content_type = 'image/png' + + def call(self): + fid = self._cw.form['fid'] + for lang in chain((self._cw.lang, self._cw.vreg.property_value('ui.language')), + self._cw.vreg.config.available_languages()): + rid = join('images', '%s_%s.png' % (fid, lang)) + resourcedir = self._cw.vreg.config.locate_doc_file(rid) + if resourcedir: + break + else: + raise NotFound + self.w(open(join(resourcedir, rid)).read()) + + + +class HelpAction(action.Action): + __regid__ = 'help' + __select__ = yes() + + category = 'footer' + order = 0 + title = _('Help') + + def url(self): + return self._cw.build_url('doc/main') + + +class AboutAction(action.Action): + __regid__ = 'about' + __select__ = yes() + + category = 'footer' + order = 2 + title = _('About this site') + + def url(self): + return self._cw.build_url('doc/about')