src/doc: introduce DocComposite HTML rendering services
[nit.git] / src / doc / html_templates / html_templates.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Introduces templates that compose the documentation HTML rendering.
16 module html_templates
17
18 import html_model
19 import html::bootstrap
20
21 # Renders the page as HTML.
22 redef class DocPage
23 super Template
24
25 # Page url.
26 var html_url: String is writable, noinit
27
28 # Directory where css, js and other assets can be found.
29 var shareurl: String is writable, noinit
30
31 # Attributes of the body tag element.
32 var body_attrs = new Array[TagAttribute]
33
34 # Top menu template if any.
35 var topmenu: DocTopMenu is writable, noinit
36
37 # Sidebar template if any.
38 var sidebar: nullable TplSidebar = null is writable
39
40 # Content of the page in form a TplSection.
41 # TODO remove when other templates are migrated.
42 var sections = new Array[TplSection]
43
44 # Footer content if any.
45 var footer: nullable Writable = null is writable
46
47 # JS scripts to append at the end of the body
48 var scripts = new Array[TplScript]
49
50 # Adds a section to this page.
51 # TODO remove when other templates are migrated.
52 fun add_section(section: TplSection) do
53 sections.add section
54 end
55
56 # Renders the html `<head>`.
57 private fun render_head do
58 var css = (self.shareurl / "css").html_escape
59 var vendors = (self.shareurl / "vendors").html_escape
60
61 addn "<!DOCTYPE html>"
62 addn "<head>"
63 addn " <meta charset='utf-8'/>"
64 addn " <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
65 addn " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
66 addn " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
67 addn " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
68 addn " <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
69 addn " <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
70 addn " <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
71 addn " <title>{title.html_escape}</title>"
72 addn "</head>"
73 add "<body"
74 for attr in body_attrs do add attr
75 addn ">"
76 end
77
78 # Renders the sidebar template.
79 #
80 # Sidebar is automatically populated with a summary of all sections
81 # TODO remove summary generation when other templates are migrated.
82 private fun render_sidebar do
83 if sidebar == null then return
84 var summary = new TplSummary.with_order(0)
85 for section in sections do
86 section.render_summary summary
87 end
88 sidebar.boxes.add summary
89 add sidebar.as(not null)
90 end
91
92 # Renders the footer and content.
93 private fun render_content do
94 for section in sections do add section
95 if footer != null then
96 addn "<div class='well footer'>"
97 add footer.as(not null)
98 addn "</div>"
99 end
100 end
101
102 # Render JS scripts
103 private fun render_footer do
104 var vendors = (self.shareurl / "vendors").html_escape
105 var js = (self.shareurl / "js").html_escape
106
107 addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
108 addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
109 addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
110 addn "<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
111 for script in scripts do add script
112 addn """<script>
113 $(function () {
114 $("[data-toggle='tooltip']").tooltip();
115 $("[data-toggle='popover']").popover();
116 });
117 </script>"""
118 addn "</body>"
119 addn "</html>"
120 end
121
122 # Render the whole page
123 redef fun rendering do
124 render_head
125 addn "<div class='container-fluid'>"
126 addn " <div class='row'>"
127 add topmenu
128 addn " </div>"
129 addn " <div class='row' id='content'>"
130 if sidebar != null then
131 addn "<div class='col col-xs-3 col-lg-2'>"
132 render_sidebar
133 addn "</div>"
134 addn "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
135 render_content
136 addn "</div>"
137 else
138 addn "<div class='col col-xs-12'>"
139 render_content
140 addn "</div>"
141 end
142 addn " </div>"
143 addn "</div>"
144 render_footer
145 end
146 end
147
148 # Top menu bar template.
149 #
150 # FIXME should be a Bootstrap component template
151 # At this moment, the topmenu structure stills to specific to Nitdoc to use the
152 # generic component.
153 class DocTopMenu
154 super UnorderedList
155
156 # Brand link to display in first position of the top menu.
157 #
158 # This is where you want to put your logo.
159 var brand: nullable Writable is noinit, writable
160
161 # Active menu item.
162 #
163 # Depends on the current page, this allows to hilighted the current item.
164 #
165 # FIXME should be using Boostrap breadcrumbs component.
166 # This will still like this to avoid diff and be changed in further fixes
167 # when we will modify the output.
168 var active_item: nullable ListItem is noinit, writable
169
170 redef fun rendering do
171 addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
172 addn " <div class='container-fluid'>"
173 addn " <div class='navbar-header'>"
174 add " <button type='button' class='navbar-toggle' "
175 addn " data-toggle='collapse' data-target='#topmenu-collapse'>"
176 addn " <span class='sr-only'>Toggle menu</span>"
177 addn " <span class='icon-bar'></span>"
178 addn " <span class='icon-bar'></span>"
179 addn " <span class='icon-bar'></span>"
180 addn " </button>"
181 if brand != null then
182 add "<span class='navbar-brand'>"
183 add brand.write_to_string
184 add "</span>"
185 end
186 addn " </div>"
187 addn " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
188 addn " <ul class='nav navbar-nav'>"
189 for item in items do
190 if item == active_item then item.css_classes.add "active"
191 add item.write_to_string
192 end
193 addn " </ul>"
194 addn " </div>"
195 addn " </div>"
196 addn "</nav>"
197 end
198 end
199
200 redef class DocComposite
201 super Template
202
203 # HTML anchor id
204 var html_id: String is noinit
205
206 # Title to display if any.
207 #
208 # This title can be decorated with HTML.
209 var html_title: nullable Writable is noinit, writable
210
211 # Subtitle to display if any.
212 var html_subtitle: nullable Writable is noinit, writable
213
214 # Render the element title and subtitle.
215 private fun render_title do
216 if html_title != null then
217 addn new Header(hlvl, html_title.write_to_string)
218 end
219 if html_subtitle != null then
220 addn "<div class='info subtitle'>"
221 addn html_subtitle.write_to_string
222 addn "</div>"
223 end
224 end
225
226 # Render the element body.
227 private fun render_body do end
228
229 redef fun rendering do
230 if is_hidden then return
231 render_title
232 render_body
233 end
234
235 # Level <hX> for HTML heading.
236 private fun hlvl: Int do
237 if parent == null then return 1
238 return parent.hlvl + 1
239 end
240
241 # Is `self` not displayed in the page.
242 #
243 # By default, empty elements are hidden.
244 fun is_hidden: Bool do return is_empty
245 end
246
247 redef class DocSection
248 super BSComponent
249
250 redef fun rendering do
251 if is_hidden then
252 addn "<a id=\"{html_id}\"></a>"
253 return
254 end
255 render_body
256 end
257 end
258
259 redef class DocArticle
260 super BSComponent
261
262 # Never displays the title for article.
263 #
264 # This is to maintain compatibility with old components, this may change
265 # without notice in further version.
266 redef fun render_title do end
267 end