Commit a188c82e authored by kalman@chromium.org's avatar kalman@chromium.org

Docserver: Include <h4> tags in the table of contents, it's needed for the API

reference. Note that until the whole of bug 325555 is fixed the API reference
will still look wonky, and in fact this makes it look even wonkier.

BUG=325555
R=yoz@chromium.org
NOTRY=true

Review URL: https://codereview.chromium.org/103413002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238529 0039d316-1c4b-4281-b951-d872f2087c98
parent abcefa3e
application: chrome-apps-doc
version: 2-43-0
version: 2-44-0
runtime: python27
api_version: 1
threadsafe: false
......
......@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data.
url: /_cron
schedule: every 5 minutes
target: 2-43-0
target: 2-44-0
......@@ -93,7 +93,7 @@ def RemoveTitle(document):
return (document[:title_start] + document[title_end + 4:], None)
_HEADER_TAGS = ['h2', 'h3']
_HEADER_TAGS = ['h2', 'h3', 'h4']
class _DocumentParser(HTMLParser):
......@@ -139,8 +139,10 @@ class _DocumentParser(HTMLParser):
belongs_to = self._processing_section.structure
for header in _HEADER_TAGS[:_HEADER_TAGS.index(tag)]:
if len(belongs_to) == 0:
self._WarnWithPosition('Found <%s> without any preceding <%s>' %
(tag, header))
# TODO(kalman): Re-enable this warning once the reference pages have
# their references fixed.
#self._WarnWithPosition('Found <%s> without any preceding <%s>' %
# (tag, header))
break
belongs_to = belongs_to[-1].entries
belongs_to.append(self._processing_entry)
......
......@@ -36,10 +36,16 @@ But it should still show up in the TOC as though it were an h2.
The embedded h3 should be ignored.
<h4>It's a h4</h4>
h4 are not considered part of the document structure.
h4 are part of the document structure, but this is not inside a h3.
<h3>Plantains</h3>
Now I'm just getting lazy.
<h4>Another h4</h4>
This h4 is inside a h3 so will show up.
<h5>Header 5</h5>
Header 5s are not parsed.
'''
......@@ -71,10 +77,16 @@ But it should still show up in the TOC as though it were an h2.
The embedded h3 should be ignored.
<h4>It's a h4</h4>
h4 are not considered part of the document structure.
h4 are part of the document structure, but this is not inside a h3.
<h3>Plantains</h3>
Now I'm just getting lazy.
<h4>Another h4</h4>
This h4 is inside a h3 so will show up.
<h5>Header 5</h5>
Header 5s are not parsed.
'''
......@@ -144,6 +156,9 @@ class DocumentParserUnittest(unittest.TestCase):
'Found multiple <h1> tags. Subsequent <h1> tags will be classified as '
'<h2> for the purpose of the structure (line 22, column 1)',
'Found <h3> in the middle of processing a <h2> (line 25, column 9)',
# TODO(kalman): Re-enable this warning once the reference pages have
# their references fixed.
#'Found <h4> without any preceding <h3> (line 28, column 1)',
], result.warnings)
# The non-trivial table of contents assertions...
......@@ -179,13 +194,22 @@ class DocumentParserUnittest(unittest.TestCase):
self.assertEqual('Not a banana', entry4.name)
self.assertEqual({}, entry4.attributes)
self.assertEqual(1, len(entry4.entries))
entry4_1, = entry4.entries
self.assertEqual(2, len(entry4.entries))
entry4_1, entry4_2 = entry4.entries
self.assertEqual('Plantains', entry4_1.name)
self.assertEqual('It\'s a h4', entry4_1.name)
self.assertEqual({}, entry4_1.attributes)
self.assertEqual([], entry4_1.entries)
self.assertEqual('Plantains', entry4_2.name)
self.assertEqual({}, entry4_2.attributes)
self.assertEqual(1, len(entry4_2.entries))
entry4_2_1, = entry4_2.entries
self.assertEqual('Another h4', entry4_2_1.name)
self.assertEqual({}, entry4_2_1.attributes)
self.assertEqual([], entry4_2_1.entries)
def testSingleExplicitSection(self):
def test(document):
result = ParseDocument(document, expect_title=True)
......
......@@ -24,7 +24,6 @@ class IntroDataSource(DataSource):
'''
def __init__(self, server_instance, request):
self._template_renderer = server_instance.template_renderer
self._request = request
self._cache = server_instance.compiled_fs_factory.Create(
server_instance.host_file_system_provider.GetTrunk(),
......
......@@ -98,10 +98,13 @@ class RenderServlet(Servlet):
content = content_and_type.content
if isinstance(content, Handlebar):
template_content, template_warnings = (
server_instance.template_renderer.Render(content, self._request))
# HACK: the Google ID thing (google2ed...) doesn't have a title.
content, warnings = server_instance.document_renderer.Render(
server_instance.template_renderer.Render(content, self._request),
content, doc_warnings = server_instance.document_renderer.Render(
template_content,
render_title=path != 'google2ed1af765c529f57.html')
warnings = template_warnings + doc_warnings
if warnings:
sep = '\n - '
logging.warning('Rendering %s:%s%s' % (path, sep, sep.join(warnings)))
......
......@@ -67,10 +67,6 @@ class ServerInstance(object):
assert base_path.startswith('/') and base_path.endswith('/')
self.base_path = base_path
self.document_renderer = DocumentRenderer(TableOfContentsRenderer(
host_fs_at_trunk,
compiled_fs_factory))
self.host_file_system_iterator = HostFileSystemIterator(
host_file_system_provider,
branch_utility)
......@@ -153,6 +149,14 @@ class ServerInstance(object):
# the entire ServerInstance doesn't need to be passed in here.
self.template_renderer = TemplateRenderer(self)
# TODO(kalman): It may be better for |document_renderer| to construct a
# TemplateDataSource itself rather than depending on template_renderer, but
# for that the above todo should be addressed.
self.document_renderer = DocumentRenderer(TableOfContentsRenderer(
host_fs_at_trunk,
compiled_fs_factory,
self.template_renderer))
@staticmethod
def ForTest(file_system=None, file_system_provider=None, base_path='/'):
object_store_creator = ObjectStoreCreator.ForTest()
......
......@@ -14,8 +14,12 @@ class TableOfContentsRenderer(object):
class for testability.
'''
def __init__(self, host_file_system, compiled_fs_factory):
def __init__(self,
host_file_system,
compiled_fs_factory,
template_renderer):
self._templates = compiled_fs_factory.ForTemplates(host_file_system)
self._template_renderer = template_renderer
def Render(self, sections):
'''Renders a list of DocumentSections |sections| and returns a tuple
......@@ -43,7 +47,9 @@ class TableOfContentsRenderer(object):
items_for_section[0]['separator'] = True
toc_items.extend(items_for_section)
table_of_contents = table_of_contents_template.Render({
'items': toc_items
})
return table_of_contents.text, table_of_contents.errors
return self._template_renderer.Render(
self._templates.GetFromFile(
'%s/table_of_contents.html' % PRIVATE_TEMPLATES).Get(),
None, # no request
data_sources=('partials'),
additional_context={'items': toc_items})
......@@ -16,13 +16,18 @@ class TemplateRenderer(object):
def __init__(self, server_instance):
self._server_instance = server_instance
def Render(self, template, request, data_sources=None, warn=True):
def Render(self,
template,
request,
data_sources=None,
additional_context=None):
'''Renders |template| using |request|.
Specify |data_sources| to only include the DataSources with the given names
when rendering the template.
Specify |warn| whether to warn (e.g. logging.warning) if there are template
rendering errors. It may be useful to disable this when errors are expected,
for example when doing an initial page render to determine document title.
Specify |additional_context| to inject additional template context when
rendering the template.
'''
assert isinstance(template, Handlebar), type(template)
render_context = self._CreateDataSources(request)
......@@ -35,11 +40,10 @@ class TemplateRenderer(object):
'extensions_samples_url': EXTENSIONS_SAMPLES,
'static': self._server_instance.base_path + 'static',
})
if additional_context:
render_context.update(additional_context)
render_data = template.Render(render_context)
if warn and render_data.errors:
logging.error('Handlebar error(s) rendering %s:\n%s' %
(template._name, ' \n'.join(render_data.errors)))
return render_data.text
return render_data.text, render_data.errors
def _CreateDataSources(self, request):
server_instance = self._server_instance
......
......@@ -21,8 +21,9 @@ class TemplateRendererTest(unittest.TestCase):
def testSimpleWiring(self):
template = Handlebar('hello {{?true}}{{strings.extension}}{{/}}')
self.assertEqual('hello extension',
self._template_renderer.Render(template, None))
text, warnings = self._template_renderer.Render(template, None)
self.assertEqual('hello extension', text)
self.assertEqual([], warnings)
if __name__ == '__main__':
......
<div id="toc">
<ol>
{{#i:items}}
<li {{?i.separator}}class="separator"{{/}}>
<a href="#{{i.link}}">{{{i.title}}}</a>
{{?i.subheadings}}
<ol>
{{#sh:i.subheadings}}
<li><a href="#{{sh.link}}">{{{sh.title}}}</a></li>
{{/i.subheadings}}
</ol>
{{/i.subheadings}}
</li>
{{/items}}
</ol>
{{+partials.table_of_contents_items items:items /}}
</div>
<ol>
{{#i:items}}
<li {{?i.separator}}class="separator"{{/}}>
<a href="#{{i.link}}">{{{i.title}}}</a>
{{?i.subheadings +partials.table_of_contents_items items:i.subheadings /}}
</li>
{{/items}}
</ol>
<a href="#dom_events">DOM Events</a>
<ol>
{{#e:domEvents}}
<li><a href="#{{e.id}}">{{e.name}}</a></li>
{{/domEvents}}
</ol>
<a href="#{{?parentName}}{{parentName}}-{{/}}events">Events</a>
<ol>
{{#e:events}}
<li><a href="#{{e.id}}">{{e.name}}</a></li>
{{/events}}
</ol>
<a href="#{{?parentName}}{{parentName}}-{{/}}methods">Methods</a>
<ol>
{{#f:functions}}
<li><a href="#{{f.id}}">{{f.name}}</a></li>
{{/functions}}
</ol>
<a href="#{{?parentName}}{{parentName}}-{{/}}properties">Properties</a>
<ol>
{{#p:properties}}
<li>
<a href="#{{p.id}}">{{p.name}}</a>
{{?p.functions}}<ol><li>
{{+partials.toc_functions parentName:name functions:p.functions/}}
</li></ol>{{/p.functions}}
{{?p.events}}<ol><li>
{{+partials.toc_events parentName:p.name events:p.events/}}
</li></ol>{{/p.events}}
{{?p.properties}}<ol><li>
{{+partials.toc_properties parentName:p.name properties:p.properties/}}
</li></ol>{{/p.properties}}
</li>
{{/}}
</ol>
{{!types Types in the TOC}}
<a href="#{{?parentName}}{{parentName}}-{{/}}types">Types</a>
<ol>
{{#t:types}}
<li>
<a href="#{{t.id}}">{{t.name}}</a>
{{?t.functions}}<ol><li>
{{+partials.toc_functions parentName:t.name functions:t.functions/}}
</li></ol>{{/}}
{{?t.events}}<ol><li>
{{+partials.toc_events parentName:t.name events:t.events/}}
</li></ol>{{/t.events}}
</li>
{{/types}}
</ol>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment