1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
7 from document_parser
import ParseDocument
8 from platform_util
import ExtractPlatformFromURL
9 from third_party
.json_schema_compiler
.model
import UnixName
12 class DocumentRenderer(object):
13 '''Performs document-level rendering such as the title, references,
14 and table of contents: pulling that data out of the document, then
15 replacing the $(title), $(ref:...) and $(table_of_contents) tokens with them.
17 This can be thought of as a parallel to TemplateRenderer; while
18 TemplateRenderer is responsible for interpreting templates and rendering files
19 within the template engine, DocumentRenderer is responsible for interpreting
20 higher-level document concepts like the title and TOC, then performing string
21 replacement for them. The syntax for this replacement is $(...) where ... is
22 the concept. Currently title and table_of_contents are supported.
25 def __init__(self
, table_of_contents_renderer
, platform_bundle
):
26 self
._table
_of
_contents
_renderer
= table_of_contents_renderer
27 self
._platform
_bundle
= platform_bundle
29 def _RenderLinks(self
, document
, path
):
30 ''' Replaces all $(ref:...) references in |document| with html links.
32 References have two forms:
34 $(ref:api.node) - Replaces the reference with a link to node on the
35 API page. The title is set to the name of the node.
37 $(ref:api.node Title) - Same as the previous form, but title is set
46 # Keeps track of position within |document|
48 start_ref_index
= document
.find(START_REF
)
50 while start_ref_index
!= -1:
51 end_ref_index
= document
.find(END_REF
, start_ref_index
)
53 if (end_ref_index
== -1 or
54 end_ref_index
- start_ref_index
> MAX_REF_LENGTH
):
55 end_ref_index
= document
.find(' ', start_ref_index
)
56 logging
.error('%s:%s has no terminating ) at line %s' % (
58 document
[start_ref_index
:end_ref_index
],
59 document
.count('\n', 0, end_ref_index
)))
61 new_document
.append(document
[cursor_index
:end_ref_index
+ 1])
63 ref
= document
[start_ref_index
:end_ref_index
]
64 ref_parts
= ref
[len(START_REF
):].split(None, 1)
66 # Guess the api name from the html name, replacing '_' with '.' (e.g.
67 # if the page is app_window.html, guess the api name is app.window)
68 api_name
= os
.path
.splitext(os
.path
.basename(path
))[0].replace('_', '.')
69 title
= ref_parts
[0] if len(ref_parts
) == 1 else ref_parts
[1]
71 platform
= ExtractPlatformFromURL(path
)
73 logging
.error('Cannot resolve reference without a platform.')
75 ref_dict
= self
._platform
_bundle
.GetReferenceResolver(
76 platform
).SafeGetLink(ref_parts
[0],
81 new_document
.append(document
[cursor_index
:start_ref_index
])
82 new_document
.append('<a href=%s/%s>%s</a>' % (
83 self
._platform
_bundle
._base
_path
+ platform
,
87 cursor_index
= end_ref_index
+ 1
88 start_ref_index
= document
.find(START_REF
, cursor_index
)
90 new_document
.append(document
[cursor_index
:])
92 return ''.join(new_document
)
94 def Render(self
, document
, path
, render_title
=False):
95 ''' |document|: document to be rendered.
96 |path|: request path to the document.
97 |render_title|: boolean representing whether or not to render a title.
99 # Render links first so that parsing and later replacements aren't
100 # affected by $(ref...) substitutions
101 document
= self
._RenderLinks
(document
, path
)
103 parsed_document
= ParseDocument(document
, expect_title
=render_title
)
104 toc_text
, toc_warnings
= self
._table
_of
_contents
_renderer
.Render(
105 parsed_document
.sections
)
107 # Only 1 title and 1 table of contents substitution allowed; in the common
108 # case, save necessarily running over the entire file.
109 if parsed_document
.title
:
110 document
= document
.replace('$(title)', parsed_document
.title
, 1)
111 return (document
.replace('$(table_of_contents)', toc_text
, 1),
112 parsed_document
.warnings
+ toc_warnings
)