1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
22 # Render HTML output looking for changes in the markdown sources.
25 if not root_section
.is_dirty
and not force_render
then return
26 var out_dir
= expand_path
(config
.root_dir
, config
.out_dir
)
29 root_section
.add_child make_sitemap
33 # Copy the asset directory to the (public) output directory.
34 private fun copy_assets
do
35 var src
= expand_path
(config
.root_dir
, config
.assets_dir
)
36 var out
= expand_path
(config
.root_dir
, config
.out_dir
)
37 if need_render
(src
, expand_path
(out
, config
.assets_dir
)) then
38 if src
.file_exists
then sys
.system
"cp -R {src} {out}"
42 # Build the wiki sitemap page.
43 private fun make_sitemap
: WikiSitemap do
44 var sitemap
= new WikiSitemap(self, "sitemap")
45 sitemap
.is_dirty
= true
52 # Url to `self` once generated.
53 fun url
: String do return wiki
.config
.root_url
.join_path
(breadcrumbs
.join
("/"))
55 # Get a `<a>` template link to `self`
56 fun tpl_link
: Writable do
57 return "<a href=\"{url}\
">{title}</a>"
61 redef class WikiSection
63 # Output directory (where to ouput the HTML pages for this section).
64 redef fun out_path
: String do
65 if parent
== null then
66 return wiki
.config
.out_dir
68 return wiki
.expand_path
(parent
.out_path
, name
)
73 if not is_dirty
and not wiki
.force_render
then return
77 sys
.system
"touch {out_full_path}"
80 wiki
.message
("Render section {out_path}", 1)
83 var index
= self.index
84 if index
isa WikiSectionIndex then
85 wiki
.message
("Render auto-index for section {out_path}", 1)
92 # Copy attached files from `src_path` to `out_path`.
93 private fun copy_files
do
95 var dir
= src_full_path
.to_s
96 for name
in dir
.files
do
97 if name
== wiki
.config_filename
then continue
98 if name
.has_suffix
(".md") then continue
99 if has_child
(name
) then continue
100 var src
= wiki
.expand_path
(dir
, name
)
101 var out
= wiki
.expand_path
(out_full_path
, name
)
102 if not wiki
.need_render
(src
, out
) then continue
103 sys
.system
"cp -R {src} {out_full_path}"
107 # The index page for this section.
109 # If no file `index.md` exists for this section,
110 # a summary is generated using contained articles.
111 var index
: WikiArticle is lazy
do
112 for child
in children
.values
do
113 if child
isa WikiArticle and child
.is_index
then return child
115 return new WikiSectionIndex(wiki
, "index", self)
118 redef fun tpl_link
do return index
.tpl_link
120 # Render the section hierarchy as a html tree.
122 # `limit` is used to specify the max-depth of the tree.
124 # The generated tree will be something like this:
131 # <li>section 2.1</li>
132 # <li>section 2.2</li>
137 fun tpl_tree
(limit
: Int): Template do
138 return tpl_tree_intern
(limit
, 1)
141 # Build the template tree for this section recursively.
142 protected fun tpl_tree_intern
(limit
, count
: Int): Template do
143 var out
= new Template
147 if (limit
< 0 or count
< limit
) and
148 (children
.length
> 1 or (children
.length
== 1)) then
150 for child
in children
.values
do
151 if child
== index
then continue
152 if child
isa WikiArticle then
154 out
.add child
.tpl_link
156 else if child
isa WikiSection and not child
.is_hidden
then
157 out
.add child
.tpl_tree_intern
(limit
, count
+ 1)
167 redef class WikiArticle
169 redef fun out_path
: String do
170 if parent
== null then
171 return wiki
.expand_path
(wiki
.config
.out_dir
, "{name}.html")
173 return wiki
.expand_path
(parent
.out_path
, "{name}.html")
178 if parent
== null then
179 return wiki
.config
.root_url
.join_path
("{name}.html")
181 return parent
.url
.join_path
("{name}.html")
185 # Is `self` an index page?
187 # Checks if `self.name == "index"`.
188 fun is_index
: Bool do return name
== "index"
191 if not is_dirty
and not wiki
.force_render
then return
192 wiki
.message
("Render article {name}", 2)
193 var file
= out_full_path
195 tpl_page
.write_to_file file
200 # Replace macros in the template by wiki data.
201 private fun tpl_page
: TemplateString do
202 var tpl
= wiki
.load_template
(template_file
)
203 if tpl
.has_macro
("TOP_MENU") then
204 tpl
.replace
("TOP_MENU", tpl_menu
)
206 if tpl
.has_macro
("HEADER") then
207 tpl
.replace
("HEADER", tpl_header
)
209 if tpl
.has_macro
("BODY") then
210 tpl
.replace
("BODY", tpl_article
)
212 if tpl
.has_macro
("FOOTER") then
213 tpl
.replace
("FOOTER", tpl_footer
)
218 # Generate the HTML header for this article.
219 fun tpl_header
: Writable do
220 var file
= header_file
221 if not wiki
.has_template
(file
) then return ""
222 return wiki
.load_template
(file
)
225 # Generate the HTML page for this article.
226 fun tpl_article
: TplArticle do
227 var article
= new TplArticle
228 article
.body
= content
229 article
.breadcrumbs
= new TplBreadcrumbs(self)
230 tpl_sidebar
.blocks
.add tpl_summary
231 article
.sidebar
= tpl_sidebar
235 # Sidebar for this page.
236 var tpl_sidebar
= new TplSidebar
238 # Generate the HTML summary for this article.
240 # Based on `headlines`
241 fun tpl_summary
: Writable do
242 var headlines
= self.headlines
243 var tpl
= new Template
244 tpl
.add
"<ul class=\"summary list-unstyled\
">"
245 var iter
= headlines
.iterator
248 # parse title as markdown
249 var title
= hl
.title
.md_to_html
.to_s
250 title
= title
.substring
(3, title
.length
- 8)
251 tpl
.add
"<li><a href=\"#{hl.id}\">{title}</a>"
254 if iter
.item
.level
> hl
.level
then
255 tpl
.add
"<ul class=\"list-unstyled\
">"
256 else if iter
.item
.level
< hl
.level
then
268 # Generate the HTML menu for this article.
269 fun tpl_menu
: Writable do
271 if not wiki
.has_template
(file
) then return ""
272 var tpl
= wiki
.load_template
(file
)
273 if tpl
.has_macro
("MENUS") then
274 var items
= new Template
275 for child
in wiki
.root_section
.children
.values
do
276 if child
isa WikiArticle and child
.is_index
then continue
277 if child
isa WikiSection and child
.is_hidden
then continue
279 if self == child
or self.breadcrumbs
.has
(child
) then
280 items
.add
" class=\"active\
""
283 items
.add child
.tpl_link
286 tpl
.replace
("MENUS", items
)
291 # Generate the HTML footer for this article.
292 fun tpl_footer
: Writable do
293 var file
= footer_file
294 if not wiki
.has_template
(file
) then return ""
295 var tpl
= wiki
.load_template
(file
)
296 var time
= new Tm.gmtime
297 if tpl
.has_macro
("YEAR") then
298 tpl
.replace
("YEAR", (time
.year
+ 1900).to_s
)
300 if tpl
.has_macro
("GEN_TIME") then
301 tpl
.replace
("GEN_TIME", time
.to_s
)
307 # A `WikiArticle` that contains the sitemap tree.
311 redef fun tpl_article
do
312 var article
= new TplArticle.with_title
("Sitemap")
313 article
.body
= new TplPageTree(wiki
.root_section
, -1)
317 redef var is_dirty
= false
320 # A `WikiArticle` that contains the section index tree.
321 class WikiSectionIndex
324 # The section described by `self`.
325 var section
: WikiSection
327 redef fun title
do return section
.title
329 redef fun url
do return section
.url
331 redef var is_dirty
= false
333 redef fun tpl_article
do
334 var article
= new TplArticle.with_title
(section
.title
)
335 article
.body
= new TplPageTree(section
, -1)
336 article
.breadcrumbs
= new TplBreadcrumbs(self)
341 # Article HTML output.
346 var title
: nullable Writable = null
349 var body
: nullable Writable = null
351 # Sidebar of this article (if any).
352 var sidebar
: nullable TplSidebar = null
354 # Breadcrumbs from wiki root to this article.
355 var breadcrumbs
: nullable TplBreadcrumbs = null
357 # Init `self` with a `title`.
358 init with_title
(title
: Writable) do
362 redef fun rendering
do
363 if sidebar
!= null then
364 add
"<div class=\"col-sm-3 sidebar\
">"
365 add sidebar
.as(not null)
367 add
"<div class=\"col-sm-9 content\
">"
369 add
"<div class=\"col-sm-12 content\
">"
373 if breadcrumbs
!= null then
374 add breadcrumbs
.as(not null)
376 if title
!= null then
378 add title
.as(not null)
381 add body
.as(not null)
388 # A collection of HTML blocks displayed on the side of a page.
392 # Blocks are `Stremable` pieces that will be rendered in the sidebar.
393 var blocks
= new Array[Writable]
395 redef fun rendering
do
396 for block
in blocks
do
397 add
"<div class=\"sideblock\
">"
404 # An HTML breadcrumbs that show the path from a `WikiArticle` to the `Nitiwiki` root.
408 # Bread crumb article.
409 var article
: WikiArticle
411 redef fun rendering
do
412 var path
= article
.breadcrumbs
413 if path
.is_empty
or path
.length
<= 2 and article
.is_index
then return
414 add
"<ol class=\"breadcrumb\
">"
416 if entry
== path
.last
then
417 add
"<li class=\"active\
">"
421 if article
.parent
== entry
and article
.is_index
then continue
431 # An HTML tree that show the section pages structure.
435 # Builds the page tree from `root`.
436 var root
: WikiSection
438 # Limits the tree depth to `max_depth` levels.
441 redef fun rendering
do
443 add root
.tpl_tree
(-1)