5194e08cc5d50882d5398633bc8b05f537ad0361
[nit.git] / src / doc / html_templates / html_components.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 # HTML templates used by Nitdoc to generate API documentation
16 # Pages are assembled using `Template`
17 module html_components
18
19 import doc_base
20 import template
21 import json::static
22
23 # A documentation page
24 redef class DocPage
25 super Template
26
27 # Page url
28 var url: String is writable, noinit
29
30 # Directory where css, js and other assets can be found
31 var shareurl: String is writable, noinit
32
33 # Attributes of the body tag element
34 var body_attrs = new Array[TagAttribute]
35
36 # Top menu template if any
37 var topmenu: TplTopMenu is writable, noinit
38
39 # Sidebar template if any
40 var sidebar: nullable TplSidebar = null is writable
41
42 # Content of the page in form a TplSection
43 var sections = new Array[TplSection]
44
45 # Footer content if any
46 var footer: nullable Writable = null is writable
47
48 # JS scripts to append at the end of the body
49 var scripts = new Array[TplScript]
50
51 # Add a section to this page
52 fun add_section(section: TplSection) do
53 sections.add section
54 end
55
56 # Render the html header
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 # Render the topmenu template
79 private fun render_topmenu do
80 addn " <div class='row'>"
81 add topmenu
82 addn " </div>"
83 end
84
85 # Render the sidebar
86 # Sidebar is automatically populated with a summary of all sections
87 fun render_sidebar do
88 if sidebar == null then return
89 var summary = new TplSummary.with_order(0)
90 for section in sections do
91 section.render_summary summary
92 end
93 sidebar.boxes.add summary
94 add sidebar.as(not null)
95 end
96 # Render the footer and content
97 private fun render_content do
98 for section in sections do add section
99 if footer != null then
100 addn "<div class='well footer'>"
101 add footer.as(not null)
102 addn "</div>"
103 end
104 end
105
106 # Render JS scripts
107 private fun render_footer do
108 var vendors = (self.shareurl / "vendors").html_escape
109 var js = (self.shareurl / "js").html_escape
110
111 addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
112 addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
113 addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
114 addn "<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
115 for script in scripts do add script
116 addn """<script>
117 $(function () {
118 $("[data-toggle='tooltip']").tooltip();
119 $("[data-toggle='popover']").popover();
120 });
121 </script>"""
122 addn "</body>"
123 addn "</html>"
124 end
125
126 # Render the whole page
127 redef fun rendering do
128 render_head
129 addn "<div class='container-fluid'>"
130 render_topmenu
131 addn " <div class='row' id='content'>"
132 if sidebar != null then
133 addn "<div class='col col-xs-3 col-lg-2'>"
134 render_sidebar
135 addn "</div>"
136 addn "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
137 render_content
138 addn "</div>"
139 else
140 addn "<div class='col col-xs-12'>"
141 render_content
142 addn "</div>"
143 end
144 addn " </div>"
145 addn "</div>"
146 render_footer
147 end
148 end
149
150 #########################
151 # general layout elements
152 #########################
153
154 # Top menu bar template
155 class TplTopMenu
156 super Template
157
158 # Brand link to display in first position of the top menu
159 private var brand: nullable Writable = null is writable
160 # Elements of the topmenu
161 private var elts = new Array[Writable]
162
163 # The page url where the top menu is displayed.
164 #
165 # Used to select the active link.
166 private var current_url: String
167
168 # Add a new link to the menu.
169 fun add_link(content: TplLink) do
170 var is_active = content.href == current_url
171 add_item(content, is_active)
172 end
173
174 # Add a content between `<li>` tags
175 fun add_item(content: Writable, is_active: Bool) do
176 var tpl = new Template
177 tpl.add "<li"
178 if is_active then
179 tpl.add " class='active'"
180 end
181 tpl.add ">"
182 tpl.add content
183 tpl.addn "</li>"
184 add_raw(tpl)
185 end
186
187 # Add a raw content to the menu
188 fun add_raw(content: Writable) do
189 elts.add content
190 end
191
192 redef fun rendering do
193 if brand == null and elts.is_empty then return
194 addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
195 addn " <div class='container-fluid'>"
196 addn " <div class='navbar-header'>"
197 add " <button type='button' class='navbar-toggle' "
198 addn " data-toggle='collapse' data-target='#topmenu-collapse'>"
199 addn " <span class='sr-only'>Toggle menu</span>"
200 addn " <span class='icon-bar'></span>"
201 addn " <span class='icon-bar'></span>"
202 addn " <span class='icon-bar'></span>"
203 addn " </button>"
204 if brand != null then add brand.as(not null)
205 addn " </div>"
206 addn " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
207 if not elts.is_empty then
208 addn "<ul class='nav navbar-nav'>"
209 for elt in elts do add elt
210 addn "</ul>"
211 end
212 addn " </div>"
213 addn " </div>"
214 addn "</nav>"
215 end
216 end
217
218 # A sidebar template
219 class TplSidebar
220 super Template
221
222 # Sidebar contains sidebar element templates called boxes
223 var boxes = new Array[TplSidebarElt]
224
225 # Sort boxes by order priority
226 private fun order_boxes do
227 var sorter = new OrderComparator
228 sorter.sort(boxes)
229 end
230
231 redef fun rendering do
232 if boxes.is_empty then return
233 order_boxes
234 addn "<div id='sidebar'>"
235 for box in boxes do add box
236 addn "</div>"
237 end
238 end
239
240 # Comparator used to sort boxes by order
241 private class OrderComparator
242 super Comparator
243
244 redef type COMPARED: TplSidebarElt
245
246 redef fun compare(a, b) do
247 if a.order < b.order then return -1
248 if a.order > b.order then return 1
249 return 0
250 end
251 end
252
253 # Something that can be put in the sidebar
254 class TplSidebarElt
255 super Template
256
257 # Order of the box in the sidebar
258 var order: Int = 1
259
260 init with_order(order: Int) do self.order = order
261 end
262
263 # Agenericbox that can be added to sidebar
264 class TplSideBox
265 super TplSidebarElt
266
267 # Title of the box to display
268 # Title is also a placeholder for the collapse link
269 var title: String
270
271 # Box HTML id
272 # equals to `title.to_cmangle` by default
273 # Used for collapsing
274 var id: String is noinit
275
276 # Content to display in the box
277 # box will not be rendered if the content is null
278 var content: nullable Writable = null is writable
279
280 # Is the box opened by default
281 # otherwise, the user will have to clic on the title to display the content
282 var is_open = false is writable
283
284 init do
285 self.id = title.to_cmangle
286 end
287
288 init with_content(title: String, content: Writable) do
289 init(title)
290 self.content = content
291 end
292
293 redef fun rendering do
294 if content == null then return
295 var open = ""
296 if is_open then open = "in"
297 addn "<div class='panel'>"
298 addn " <div class='panel-heading'>"
299 add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
300 add title
301 addn " </a>"
302 addn " </div>"
303 addn " <div id='box_{id}' class='panel-body collapse {open}'>"
304 add content.as(not null)
305 addn " </div>"
306 addn "</div>"
307 end
308 end
309
310 # Something that can go on a summary template
311 class TplSummaryElt
312 super Template
313
314 # Add an element to the summary
315 fun add_child(child: TplSummaryElt) is abstract
316 end
317
318 # A summary that can go on the sidebar
319 # If the page contains a sidebar, the summary is automatically placed
320 # on top of the sidebarauto-generated
321 # summary contains anchors to all sections displayed in the page
322 class TplSummary
323 super TplSidebarElt
324 super TplSummaryElt
325
326 # Summary elements to display
327 var children = new Array[TplSummaryElt]
328
329 redef fun add_child(child) do children.add child
330
331 redef fun rendering do
332 if children.is_empty then return
333 addn "<div class='panel'>"
334 addn " <div class='panel-heading'>"
335 add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
336 add "Summary"
337 addn " </a>"
338 addn " </div>"
339 addn " <div id='box-sum' class='summary collapse in'>"
340 addn " <ul class='nav'>"
341 for entry in children do add entry
342 addn " </ul>"
343 addn " </div>"
344 addn "</div>"
345 end
346 end
347
348 # A summary entry
349 class TplSummaryEntry
350 super TplSummaryElt
351
352 # Text to display
353 var text: Writable
354
355 # Children of this entry
356 # Will be displayed as a tree
357 var children = new Array[TplSummaryElt]
358
359 redef fun add_child(child) do children.add child
360
361 redef fun rendering do
362 add "<li>"
363 add text
364 if not children.is_empty then
365 addn "\n<ul class='nav'>"
366 for entry in children do add entry
367 addn "</ul>"
368 end
369 addn "</li>"
370 end
371 end
372
373 # Something that can go in a section
374 # Sections are automatically collected to populate the menu
375 class TplSectionElt
376 super Template
377
378 # HTML anchor id
379 var id: String
380
381 # Title to display if any
382 # if both `title` and `summary_title` are null then
383 # the section will not appear in the summary
384 var title: nullable Writable = null is writable
385
386 # Subtitle to display if any
387 var subtitle: nullable Writable = null is writable
388
389 # Title that appear in the summary
390 # if null use `title` instead
391 var summary_title: nullable String = null is writable
392
393 # CSS classes to apply on the section element
394 var css_classes = new Array[String]
395
396 # CSS classes to apply on the title heading element
397 var title_classes = new Array[String]
398
399 # Parent article/section if any
400 var parent: nullable TplSectionElt = null
401
402 init with_title(id: String, title: Writable) do
403 init(id)
404 self.title = title
405 end
406
407 # Level <hX> for HTML heading
408 protected fun hlvl: Int do
409 if parent == null then return 1
410 return parent.hlvl + 1
411 end
412
413 # Elements contained by this section
414 var children = new Array[TplSectionElt]
415
416 # Add an element in this section
417 fun add_child(child: TplSectionElt) do
418 child.parent = self
419 children.add child
420 end
421
422 # Is the section empty (no content at all)
423 fun is_empty: Bool do return children.is_empty
424
425 # Render this section in the summary
426 fun render_summary(parent: TplSummaryElt) do
427 if is_empty then return
428 var title = summary_title
429 if title == null and self.title != null then title = self.title.write_to_string
430 if title == null then return
431 var lnk = new TplLink("#{id}", title)
432 var entry = new TplSummaryEntry(lnk)
433 for child in children do
434 child.render_summary(entry)
435 end
436 parent.add_child entry
437 end
438 end
439
440 # A HTML <section> element
441 class TplSection
442 super TplSectionElt
443
444 redef fun rendering do
445 addn "<section id='{id}' class='{css_classes.join(" ")}'>"
446 if title != null then
447 var lvl = hlvl
448 if lvl == 2 then title_classes.add "well well-sm"
449 addn "<h{lvl} class='{title_classes.join(" ")}'>"
450 addn title.as(not null)
451 addn "</h{lvl}>"
452 end
453 if subtitle != null then
454 addn "<div class='info subtitle'>"
455 addn subtitle.as(not null)
456 addn "</div>"
457 end
458 for child in children do
459 add child
460 end
461 addn "</section>"
462 end
463 end
464
465 # A page article that can go in a section
466 class TplArticle
467 super TplSectionElt
468
469 # Content for this article
470 var content: nullable Writable = null is writable
471 var source_link: nullable Writable = null is writable
472
473 init with_content(id: String, title: Writable, content: Writable) do
474 with_title(id, title)
475 self.content = content
476 end
477
478 redef fun render_summary(parent) do
479 if is_empty then return
480 var title = summary_title
481 if title == null and self.title != null then title = self.title.write_to_string
482 if title == null then return
483 var lnk = new TplLink("#{id}", title)
484 parent.add_child new TplSummaryEntry(lnk)
485 end
486
487 redef fun rendering do
488 if is_empty then return
489 addn "<article id='{id}' class='{css_classes.join(" ")}'>"
490 if source_link != null then
491 add "<div class='source-link'>"
492 add source_link.as(not null)
493 addn "</div>"
494 end
495 if title != null then
496 var lvl = hlvl
497 if lvl == 2 then title_classes.add "well well-sm"
498 add "<h{lvl} class='{title_classes.join(" ")}'>"
499 add title.as(not null)
500 addn "</h{lvl}>"
501 end
502 if subtitle != null then
503 add "<div class='info subtitle'>"
504 add subtitle.as(not null)
505 addn "</div>"
506 end
507 if content != null then
508 add content.as(not null)
509 end
510 for child in children do
511 add child
512 end
513 addn """</article>"""
514 end
515
516 redef fun is_empty: Bool do
517 return title == null and subtitle == null and content == null and children.is_empty
518 end
519 end
520
521 # A module / class / prop definition
522 class TplDefinition
523 super Template
524
525 # Comment to display
526 var comment: nullable Writable = null is writable
527
528 # Namespace for this definition
529 var namespace: nullable Writable = null is writable
530
531 # Location link to display
532 var location: nullable Writable = null is writable
533
534 private fun render_info do
535 addn "<div class='info text-right'>"
536 if namespace != null then
537 if comment == null then
538 add "<span class=\"noComment\">no comment for </span>"
539 end
540 add namespace.as(not null)
541 end
542 if location != null then
543 add " "
544 add location.as(not null)
545 end
546 addn "</div>"
547 end
548
549 private fun render_comment do
550 if comment != null then add comment.as(not null)
551 end
552
553 redef fun rendering do
554 addn "<div class='definition'>"
555 render_comment
556 render_info
557 addn "</div>"
558 end
559 end
560
561 # Class definition
562 class TplClassDefinition
563 super TplDefinition
564
565 var intros = new Array[TplListElt]
566 var redefs = new Array[TplListElt]
567
568 redef fun rendering do
569 addn "<div class='definition'>"
570 render_comment
571 render_info
572 render_list("Introduces", intros)
573 render_list("Redefines", redefs)
574 addn "</div>"
575 end
576
577 private fun render_list(name: String, elts: Array[TplListElt]) do
578 if elts.is_empty then return
579 addn "<h5>{name.html_escape}</h5>"
580 addn "<ul class='list-unstyled list-definition'>"
581 for elt in elts do add elt
582 addn "</ul>"
583 end
584 end
585
586 # Layout for Search page
587 class TplSearchPage
588 super TplSectionElt
589
590 var modules = new Array[Writable]
591 var classes = new Array[Writable]
592 var props = new Array[Writable]
593
594 redef fun rendering do
595 var title = self.title
596 if title != null then addn "<h1>{title.to_s.html_escape}</h1>"
597 addn "<div class='container-fluid'>"
598 addn " <div class='row'>"
599 if not modules.is_empty then
600 addn "<div class='col-xs-4'>"
601 addn "<h3>Modules</h3>"
602 addn "<ul>"
603 for m in modules do
604 add "<li>"
605 add m
606 addn "</li>"
607 end
608 addn "</ul>"
609 addn "</div>"
610 end
611 if not classes.is_empty then
612 addn "<div class='col-xs-4'>"
613 addn "<h3>Classes</h3>"
614 addn "<ul>"
615 for c in classes do
616 add "<li>"
617 add c
618 addn "</li>"
619 end
620 addn "</ul>"
621 addn "</div>"
622 end
623 if not props.is_empty then
624 addn "<div class='col-xs-4'>"
625 addn "<h3>Properties</h3>"
626 addn "<ul>"
627 for p in props do
628 add "<li>"
629 add p
630 addn "</li>"
631 end
632 addn "</ul>"
633 addn "</div>"
634 end
635 addn " </div>"
636 addn "</div>"
637 end
638 end
639
640 #####################
641 # Basiv HTML elements
642 #####################
643
644 # A html link <a>
645 class TplLink
646 super Template
647
648 # Link href
649 var href: String is writable
650
651 # The raw HTML content to display in the link
652 var text: Writable is writable
653
654 # The unescaped optional title.
655 var title: nullable String = null is writable
656
657 init with_title(href, text, title: String) do
658 init(href, text)
659 self.title = title
660 end
661
662 redef fun rendering do
663 add "<a href=\""
664 add href.html_escape
665 add "\""
666 if title != null then
667 add " title=\""
668 add title.as(not null).html_escape
669 add "\""
670 end
671 add ">"
672 add text
673 add "</a>"
674 end
675 end
676
677 # A <ul> list
678 class TplList
679 super TplListElt
680
681 # Elements contained in this list
682 # can be <li> or <ul> elements
683 var elts = new Array[TplListElt]
684
685 # CSS classes of the <ul> element
686 var css_classes = new Array[String]
687
688 # Add content wrapped in a <li> element
689 fun add_li(item: TplListItem) do elts.add item
690
691 init with_classes(classes: Array[String]) do self.css_classes = classes
692
693 fun is_empty: Bool do return elts.is_empty
694
695 redef fun rendering do
696 if elts.is_empty then return
697 addn "<ul class='{css_classes.join(" ")}'>"
698 for elt in elts do add elt
699 addn "</ul>"
700 end
701 end
702
703 # Something that can be added to a TplList
704 class TplListElt
705 super Template
706 end
707
708 # A list item <li>
709 class TplListItem
710 super TplListElt
711
712 # Content of the list item
713 var content = new Template
714
715 # CSS classes of the <li> element
716 var css_classes = new Array[String]
717
718 init with_content(content: Writable) do append(content)
719
720 init with_classes(content: Writable, classes: Array[String]) do
721 with_content(content)
722 css_classes = classes
723 end
724
725 # Append `content` to the item
726 # similar to `self.content.add`
727 fun append(content: Writable) do self.content.add content
728
729 redef fun rendering do
730 add "<li class='{css_classes.join(" ")}'>"
731 add content
732 addn "</li>"
733 end
734 end
735
736 # A Bootstrap tab component that contains `TplTabPanel`.
737 class TplTab
738 super Template
739
740 # Panels contained in the tab.
741 var panels = new Array[TplTabPanel]
742
743 # Add a new panel.
744 fun add_panel(panel: TplTabPanel) do panels.add panel
745
746 # CSS classes of the tab component.
747 var css_classes = new Array[String]
748
749 redef fun rendering do
750 addn "<div class='tab-content'>"
751 for panel in panels do add panel
752 addn "</div>"
753 end
754 end
755
756 # A panel that goes in a `TplTab`.
757 class TplTabPanel
758 super Template
759
760 # CSS classes of the pane element.
761 var css_classes = new Array[String]
762
763 # The panel id.
764 #
765 # Used to show/hide panel.
766 var id: String is noinit
767
768 # The panel name.
769 #
770 # Displayed in the tab header or in the pointing link.
771 var name: Writable
772
773 # Is the panel visible by default?
774 var is_active = false is writable
775
776 # Body of the panel
777 var content: nullable Writable = null is writable
778
779 # Get a link pointing to this panel.
780 fun tpl_link_to: Writable do
781 var lnk = new Template
782 lnk.add "<a data-target='#{id}' data-toggle='pill'>"
783 lnk.add name
784 lnk.add "</a>"
785 return lnk
786 end
787
788 redef fun rendering do
789 add "<div class='tab-pane {css_classes.join(" ")}"
790 if is_active then add "active"
791 addn "' id='{id}'>"
792 if content != null then add content.as(not null)
793 addn "</div>"
794 end
795 end
796
797 # A label with a text content
798 class TplLabel
799 super Template
800
801 # Content of the label if any
802 var content: nullable Writable = null is writable
803
804 # CSS classes of the <span> element
805 var css_classes = new Array[String]
806
807 init with_content(content: Writable) do self.content = content
808 init with_classes(classes: Array[String]) do self.css_classes = classes
809
810 redef fun rendering do
811 add "<span class='label {css_classes.join(" ")}'>"
812 if content != null then add content.as(not null)
813 add "</span>"
814 end
815 end
816
817 # A label with an icon
818 class TplIcon
819 super TplLabel
820
821 # Bootsrap icon name
822 # see: http://getbootstrap.com/components/#glyphicons
823 var icon: String
824
825 init with_icon(icon: String) do self.icon = icon
826
827 redef fun rendering do
828 add "<span class='glyphicon glyphicon-{icon} {css_classes.join(" ")}'>"
829 if content != null then add content.as(not null)
830 add "</span>"
831 end
832 end
833
834 # A HTML tag attribute
835 # `<tag attr="value">`
836 #
837 # ~~~nit
838 # var attr: TagAttribute
839 #
840 # attr = new TagAttribute("foo", null)
841 # assert attr.write_to_string == " foo=\"\""
842 #
843 # attr = new TagAttribute("foo", "bar<>")
844 # assert attr.write_to_string == " foo=\"bar&lt;&gt;\""
845 # ~~~
846 class TagAttribute
847 super Template
848
849 var name: String
850 var value: nullable String
851
852 redef fun rendering do
853 var value = self.value
854 if value == null then
855 # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
856 add " {name.html_escape}=\"\""
857 else
858 add " {name.html_escape}=\"{value.html_escape}\""
859 end
860 end
861 end
862
863 # Javacript template
864 class TplScript
865 super Template
866
867 var attrs = new Array[TagAttribute]
868 var content: nullable Writable = null is writable
869
870 init do
871 attrs.add(new TagAttribute("type", "text/javascript"))
872 end
873
874 protected fun render_content do
875 if content != null then add content.as(not null)
876 end
877
878 redef fun rendering do
879 add "<script"
880 for attr in attrs do add attr
881 addn ">"
882 render_content
883 addn "</script>"
884 end
885 end
886
887 # JS script for Piwik Tracker
888 class TplPiwikScript
889 super TplScript
890
891 var tracker_url: String
892 var site_id: String
893
894 redef fun render_content do
895 var site_id = self.site_id.to_json
896 var tracker_url = self.tracker_url.trim
897 if tracker_url.chars.last != '/' then tracker_url += "/"
898 tracker_url = "://{tracker_url}".to_json
899
900 addn "<!-- Piwik -->"
901 addn "var _paq = _paq || [];"
902 addn " _paq.push([\"trackPageView\"]);"
903 addn " _paq.push([\"enableLinkTracking\"]);"
904 addn "(function() \{"
905 addn " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + {tracker_url};"
906 addn " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
907 addn " _paq.push([\"setSiteId\", {site_id}]);"
908 addn " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
909 addn " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
910 addn "\})();"
911 end
912 end