nitdoc: Escape attributes.
[nit.git] / src / doc / doc_templates.nit
index 200e650..353ecdf 100644 (file)
@@ -17,6 +17,7 @@
 module doc_templates
 
 import template
+import json::static
 
 # A documentation page
 class TplPage
@@ -49,8 +50,6 @@ class TplPage
        # JS scripts to append at the end of the body
        var scripts = new Array[TplScript]
 
-       init do end
-
        # Add a section to this page
        fun add_section(section: TplSection) do
                sections.add section
@@ -58,16 +57,19 @@ class TplPage
 
        # Render the html header
        private fun render_head do
+               var css = (self.shareurl / "css").html_escape
+               var vendors = (self.shareurl / "vendors").html_escape
+
                add "<!DOCTYPE html>"
                add "<head>"
                add " <meta charset='utf-8'/>"
-               add " <!--link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css'/-->"
-               add " <link rel='stylesheet' href='{shareurl}/vendors/bootstrap/css/bootstrap.min.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.bootstrap.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css'/>"
-               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css'/>"
+               add " <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
+               add " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
+               add " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
+               add " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
+               add " <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
+               add " <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
+               add " <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
                add " <title>{title}</title>"
                add "</head>"
                add "<body"
@@ -105,10 +107,13 @@ class TplPage
 
        # Render JS scripts
        private fun render_footer do
-               add "<script src='{shareurl}/vendors/jquery/jquery-1.11.1.min.js'></script>"
-               add "<script src='{shareurl}/vendors/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
-               add "<script src='{shareurl}/vendors/bootstrap/js/bootstrap.min.js'></script>"
-               add "<script data-main='{shareurl}/js/nitdoc' src='{shareurl}/js/lib/require.js'></script>"
+               var vendors = (self.shareurl / "vendors").html_escape
+               var js = (self.shareurl / "js").html_escape
+
+               add "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
+               add "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
+               add "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
+               add "<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
                for script in scripts do add script
                add """<script>
                        $(function () {
@@ -162,10 +167,6 @@ class TplTopMenu
        # Used to select the active link.
        private var current_url: String
 
-       init(current_url: String) do
-               self.current_url = current_url
-       end
-
        # Add a new link to the menu.
        fun add_link(content: TplLink) do
                var is_active = content.href == current_url
@@ -240,7 +241,9 @@ end
 
 # Comparator used to sort boxes by order
 private class OrderComparator
-       super Comparator[TplSidebarElt]
+       super Comparator
+
+       redef type COMPARED: TplSidebarElt
 
        redef fun compare(a, b) do
                if a.order < b.order then return -1
@@ -270,18 +273,17 @@ class TplSideBox
        # Box HTML id
        # equals to `title.to_cmangle` by default
        # Used for collapsing
-       var id: String
+       var id: String is noinit
 
        # Content to display in the box
        # box will not be rendered if the content is null
-       var content: nullable Streamable is writable
+       var content: nullable Streamable = null is writable
 
        # Is the box opened by default
        # otherwise, the user will have to clic on the title to display the content
        var is_open = false is writable
 
-       init(title: String) do
-               self.title = title
+       init do
                self.id = title.to_cmangle
        end
 
@@ -356,8 +358,6 @@ class TplSummaryEntry
        # Will be displayed as a tree
        var children = new Array[TplSummaryElt]
 
-       init(text: Streamable) do self.text = text
-
        redef fun add_child(child) do children.add child
 
        redef fun rendering do
@@ -383,14 +383,14 @@ class TplSectionElt
        # Title to display if any
        # if both `title` and `summary_title` are null then
        # the section will not appear in the summary
-       var title: nullable Streamable is writable
+       var title: nullable Streamable = null is writable
 
        # Subtitle to display if any
-       var subtitle: nullable Streamable is writable
+       var subtitle: nullable Streamable = null is writable
 
        # Title that appear in the summary
        # if null use `title` instead
-       var summary_title: nullable String is writable
+       var summary_title: nullable String = null is writable
 
        # CSS classes to apply on the section element
        var css_classes = new Array[String]
@@ -399,9 +399,7 @@ class TplSectionElt
        var title_classes = new Array[String]
 
        # Parent article/section if any
-       var parent: nullable TplSectionElt
-
-       init(id: String) do self.id = id
+       var parent: nullable TplSectionElt = null
 
        init with_title(id: String, title: Streamable) do
                init(id)
@@ -582,7 +580,7 @@ class TplClassDefinition
 
        private fun render_list(name: String, elts: Array[TplListElt]) do
                if elts.is_empty then return
-               add "<h5>{name}</h5>"
+               add "<h5>{name.html_escape}</h5>"
                add "<ul class='list-unstyled list-definition'>"
                for elt in elts do add elt
                add "</ul>"
@@ -599,7 +597,7 @@ class TplSearchPage
 
        redef fun rendering do
                var title = self.title
-               if title != null then add "<h1>{title}</h1>"
+               if title != null then add "<h1>{title.to_s.html_escape}</h1>"
                add "<div class='container-fluid'>"
                add " <div class='row'>"
                if not modules.is_empty then
@@ -658,12 +656,7 @@ class TplLink
        var text: Streamable is writable
 
        # Optional title
-       var title: nullable String is writable
-
-       init(href, text: String) do
-               self.href = href
-               self.text = text
-       end
+       var title: nullable String = null is writable
 
        init with_title(href, text, title: String) do
                init(href, text)
@@ -778,7 +771,7 @@ class TplTabPanel
        # The panel id.
        #
        # Used to show/hide panel.
-       var id: String
+       var id: String is noinit
 
        # The panel name.
        #
@@ -848,23 +841,29 @@ end
 
 # A HTML tag attribute
 #  `<tag attr="value">`
+#
+# ~~~nit
+# var attr: TagAttribute
+#
+# attr = new TagAttribute("foo", null)
+# assert attr.write_to_string == " foo=\"\""
+#
+# attr = new TagAttribute("foo", "bar<>")
+# assert attr.write_to_string == " foo=\"bar&lt;&gt;\""
+# ~~~
 class TagAttribute
        super Template
 
        var name: String
        var value: nullable String
 
-       init(name: String, value: nullable String) do
-               self.name = name
-               self.value = value
-       end
-
        redef fun rendering do
                var value = self.value
                if value == null then
-                       add(" {name}")
+                       # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
+                       add " {name.html_escape}=\"\""
                else
-                       add(" {name}=\"{value}\"")
+                       add " {name.html_escape}=\"{value.html_escape}\""
                end
        end
 end
@@ -900,21 +899,20 @@ class TplPiwikScript
        var tracker_url: String
        var site_id: String
 
-       init(tracker_url, site_id: String) do
-               super
-               self.tracker_url = tracker_url
-               self.site_id = site_id
-       end
-
        redef fun render_content do
+               var site_id = self.site_id.to_json
+               var tracker_url = self.tracker_url.trim
+               if tracker_url.chars.last != '/' then tracker_url += "/"
+               tracker_url = "://{tracker_url}".to_json
+
                add "<!-- Piwik -->"
                add "var _paq = _paq || [];"
                add " _paq.push([\"trackPageView\"]);"
                add " _paq.push([\"enableLinkTracking\"]);"
                add "(function() \{"
-               add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
+               add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + {tracker_url};"
                add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
-               add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
+               add " _paq.push([\"setSiteId\", {site_id}]);"
                add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
                add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
                add "\})();"