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 application: chrome-apps-doc
version: 2-43-0 version: 2-44-0
runtime: python27 runtime: python27
api_version: 1 api_version: 1
threadsafe: false threadsafe: false
......
...@@ -2,4 +2,4 @@ cron: ...@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data. - description: Repopulates all cached data.
url: /_cron url: /_cron
schedule: every 5 minutes schedule: every 5 minutes
target: 2-43-0 target: 2-44-0
...@@ -93,7 +93,7 @@ def RemoveTitle(document): ...@@ -93,7 +93,7 @@ def RemoveTitle(document):
return (document[:title_start] + document[title_end + 4:], None) return (document[:title_start] + document[title_end + 4:], None)
_HEADER_TAGS = ['h2', 'h3'] _HEADER_TAGS = ['h2', 'h3', 'h4']
class _DocumentParser(HTMLParser): class _DocumentParser(HTMLParser):
...@@ -139,8 +139,10 @@ class _DocumentParser(HTMLParser): ...@@ -139,8 +139,10 @@ class _DocumentParser(HTMLParser):
belongs_to = self._processing_section.structure belongs_to = self._processing_section.structure
for header in _HEADER_TAGS[:_HEADER_TAGS.index(tag)]: for header in _HEADER_TAGS[:_HEADER_TAGS.index(tag)]:
if len(belongs_to) == 0: if len(belongs_to) == 0:
self._WarnWithPosition('Found <%s> without any preceding <%s>' % # TODO(kalman): Re-enable this warning once the reference pages have
(tag, header)) # their references fixed.
#self._WarnWithPosition('Found <%s> without any preceding <%s>' %
# (tag, header))
break break
belongs_to = belongs_to[-1].entries belongs_to = belongs_to[-1].entries
belongs_to.append(self._processing_entry) 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. ...@@ -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. The embedded h3 should be ignored.
<h4>It's a h4</h4> <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> <h3>Plantains</h3>
Now I'm just getting lazy. 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. ...@@ -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. The embedded h3 should be ignored.
<h4>It's a h4</h4> <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> <h3>Plantains</h3>
Now I'm just getting lazy. 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): ...@@ -144,6 +156,9 @@ class DocumentParserUnittest(unittest.TestCase):
'Found multiple <h1> tags. Subsequent <h1> tags will be classified as ' 'Found multiple <h1> tags. Subsequent <h1> tags will be classified as '
'<h2> for the purpose of the structure (line 22, column 1)', '<h2> for the purpose of the structure (line 22, column 1)',
'Found <h3> in the middle of processing a <h2> (line 25, column 9)', '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) ], result.warnings)
# The non-trivial table of contents assertions... # The non-trivial table of contents assertions...
...@@ -179,13 +194,22 @@ class DocumentParserUnittest(unittest.TestCase): ...@@ -179,13 +194,22 @@ class DocumentParserUnittest(unittest.TestCase):
self.assertEqual('Not a banana', entry4.name) self.assertEqual('Not a banana', entry4.name)
self.assertEqual({}, entry4.attributes) self.assertEqual({}, entry4.attributes)
self.assertEqual(1, len(entry4.entries)) self.assertEqual(2, len(entry4.entries))
entry4_1, = 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.attributes)
self.assertEqual([], entry4_1.entries) 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 testSingleExplicitSection(self):
def test(document): def test(document):
result = ParseDocument(document, expect_title=True) result = ParseDocument(document, expect_title=True)
......
...@@ -24,7 +24,6 @@ class IntroDataSource(DataSource): ...@@ -24,7 +24,6 @@ class IntroDataSource(DataSource):
''' '''
def __init__(self, server_instance, request): def __init__(self, server_instance, request):
self._template_renderer = server_instance.template_renderer
self._request = request self._request = request
self._cache = server_instance.compiled_fs_factory.Create( self._cache = server_instance.compiled_fs_factory.Create(
server_instance.host_file_system_provider.GetTrunk(), server_instance.host_file_system_provider.GetTrunk(),
......
...@@ -98,10 +98,13 @@ class RenderServlet(Servlet): ...@@ -98,10 +98,13 @@ class RenderServlet(Servlet):
content = content_and_type.content content = content_and_type.content
if isinstance(content, Handlebar): 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. # HACK: the Google ID thing (google2ed...) doesn't have a title.
content, warnings = server_instance.document_renderer.Render( content, doc_warnings = server_instance.document_renderer.Render(
server_instance.template_renderer.Render(content, self._request), template_content,
render_title=path != 'google2ed1af765c529f57.html') render_title=path != 'google2ed1af765c529f57.html')
warnings = template_warnings + doc_warnings
if warnings: if warnings:
sep = '\n - ' sep = '\n - '
logging.warning('Rendering %s:%s%s' % (path, sep, sep.join(warnings))) logging.warning('Rendering %s:%s%s' % (path, sep, sep.join(warnings)))
......
...@@ -67,10 +67,6 @@ class ServerInstance(object): ...@@ -67,10 +67,6 @@ class ServerInstance(object):
assert base_path.startswith('/') and base_path.endswith('/') assert base_path.startswith('/') and base_path.endswith('/')
self.base_path = base_path self.base_path = base_path
self.document_renderer = DocumentRenderer(TableOfContentsRenderer(
host_fs_at_trunk,
compiled_fs_factory))
self.host_file_system_iterator = HostFileSystemIterator( self.host_file_system_iterator = HostFileSystemIterator(
host_file_system_provider, host_file_system_provider,
branch_utility) branch_utility)
...@@ -153,6 +149,14 @@ class ServerInstance(object): ...@@ -153,6 +149,14 @@ class ServerInstance(object):
# the entire ServerInstance doesn't need to be passed in here. # the entire ServerInstance doesn't need to be passed in here.
self.template_renderer = TemplateRenderer(self) 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 @staticmethod
def ForTest(file_system=None, file_system_provider=None, base_path='/'): def ForTest(file_system=None, file_system_provider=None, base_path='/'):
object_store_creator = ObjectStoreCreator.ForTest() object_store_creator = ObjectStoreCreator.ForTest()
......
...@@ -14,8 +14,12 @@ class TableOfContentsRenderer(object): ...@@ -14,8 +14,12 @@ class TableOfContentsRenderer(object):
class for testability. 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._templates = compiled_fs_factory.ForTemplates(host_file_system)
self._template_renderer = template_renderer
def Render(self, sections): def Render(self, sections):
'''Renders a list of DocumentSections |sections| and returns a tuple '''Renders a list of DocumentSections |sections| and returns a tuple
...@@ -43,7 +47,9 @@ class TableOfContentsRenderer(object): ...@@ -43,7 +47,9 @@ class TableOfContentsRenderer(object):
items_for_section[0]['separator'] = True items_for_section[0]['separator'] = True
toc_items.extend(items_for_section) toc_items.extend(items_for_section)
table_of_contents = table_of_contents_template.Render({ return self._template_renderer.Render(
'items': toc_items self._templates.GetFromFile(
}) '%s/table_of_contents.html' % PRIVATE_TEMPLATES).Get(),
return table_of_contents.text, table_of_contents.errors None, # no request
data_sources=('partials'),
additional_context={'items': toc_items})
...@@ -16,13 +16,18 @@ class TemplateRenderer(object): ...@@ -16,13 +16,18 @@ class TemplateRenderer(object):
def __init__(self, server_instance): def __init__(self, server_instance):
self._server_instance = 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|. '''Renders |template| using |request|.
Specify |data_sources| to only include the DataSources with the given names Specify |data_sources| to only include the DataSources with the given names
when rendering the template. 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, Specify |additional_context| to inject additional template context when
for example when doing an initial page render to determine document title. rendering the template.
''' '''
assert isinstance(template, Handlebar), type(template) assert isinstance(template, Handlebar), type(template)
render_context = self._CreateDataSources(request) render_context = self._CreateDataSources(request)
...@@ -35,11 +40,10 @@ class TemplateRenderer(object): ...@@ -35,11 +40,10 @@ class TemplateRenderer(object):
'extensions_samples_url': EXTENSIONS_SAMPLES, 'extensions_samples_url': EXTENSIONS_SAMPLES,
'static': self._server_instance.base_path + 'static', 'static': self._server_instance.base_path + 'static',
}) })
if additional_context:
render_context.update(additional_context)
render_data = template.Render(render_context) render_data = template.Render(render_context)
if warn and render_data.errors: return render_data.text, render_data.errors
logging.error('Handlebar error(s) rendering %s:\n%s' %
(template._name, ' \n'.join(render_data.errors)))
return render_data.text
def _CreateDataSources(self, request): def _CreateDataSources(self, request):
server_instance = self._server_instance server_instance = self._server_instance
......
...@@ -21,8 +21,9 @@ class TemplateRendererTest(unittest.TestCase): ...@@ -21,8 +21,9 @@ class TemplateRendererTest(unittest.TestCase):
def testSimpleWiring(self): def testSimpleWiring(self):
template = Handlebar('hello {{?true}}{{strings.extension}}{{/}}') template = Handlebar('hello {{?true}}{{strings.extension}}{{/}}')
self.assertEqual('hello extension', text, warnings = self._template_renderer.Render(template, None)
self._template_renderer.Render(template, None)) self.assertEqual('hello extension', text)
self.assertEqual([], warnings)
if __name__ == '__main__': if __name__ == '__main__':
......
<div id="toc"> <div id="toc">
<ol> {{+partials.table_of_contents_items items:items /}}
{{#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>
</div> </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