.
8 | .list-group {
9 | // No need to set list-style: none; since .list-group-item is block level
10 | margin-bottom: 20px;
11 | padding-left: 0; // reset padding because ul and ol
12 | }
13 |
14 | // Individual list items
15 | // -------------------------
16 |
17 | .list-group-item {
18 | position: relative;
19 | display: block;
20 | padding: 10px 15px;
21 | // Place the border on the list items and negative margin up for better styling
22 | margin-bottom: -1px;
23 | background-color: @list-group-bg;
24 | border: 1px solid @list-group-border;
25 |
26 | // Round the first and last items
27 | &:first-child {
28 | .border-top-radius(@list-group-border-radius);
29 | }
30 | &:last-child {
31 | margin-bottom: 0;
32 | .border-bottom-radius(@list-group-border-radius);
33 | }
34 |
35 | // Align badges within list items
36 | > .badge {
37 | float: right;
38 | }
39 | > .badge + .badge {
40 | margin-right: 5px;
41 | }
42 |
43 | // Linked list items
44 | a& {
45 | color: @list-group-link-color;
46 |
47 | .list-group-item-heading {
48 | color: @list-group-link-heading-color;
49 | }
50 |
51 | // Hover state
52 | &:hover,
53 | &:focus {
54 | text-decoration: none;
55 | background-color: @list-group-hover-bg;
56 | }
57 | }
58 |
59 | // Active class on item itself, not parent
60 | &.active,
61 | &.active:hover,
62 | &.active:focus {
63 | z-index: 2; // Place active items above their siblings for proper border styling
64 | color: @list-group-active-color;
65 | background-color: @list-group-active-bg;
66 | border-color: @list-group-active-border;
67 |
68 | // Force color to inherit for custom content
69 | .list-group-item-heading {
70 | color: inherit;
71 | }
72 | .list-group-item-text {
73 | color: lighten(@list-group-active-bg, 40%);
74 | }
75 | }
76 | }
77 |
78 | // Custom content options
79 | // -------------------------
80 |
81 | .list-group-item-heading {
82 | margin-top: 0;
83 | margin-bottom: 5px;
84 | }
85 | .list-group-item-text {
86 | margin-bottom: 0;
87 | line-height: 1.3;
88 | }
89 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/media.less:
--------------------------------------------------------------------------------
1 | // Media objects
2 | // Source: http://stubbornella.org/content/?p=497
3 | // --------------------------------------------------
4 |
5 |
6 | // Common styles
7 | // -------------------------
8 |
9 | // Clear the floats
10 | .media,
11 | .media-body {
12 | overflow: hidden;
13 | zoom: 1;
14 | }
15 |
16 | // Proper spacing between instances of .media
17 | .media,
18 | .media .media {
19 | margin-top: 15px;
20 | }
21 | .media:first-child {
22 | margin-top: 0;
23 | }
24 |
25 | // For images and videos, set to block
26 | .media-object {
27 | display: block;
28 | }
29 |
30 | // Reset margins on headings for tighter default spacing
31 | .media-heading {
32 | margin: 0 0 5px;
33 | }
34 |
35 |
36 | // Media image alignment
37 | // -------------------------
38 |
39 | .media {
40 | > .pull-left {
41 | margin-right: 10px;
42 | }
43 | > .pull-right {
44 | margin-left: 10px;
45 | }
46 | }
47 |
48 |
49 | // Media list variation
50 | // -------------------------
51 |
52 | // Undo default ul/ol styles
53 | .media-list {
54 | padding-left: 0;
55 | list-style: none;
56 | }
57 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | padding-left: 0;
8 | margin: @line-height-computed 0;
9 | list-style: none;
10 | text-align: center;
11 | .clearfix();
12 | li {
13 | display: inline;
14 | > a,
15 | > span {
16 | display: inline-block;
17 | padding: 5px 14px;
18 | background-color: @pagination-bg;
19 | border: 1px solid @pagination-border;
20 | border-radius: @pager-border-radius;
21 | }
22 |
23 | > a:hover,
24 | > a:focus {
25 | text-decoration: none;
26 | background-color: @pagination-hover-bg;
27 | }
28 | }
29 |
30 | .next {
31 | > a,
32 | > span {
33 | float: right;
34 | }
35 | }
36 |
37 | .previous {
38 | > a,
39 | > span {
40 | float: left;
41 | }
42 | }
43 |
44 | .disabled {
45 | > a,
46 | > a:hover,
47 | > a:focus,
48 | > span {
49 | color: @pager-disabled-color;
50 | background-color: @pagination-bg;
51 | cursor: not-allowed;
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/pagination.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination (multiple pages)
3 | // --------------------------------------------------
4 | .pagination {
5 | display: inline-block;
6 | padding-left: 0;
7 | margin: @line-height-computed 0;
8 | border-radius: @border-radius-base;
9 |
10 | > li {
11 | display: inline; // Remove list-style and block-level defaults
12 | > a,
13 | > span {
14 | position: relative;
15 | float: left; // Collapse white-space
16 | padding: @padding-base-vertical @padding-base-horizontal;
17 | line-height: @line-height-base;
18 | text-decoration: none;
19 | background-color: @pagination-bg;
20 | border: 1px solid @pagination-border;
21 | margin-left: -1px;
22 | }
23 | &:first-child {
24 | > a,
25 | > span {
26 | margin-left: 0;
27 | .border-left-radius(@border-radius-base);
28 | }
29 | }
30 | &:last-child {
31 | > a,
32 | > span {
33 | .border-right-radius(@border-radius-base);
34 | }
35 | }
36 | }
37 |
38 | > li > a,
39 | > li > span {
40 | &:hover,
41 | &:focus {
42 | background-color: @pagination-hover-bg;
43 | }
44 | }
45 |
46 | > .active > a,
47 | > .active > span {
48 | &,
49 | &:hover,
50 | &:focus {
51 | z-index: 2;
52 | color: @pagination-active-color;
53 | background-color: @pagination-active-bg;
54 | border-color: @pagination-active-bg;
55 | cursor: default;
56 | }
57 | }
58 |
59 | > .disabled {
60 | > span,
61 | > a,
62 | > a:hover,
63 | > a:focus {
64 | color: @pagination-disabled-color;
65 | background-color: @pagination-bg;
66 | border-color: @pagination-border;
67 | cursor: not-allowed;
68 | }
69 | }
70 | }
71 |
72 | // Sizing
73 | // --------------------------------------------------
74 |
75 | // Large
76 | .pagination-lg {
77 | .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);
78 | }
79 |
80 | // Small
81 | .pagination-sm {
82 | .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);
83 | }
84 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/print.less:
--------------------------------------------------------------------------------
1 | //
2 | // Basic print styles
3 | // --------------------------------------------------
4 | // Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css
5 |
6 | @media print {
7 |
8 | * {
9 | text-shadow: none !important;
10 | color: #000 !important; // Black prints faster: h5bp.com/s
11 | background: transparent !important;
12 | box-shadow: none !important;
13 | }
14 |
15 | a,
16 | a:visited {
17 | text-decoration: underline;
18 | }
19 |
20 | a[href]:after {
21 | content: " (" attr(href) ")";
22 | }
23 |
24 | abbr[title]:after {
25 | content: " (" attr(title) ")";
26 | }
27 |
28 | // Don't show links for images, or javascript/internal links
29 | .ir a:after,
30 | a[href^="javascript:"]:after,
31 | a[href^="#"]:after {
32 | content: "";
33 | }
34 |
35 | pre,
36 | blockquote {
37 | border: 1px solid #999;
38 | page-break-inside: avoid;
39 | }
40 |
41 | thead {
42 | display: table-header-group; // h5bp.com/t
43 | }
44 |
45 | tr,
46 | img {
47 | page-break-inside: avoid;
48 | }
49 |
50 | img {
51 | max-width: 100% !important;
52 | }
53 |
54 | @page {
55 | margin: 2cm .5cm;
56 | }
57 |
58 | p,
59 | h2,
60 | h3 {
61 | orphans: 3;
62 | widows: 3;
63 | }
64 |
65 | h2,
66 | h3 {
67 | page-break-after: avoid;
68 | }
69 |
70 | // Bootstrap components
71 | .navbar {
72 | display: none;
73 | }
74 | .table {
75 | td,
76 | th {
77 | background-color: #fff !important;
78 | }
79 | }
80 | .btn,
81 | .dropup > .btn {
82 | > .caret {
83 | border-top-color: #000 !important;
84 | }
85 | }
86 | .label {
87 | border: 1px solid #000;
88 | }
89 |
90 | .table {
91 | border-collapse: collapse !important;
92 | }
93 | .table-bordered {
94 | th,
95 | td {
96 | border: 1px solid #ddd !important;
97 | }
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/progress-bars.less:
--------------------------------------------------------------------------------
1 | //
2 | // Progress bars
3 | // --------------------------------------------------
4 |
5 |
6 | // Bar animations
7 | // -------------------------
8 |
9 | // Webkit
10 | @-webkit-keyframes progress-bar-stripes {
11 | from { background-position: 40px 0; }
12 | to { background-position: 0 0; }
13 | }
14 |
15 | // Firefox
16 | @-moz-keyframes progress-bar-stripes {
17 | from { background-position: 40px 0; }
18 | to { background-position: 0 0; }
19 | }
20 |
21 | // Opera
22 | @-o-keyframes progress-bar-stripes {
23 | from { background-position: 0 0; }
24 | to { background-position: 40px 0; }
25 | }
26 |
27 | // Spec and IE10+
28 | @keyframes progress-bar-stripes {
29 | from { background-position: 40px 0; }
30 | to { background-position: 0 0; }
31 | }
32 |
33 |
34 |
35 | // Bar itself
36 | // -------------------------
37 |
38 | // Outer container
39 | .progress {
40 | overflow: hidden;
41 | height: @line-height-computed;
42 | margin-bottom: @line-height-computed;
43 | background-color: @progress-bg;
44 | border-radius: @border-radius-base;
45 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
46 | }
47 |
48 | // Bar of progress
49 | .progress-bar {
50 | float: left;
51 | width: 0%;
52 | height: 100%;
53 | font-size: @font-size-small;
54 | color: @progress-bar-color;
55 | text-align: center;
56 | background-color: @progress-bar-bg;
57 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
58 | .transition(width .6s ease);
59 | }
60 |
61 | // Striped bars
62 | .progress-striped .progress-bar {
63 | #gradient > .striped(@progress-bar-bg);
64 | background-size: 40px 40px;
65 | }
66 |
67 | // Call animation for the active one
68 | .progress.active .progress-bar {
69 | -webkit-animation: progress-bar-stripes 2s linear infinite;
70 | -moz-animation: progress-bar-stripes 2s linear infinite;
71 | -ms-animation: progress-bar-stripes 2s linear infinite;
72 | -o-animation: progress-bar-stripes 2s linear infinite;
73 | animation: progress-bar-stripes 2s linear infinite;
74 | }
75 |
76 |
77 |
78 | // Variations
79 | // -------------------------
80 |
81 | .progress-bar-success {
82 | .progress-bar-variant(@progress-bar-success-bg);
83 | }
84 |
85 | .progress-bar-info {
86 | .progress-bar-variant(@progress-bar-info-bg);
87 | }
88 |
89 | .progress-bar-warning {
90 | .progress-bar-variant(@progress-bar-warning-bg);
91 | }
92 |
93 | .progress-bar-danger {
94 | .progress-bar-variant(@progress-bar-danger-bg);
95 | }
96 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/scaffolding.less:
--------------------------------------------------------------------------------
1 | //
2 | // Scaffolding
3 | // --------------------------------------------------
4 |
5 |
6 | // Reset the box-sizing
7 |
8 | *,
9 | *:before,
10 | *:after {
11 | .box-sizing(border-box);
12 | }
13 |
14 |
15 | // Body reset
16 |
17 | html {
18 | font-size: 62.5%;
19 | -webkit-tap-highlight-color: rgba(0,0,0,0);
20 | }
21 |
22 | body {
23 | font-family: @font-family-base;
24 | font-size: @font-size-base;
25 | line-height: @line-height-base;
26 | color: @text-color;
27 | background-color: @body-bg;
28 | }
29 |
30 | // Reset fonts for relevant elements
31 | input,
32 | button,
33 | select,
34 | textarea {
35 | font-family: inherit;
36 | font-size: inherit;
37 | line-height: inherit;
38 | }
39 |
40 | // Reset unusual Firefox-on-Android default style.
41 | //
42 | // See https://github.com/necolas/normalize.css/issues/214
43 |
44 | button,
45 | input,
46 | select[multiple],
47 | textarea {
48 | background-image: none;
49 | }
50 |
51 |
52 | // Links
53 |
54 | a {
55 | color: @link-color;
56 | text-decoration: none;
57 |
58 | &:hover,
59 | &:focus {
60 | color: @link-hover-color;
61 | text-decoration: underline;
62 | }
63 |
64 | &:focus {
65 | .tab-focus();
66 | }
67 | }
68 |
69 |
70 | // Images
71 |
72 | img {
73 | vertical-align: middle;
74 | }
75 |
76 | // Responsive images (ensure images don't scale beyond their parents)
77 | .img-responsive {
78 | .img-responsive();
79 | }
80 |
81 | // Rounded corners
82 | .img-rounded {
83 | border-radius: @border-radius-large;
84 | }
85 |
86 | // Image thumbnails
87 | //
88 | // Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.
89 | .img-thumbnail {
90 | padding: @thumbnail-padding;
91 | line-height: @line-height-base;
92 | background-color: @thumbnail-bg;
93 | border: 1px solid @thumbnail-border;
94 | border-radius: @thumbnail-border-radius;
95 | .transition(all .2s ease-in-out);
96 |
97 | // Keep them at most 100% wide
98 | .img-responsive(inline-block);
99 | }
100 |
101 | // Perfect circle
102 | .img-circle {
103 | border-radius: 50%; // set radius in percents
104 | }
105 |
106 |
107 | // Horizontal rules
108 |
109 | hr {
110 | margin-top: @line-height-computed;
111 | margin-bottom: @line-height-computed;
112 | border: 0;
113 | border-top: 1px solid @hr-border;
114 | }
115 |
116 |
117 | // Only display content to screen readers
118 | //
119 | // See: http://a11yproject.com/posts/how-to-hide-content/
120 |
121 | .sr-only {
122 | position: absolute;
123 | width: 1px;
124 | height: 1px;
125 | margin: -1px;
126 | padding: 0;
127 | overflow: hidden;
128 | clip: rect(0 0 0 0);
129 | border: 0;
130 | }
131 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/thumbnails.less:
--------------------------------------------------------------------------------
1 | //
2 | // Thumbnails
3 | // --------------------------------------------------
4 |
5 |
6 | // Mixin and adjust the regular image class
7 | .thumbnail {
8 | .img-thumbnail();
9 | display: block; // Override the inline-block from `.img-thumbnail`
10 |
11 | > img {
12 | .img-responsive();
13 | }
14 | }
15 |
16 |
17 | // Add a hover state for linked versions only
18 | a.thumbnail:hover,
19 | a.thumbnail:focus {
20 | border-color: @link-color;
21 | }
22 |
23 | // Images and captions
24 | .thumbnail > img {
25 | margin-left: auto;
26 | margin-right: auto;
27 | }
28 | .thumbnail .caption {
29 | padding: @thumbnail-caption-padding;
30 | color: @thumbnail-caption-color;
31 | }
32 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/tooltip.less:
--------------------------------------------------------------------------------
1 | //
2 | // Tooltips
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .tooltip {
8 | position: absolute;
9 | z-index: @zindex-tooltip;
10 | display: block;
11 | visibility: visible;
12 | font-size: @font-size-small;
13 | line-height: 1.4;
14 | .opacity(0);
15 |
16 | &.in { .opacity(.9); }
17 | &.top { margin-top: -3px; padding: 5px 0; }
18 | &.right { margin-left: 3px; padding: 0 5px; }
19 | &.bottom { margin-top: 3px; padding: 5px 0; }
20 | &.left { margin-left: -3px; padding: 0 5px; }
21 | }
22 |
23 | // Wrapper for the tooltip content
24 | .tooltip-inner {
25 | max-width: @tooltip-max-width;
26 | padding: 3px 8px;
27 | color: @tooltip-color;
28 | text-align: center;
29 | text-decoration: none;
30 | background-color: @tooltip-bg;
31 | border-radius: @border-radius-base;
32 | }
33 |
34 | // Arrows
35 | .tooltip-arrow {
36 | position: absolute;
37 | width: 0;
38 | height: 0;
39 | border-color: transparent;
40 | border-style: solid;
41 | }
42 | .tooltip {
43 | &.top .tooltip-arrow {
44 | bottom: 0;
45 | left: 50%;
46 | margin-left: -@tooltip-arrow-width;
47 | border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
48 | border-top-color: @tooltip-arrow-color;
49 | }
50 | &.top-left .tooltip-arrow {
51 | bottom: 0;
52 | left: 5px;
53 | border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
54 | border-top-color: @tooltip-arrow-color;
55 | }
56 | &.top-right .tooltip-arrow {
57 | bottom: 0;
58 | right: 5px;
59 | border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
60 | border-top-color: @tooltip-arrow-color;
61 | }
62 | &.right .tooltip-arrow {
63 | top: 50%;
64 | left: 0;
65 | margin-top: -@tooltip-arrow-width;
66 | border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
67 | border-right-color: @tooltip-arrow-color;
68 | }
69 | &.left .tooltip-arrow {
70 | top: 50%;
71 | right: 0;
72 | margin-top: -@tooltip-arrow-width;
73 | border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
74 | border-left-color: @tooltip-arrow-color;
75 | }
76 | &.bottom .tooltip-arrow {
77 | top: 0;
78 | left: 50%;
79 | margin-left: -@tooltip-arrow-width;
80 | border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
81 | border-bottom-color: @tooltip-arrow-color;
82 | }
83 | &.bottom-left .tooltip-arrow {
84 | top: 0;
85 | left: 5px;
86 | border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
87 | border-bottom-color: @tooltip-arrow-color;
88 | }
89 | &.bottom-right .tooltip-arrow {
90 | top: 0;
91 | right: 5px;
92 | border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
93 | border-bottom-color: @tooltip-arrow-color;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // Floats
7 | // -------------------------
8 |
9 | .clearfix {
10 | .clearfix();
11 | }
12 | .pull-right {
13 | float: right !important;
14 | }
15 | .pull-left {
16 | float: left !important;
17 | }
18 |
19 |
20 | // Toggling content
21 | // -------------------------
22 |
23 | .hide {
24 | display: none !important;
25 | }
26 | .show {
27 | display: block !important;
28 | }
29 | .invisible {
30 | visibility: hidden;
31 | }
32 | .text-hide {
33 | .hide-text();
34 | }
35 |
36 |
37 | // For Affix plugin
38 | // -------------------------
39 |
40 | .affix {
41 | position: fixed;
42 | }
43 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/less/wells.less:
--------------------------------------------------------------------------------
1 | //
2 | // Wells
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .well {
8 | min-height: 20px;
9 | padding: 19px;
10 | margin-bottom: 20px;
11 | background-color: @well-bg;
12 | border: 1px solid darken(@well-bg, 7%);
13 | border-radius: @border-radius-base;
14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15 | blockquote {
16 | border-color: #ddd;
17 | border-color: rgba(0,0,0,.15);
18 | }
19 | }
20 |
21 | // Sizes
22 | .well-lg {
23 | padding: 24px;
24 | border-radius: @border-radius-large;
25 | }
26 | .well-sm {
27 | padding: 9px;
28 | border-radius: @border-radius-small;
29 | }
30 |
--------------------------------------------------------------------------------
/docs/bower_components/bootstrap/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap"
3 | , "description": "Sleek, intuitive, and powerful front-end framework for faster and easier web development."
4 | , "version": "3.0.0"
5 | , "keywords": ["bootstrap", "css"]
6 | , "homepage": "http://twbs.github.com/bootstrap/"
7 | , "author": "Twitter Inc."
8 | , "scripts": { "test": "grunt test" }
9 | , "repository": {
10 | "type": "git"
11 | , "url": "https://github.com/twbs/bootstrap.git"
12 | }
13 | , "licenses": [
14 | {
15 | "type": "Apache-2.0"
16 | , "url": "http://www.apache.org/licenses/LICENSE-2.0"
17 | }
18 | ]
19 | , "devDependencies": {
20 | "grunt": "~0.4.1"
21 | , "grunt-contrib-clean": "~0.5.0"
22 | , "grunt-contrib-connect": "~0.3.0"
23 | , "grunt-contrib-concat": "~0.3.0"
24 | , "grunt-contrib-copy": "~0.4.0"
25 | , "grunt-contrib-jshint": "~0.6.0"
26 | , "grunt-contrib-uglify": "~0.2.2"
27 | , "grunt-contrib-qunit": "~0.2.2"
28 | , "grunt-contrib-watch": "~0.5.1"
29 | , "grunt-html-validation": "git://github.com/praveenvijayan/grunt-html-validation.git"
30 | , "grunt-jekyll": "~0.3.8"
31 | , "grunt-recess": "~0.3.3"
32 | , "browserstack-runner": "~0.0.11"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "version": "2.0.3",
4 | "description": "jQuery component",
5 | "keywords": [
6 | "jquery",
7 | "component"
8 | ],
9 | "main": "jquery.js",
10 | "license": "MIT",
11 | "homepage": "https://github.com/components/jquery",
12 | "_release": "2.0.3",
13 | "_resolution": {
14 | "type": "version",
15 | "tag": "2.0.3",
16 | "commit": "452a56b52b8f4a032256cdb8b6838f25f0bdb3d2"
17 | },
18 | "_source": "git://github.com/components/jquery.git",
19 | "_target": ">= 1.9.0",
20 | "_originalSource": "jquery"
21 | }
--------------------------------------------------------------------------------
/docs/bower_components/jquery/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/README.md:
--------------------------------------------------------------------------------
1 | jQuery Component
2 | ================
3 |
4 | Shim repository for the [jQuery](http://jquery.com).
5 |
6 | Package Managers
7 | ----------------
8 |
9 | * [Bower](http://bower.io/): `jquery`
10 | * [Component](https://github.com/component/component): `components/jquery`
11 | * [Composer](http://packagist.org/packages/components/jquery): `components/jquery`
12 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "version": "2.0.3",
4 | "description": "jQuery component",
5 | "keywords": [
6 | "jquery",
7 | "component"
8 | ],
9 | "main": "jquery.js",
10 | "license": "MIT"
11 | }
12 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "repo": "components/jquery",
4 | "version": "2.0.3",
5 | "description": "jQuery component",
6 | "keywords": [
7 | "jquery",
8 | "component"
9 | ],
10 | "main": "jquery.js",
11 | "scripts": [
12 | "jquery.js"
13 | ],
14 | "license": "MIT"
15 | }
16 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "components/jquery",
3 | "description": "jQuery JavaScript Library",
4 | "type": "component",
5 | "homepage": "http://jquery.com",
6 | "license": "MIT",
7 | "support": {
8 | "irc": "irc://irc.freenode.org/jquery",
9 | "issues": "http://bugs.jquery.com",
10 | "forum": "http://forum.jquery.com",
11 | "wiki": "http://docs.jquery.com/",
12 | "source": "https://github.com/jquery/jquery"
13 | },
14 | "authors": [
15 | {
16 | "name": "John Resig",
17 | "email": "jeresig@gmail.com"
18 | }
19 | ],
20 | "require": {
21 | "robloach/component-installer": "*"
22 | },
23 | "extra": {
24 | "component": {
25 | "scripts": [
26 | "jquery.js"
27 | ],
28 | "files": [
29 | "jquery.min.js",
30 | "jquery-migrate.js",
31 | "jquery-migrate.min.js"
32 | ]
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/bower_components/jquery/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "components-jquery",
3 | "version": "2.0.3",
4 | "description": "jQuery component",
5 | "keywords": ["jquery"],
6 | "main": "./jquery.js"
7 | }
8 |
--------------------------------------------------------------------------------
/docs/cn/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: subpage
3 | title: FAQ
4 | pageid: faq
5 | ---
6 | {% raw %}
7 |
8 | # 常见问题
9 |
10 | ## nunjucks 是否可同时在 node 端和浏览器端使用?
11 |
12 | 是.
13 |
14 | ## 是否可在 nunjucks 和 jinja2 使用同一个模板?两者有什么区别?
15 |
16 | 有一些区别。
17 |
18 | 首先,nunjucks 可以操作原生的 Javascript 而 [jinja2](http://jinja.pocoo.org/) 操作的是 python,比如在 nunjucks 中布尔值为 `true` 而 jinja2 为 `True`,在调用数组原生方法的时候也不同。
19 |
20 | 但是,如果你避免使用原生语言的特性(如 `{{ str.trim() }}`) 而完全使用模板的特性和过滤器,那么两者的模块可以兼容。
21 |
22 | Nunjucks 支持与 Jinja 兼容,查看 [installJinjaCompat](/api.html#installjinjacompat) 获取更多信息。
23 |
24 | 除此之外,nunjucks 还有一些未实现的功能:
25 |
26 | * `self` 变量
27 | * `for` 不支持 `if not` and `else`
28 | * `if i is divisibleby(3)` 式的条件判断
29 | * 可命名的结束区块: `{% endblock content %}`
30 | * 沙箱模式 (Sandboxed mode)
31 | * 行语句: `# for item in seq`
32 |
33 | 最后,自定义的 python 过滤器和扩展需要用 Javascript 重写。
34 |
35 | {% endraw %}
36 |
--------------------------------------------------------------------------------
/docs/cn/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: subpage
3 | pageid: getting-started
4 | ---
5 |
6 | # 快速上手
7 |
8 | ## Node 端使用
9 |
10 | ```
11 | $ npm install nunjucks
12 | ```
13 |
14 | 下载后可直接 `require('nunjucks')` 使用
15 |
16 | ## 浏览器端使用
17 |
18 | 可直接使用 [nunjucks.js](files/nunjucks.js) ([min](files/nunjucks.min.js)),如果针对编译后的模板可使用 [nunjucks-slim.js](files/nunjucks-slim.js) ([min](files/nunjucks-slim.min.js))。
19 |
20 | ### 你应该使用哪个文件
21 |
22 | * **nunjucks.js** 可用于动态加载模板,当模板变化时重新加载,也可以用于预编译后的模板。包含编译器,所以会比较大 (20K min/gzipped)。如果你刚接触 nunjucks 可使用这个文件,如果你不在意大小也可以在生产环境使用。
23 |
24 | * **nunjucks-slim.js** 只能用于预编译后的模板,只包含运行时的代码,所以比较小 (8K min/gzipped)。一般用于生产环境,如果你使用 [grunt](https://github.com/jlongster/grunt-nunjucks) 或[gulp](https://github.com/sindresorhus/gulp-nunjucks)任务自动预编译,也可以在开发环境使用。
25 |
26 | 直接用 `script` 引入文件:
27 |
28 | ```html
29 |
30 | ```
31 |
32 | 或者可以作为一个 AMD 模块加载:
33 |
34 | ```js
35 | define(['nunjucks'], function(nunjucks) {
36 | });
37 | ```
38 |
39 | > 确保在生产环境使用预编译版本,可使用 [grunt
40 | > ](https://github.com/jlongster/grunt-nunjucks)或[gulp](https://github.com/sindresorhus/gulp-nunjucks),可在 [浏览器使用](api.html#browser-usage) 查看客户端优化的配置。
41 |
42 | ## 使用说明
43 |
44 | 这是最简单使用 nunjucks 的方式,首先设置配置项(如 autoescaping),然后渲染一个字符串:
45 |
46 | ```js
47 | nunjucks.configure({ autoescape: true });
48 | nunjucks.renderString('Hello {% raw %}{{ username }}{% endraw %}', { username: 'James' });
49 | ```
50 |
51 | `renderString` 并不常用,而是使用 `render` 来直接渲染文件,这种方式支持继承(extends)和包含(include)模板。使用之前需要配置文件的路径:
52 |
53 | ```js
54 | nunjucks.configure('views', { autoescape: true });
55 | nunjucks.render('index.html', { foo: 'bar' });
56 | ```
57 |
58 | 在 node 端,`'views'` 为相对于当前工作目录 (working
59 | directory) 的路径。在浏览器端则为一个相对的 url,最好指定为绝对路径 (如 `'/views'`)。
60 |
61 | 如果使用 express 可直接传入 `configure`:
62 |
63 | ```js
64 | var app = express();
65 |
66 | nunjucks.configure('views', {
67 | autoescape: true,
68 | express: app
69 | });
70 |
71 | app.get('/', function(req, res) {
72 | res.render('index.html');
73 | });
74 | ```
75 |
76 | 上面的 API 适用于 node 端和浏览器端 (express 只适用于 node 端),在 node 端 nunjucks 从文件系统加载模板,在浏览器端通过 http 加载模板。
77 |
78 | 如果你在浏览器上使用[编译后](api.html#precompiling)的模板的话,你不需要额外做其他的事情系统也能够理解它们。这使得我们可以轻松地在开发环境和生产环境上使用同一份代码,并在生产环境上只使用已经编译过的模板。
79 |
80 | ## 更多信息
81 |
82 | 这只是冰山一角,可继续查看 [API](api.html) 文档和[模板语言](templating.html)。
83 |
--------------------------------------------------------------------------------
/docs/css/fonts/Sullivan-Fill.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/css/fonts/Sullivan-Fill.eot
--------------------------------------------------------------------------------
/docs/css/fonts/Sullivan-Fill.svg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/css/fonts/Sullivan-Fill.svg
--------------------------------------------------------------------------------
/docs/css/fonts/Sullivan-Fill.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/css/fonts/Sullivan-Fill.ttf
--------------------------------------------------------------------------------
/docs/css/fonts/Sullivan-Fill.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/css/fonts/Sullivan-Fill.woff
--------------------------------------------------------------------------------
/docs/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: subpage
3 | title: FAQ
4 | pageid: faq
5 | ---
6 | {% raw %}
7 |
8 | # Questions Asked Frequently Enough
9 |
10 | ## Can I use nunjucks in node and the browser/client-side?
11 |
12 | Yes. Nunjucks supports all modern browsers and any version of Node.js
13 | [currently supported by the Node.js Foundation](https://github.com/nodejs/Release#release-schedule1).
14 |
15 | ## Can I precompile templates for server-side use (Node/Express)?
16 |
17 | No, precompiled templates are a browser/client-side optimization only.
18 | It is not necessary to precompile on the server because templates are
19 | compiled then cached the first time they are individually loaded for rendering.
20 | The compiled template will then remained cached in memory until the server restarts.
21 |
22 | You can choose never to cache by setting [configure](api.html#configure)'s `noCache` option to `true`.
23 |
24 | ## Can I use the same templates between nunjucks and jinja2? What are the differences?
25 |
26 | Kind of. There are enough differences that it might take some work.
27 | The first problem is that nunjucks lets you access native JavaScript
28 | constructs, while [jinja2](http://jinja.pocoo.org/) lets you access
29 | Python. This means that there are minor gotchas like the boolean
30 | literal being `true` in nunjucks but `True` in jinja2, and if you call
31 | native methods on arrays the API will be different.
32 |
33 | However, if you avoid accessing the native language features (like `{{ str.trim() }}`)
34 | and rely solely on filters and pure templating
35 | features, it should be easy to make templates compatible.
36 |
37 | Nunjucks has experimental support for installing APIs into the
38 | templating environment to help with Jinja compatibility. See
39 | [installJinjaCompat](api.html#installjinjacompat).
40 |
41 | Additionally, there are few jinja2 features not implemented in nunjucks:
42 |
43 | * The special `self` variable
44 | * `for` does not support `if not` and `else`
45 | * `if i is divisibleby(3)`-style conditionals
46 | * Sandboxed mode
47 | * Note: this makes it **unsuitable for applications requiring [user-defined templates](api.html#user-defined-templates-warning)**
48 | * Line statements: `# for item in seq`
49 |
50 | Lastly, any custom Python filters and extensions will have to be written in JavaScript.
51 |
52 | {% endraw %}
53 |
--------------------------------------------------------------------------------
/docs/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/files/.keep
--------------------------------------------------------------------------------
/docs/fr/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: subpage
3 | title: FAQ
4 | pageid: faq
5 | ---
6 | {% raw %}
7 |
8 | # Questions posées fréquemment
9 |
10 | ## Puis-je utiliser nunjucks dans node et dans le navigateur/côté client ?
11 |
12 | Oui. Nunjucks supporte tous les navigateurs modernes et les versions de Node.js
13 | [même supportées par la fondation Node.js](https://github.com/nodejs/Release#release-schedule1).
14 |
15 | ## Puis-je utiliser les mêmes modèles entre nunjucks et Jinja2? Quelles sont les différences ?
16 |
17 | Il y a suffisamment de différences pour que cela puisse prendre du temps.
18 | Le premier problème est que nunjucks vous permet d'accéder aux constructions natifs de
19 | JavaScript, tandis que [jinja2](http://jinja.pocoo.org/) vous permet d'accéder à celle de
20 | Python. Cela signifie qu'il y a des pièges mineurs comme le booléen littéral
21 | qui est `true` dans nunjucks mais `True` dans jinja2, et si vous appelez des
22 | méthodes natives sur les tableaux, l'API sera différent.
23 |
24 | Toutefois, si vous n'accédez pas aux fonctionnalités natives de language (comme `{{ str.trim() }}`)
25 | et utilisez uniquement les filtres et les caractéristiques de templates
26 | pures, il devrait être facile de faire des templates compatibles.
27 |
28 | Nunjucks a un support expérimental pour l'installation d'API dans l'environnement
29 | de templates pour aider la compatibilité Jinja. Voir
30 | [installJinjaCompat](api.html#installjinjacompat).
31 |
32 | En plus, il y a quelques fonctionnalités de jinja2 qui ne sont pas implémentées dans nunjucks:
33 |
34 | * La variable spéciale `self`
35 | * `for` ne supporte pas `if not` et `else`
36 | * Le style conditionnelle de `if i is divisibleby(3)`
37 | * Le nommage des blocs de fin : `{% endblock content %}`
38 | * Le mode bac à sable (sandbox)
39 | * Les commentaires de lignes : `# for item in seq`
40 |
41 | Enfin, tous les filtres et les extensions de Python personnalisés devront être écrits en JavaScript.
42 |
43 | {% endraw %}
44 |
--------------------------------------------------------------------------------
/docs/img/apostrophe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/apostrophe.png
--------------------------------------------------------------------------------
/docs/img/apostrophe2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/apostrophe2x.png
--------------------------------------------------------------------------------
/docs/img/backbeam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/backbeam.png
--------------------------------------------------------------------------------
/docs/img/backbeam2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/backbeam2x.png
--------------------------------------------------------------------------------
/docs/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/favicon.png
--------------------------------------------------------------------------------
/docs/img/marketplace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/marketplace.png
--------------------------------------------------------------------------------
/docs/img/marketplace2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/marketplace2x.png
--------------------------------------------------------------------------------
/docs/img/webmaker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/webmaker.png
--------------------------------------------------------------------------------
/docs/img/webmaker2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/docs/img/webmaker2x.png
--------------------------------------------------------------------------------
/docs/js/subpage.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | var toc = $('.toc');
4 | if(toc.length) {
5 | var base = $('body')[0].getBoundingClientRect().top;
6 | var top = toc[0].getBoundingClientRect().top;
7 |
8 | toc.affix({
9 | offset: {
10 | top: top - base
11 | }
12 | });
13 | }
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/nunjucks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const lib = require('./src/lib');
4 | const {Environment, Template} = require('./src/environment');
5 | const Loader = require('./src/loader');
6 | const loaders = require('./src/loaders');
7 | const precompile = require('./src/precompile');
8 | const compiler = require('./src/compiler');
9 | const parser = require('./src/parser');
10 | const lexer = require('./src/lexer');
11 | const runtime = require('./src/runtime');
12 | const nodes = require('./src/nodes');
13 | const installJinjaCompat = require('./src/jinja-compat');
14 |
15 | // A single instance of an environment, since this is so commonly used
16 | let e;
17 |
18 | function configure(templatesPath, opts) {
19 | opts = opts || {};
20 | if (lib.isObject(templatesPath)) {
21 | opts = templatesPath;
22 | templatesPath = null;
23 | }
24 |
25 | let TemplateLoader;
26 | if (loaders.FileSystemLoader) {
27 | TemplateLoader = new loaders.FileSystemLoader(templatesPath, {
28 | watch: opts.watch,
29 | noCache: opts.noCache
30 | });
31 | } else if (loaders.WebLoader) {
32 | TemplateLoader = new loaders.WebLoader(templatesPath, {
33 | useCache: opts.web && opts.web.useCache,
34 | async: opts.web && opts.web.async
35 | });
36 | }
37 |
38 | e = new Environment(TemplateLoader, opts);
39 |
40 | if (opts && opts.express) {
41 | e.express(opts.express);
42 | }
43 |
44 | return e;
45 | }
46 |
47 | module.exports = {
48 | Environment: Environment,
49 | Template: Template,
50 | Loader: Loader,
51 | FileSystemLoader: loaders.FileSystemLoader,
52 | NodeResolveLoader: loaders.NodeResolveLoader,
53 | PrecompiledLoader: loaders.PrecompiledLoader,
54 | WebLoader: loaders.WebLoader,
55 | compiler: compiler,
56 | parser: parser,
57 | lexer: lexer,
58 | runtime: runtime,
59 | lib: lib,
60 | nodes: nodes,
61 | installJinjaCompat: installJinjaCompat,
62 | configure: configure,
63 | reset() {
64 | e = undefined;
65 | },
66 | compile(src, env, path, eagerCompile) {
67 | if (!e) {
68 | configure();
69 | }
70 | return new Template(src, env, path, eagerCompile);
71 | },
72 | render(name, ctx, cb) {
73 | if (!e) {
74 | configure();
75 | }
76 |
77 | return e.render(name, ctx, cb);
78 | },
79 | renderString(src, ctx, cb) {
80 | if (!e) {
81 | configure();
82 | }
83 |
84 | return e.renderString(src, ctx, cb);
85 | },
86 | precompile: (precompile) ? precompile.precompile : undefined,
87 | precompileString: (precompile) ? precompile.precompileString : undefined,
88 | };
89 |
--------------------------------------------------------------------------------
/nunjucks/src/express-app.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = function express(env, app) {
4 | function NunjucksView(name, opts) {
5 | this.name = name;
6 | this.path = name;
7 | this.defaultEngine = opts.defaultEngine;
8 | this.ext = path.extname(name);
9 | if (!this.ext && !this.defaultEngine) {
10 | throw new Error('No default engine was specified and no extension was provided.');
11 | }
12 | if (!this.ext) {
13 | this.name += (this.ext = (this.defaultEngine[0] !== '.' ? '.' : '') + this.defaultEngine);
14 | }
15 | }
16 |
17 | NunjucksView.prototype.render = function render(opts, cb) {
18 | env.render(this.name, opts, cb);
19 | };
20 |
21 | app.set('view', NunjucksView);
22 | app.set('nunjucksEnv', env);
23 | return env;
24 | };
25 |
--------------------------------------------------------------------------------
/nunjucks/src/globals.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function cycler(items) {
4 | var index = -1;
5 |
6 | return {
7 | current: null,
8 | reset() {
9 | index = -1;
10 | this.current = null;
11 | },
12 |
13 | next() {
14 | index++;
15 | if (index >= items.length) {
16 | index = 0;
17 | }
18 |
19 | this.current = items[index];
20 | return this.current;
21 | },
22 | };
23 | }
24 |
25 | function joiner(sep) {
26 | sep = sep || ',';
27 | let first = true;
28 |
29 | return () => {
30 | const val = first ? '' : sep;
31 | first = false;
32 | return val;
33 | };
34 | }
35 |
36 | // Making this a function instead so it returns a new object
37 | // each time it's called. That way, if something like an environment
38 | // uses it, they will each have their own copy.
39 | function globals() {
40 | return {
41 | range(start, stop, step) {
42 | if (typeof stop === 'undefined') {
43 | stop = start;
44 | start = 0;
45 | step = 1;
46 | } else if (!step) {
47 | step = 1;
48 | }
49 |
50 | const arr = [];
51 | if (step > 0) {
52 | for (let i = start; i < stop; i += step) {
53 | arr.push(i);
54 | }
55 | } else {
56 | for (let i = start; i > stop; i += step) { // eslint-disable-line for-direction
57 | arr.push(i);
58 | }
59 | }
60 | return arr;
61 | },
62 |
63 | cycler() {
64 | return cycler(Array.prototype.slice.call(arguments));
65 | },
66 |
67 | joiner(sep) {
68 | return joiner(sep);
69 | }
70 | };
71 | }
72 |
73 | module.exports = globals;
74 |
--------------------------------------------------------------------------------
/nunjucks/src/loader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const {EmitterObj} = require('./object');
5 |
6 | module.exports = class Loader extends EmitterObj {
7 | resolve(from, to) {
8 | return path.resolve(path.dirname(from), to);
9 | }
10 |
11 | isRelative(filename) {
12 | return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/nunjucks/src/loaders.js:
--------------------------------------------------------------------------------
1 | // This file will automatically be rewired to web-loader.js when
2 | // building for the browser
3 | module.exports = require('./node-loaders');
4 |
--------------------------------------------------------------------------------
/nunjucks/src/object.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // A simple class system, more documentation to come
4 | const EventEmitter = require('events');
5 | const lib = require('./lib');
6 |
7 | function parentWrap(parent, prop) {
8 | if (typeof parent !== 'function' || typeof prop !== 'function') {
9 | return prop;
10 | }
11 | return function wrap() {
12 | // Save the current parent method
13 | const tmp = this.parent;
14 |
15 | // Set parent to the previous method, call, and restore
16 | this.parent = parent;
17 | const res = prop.apply(this, arguments);
18 | this.parent = tmp;
19 |
20 | return res;
21 | };
22 | }
23 |
24 | function extendClass(cls, name, props) {
25 | props = props || {};
26 |
27 | lib.keys(props).forEach(k => {
28 | props[k] = parentWrap(cls.prototype[k], props[k]);
29 | });
30 |
31 | class subclass extends cls {
32 | get typename() {
33 | return name;
34 | }
35 | }
36 |
37 | lib._assign(subclass.prototype, props);
38 |
39 | return subclass;
40 | }
41 |
42 | class Obj {
43 | constructor(...args) {
44 | // Unfortunately necessary for backwards compatibility
45 | this.init(...args);
46 | }
47 |
48 | init() {}
49 |
50 | get typename() {
51 | return this.constructor.name;
52 | }
53 |
54 | static extend(name, props) {
55 | if (typeof name === 'object') {
56 | props = name;
57 | name = 'anonymous';
58 | }
59 | return extendClass(this, name, props);
60 | }
61 | }
62 |
63 | class EmitterObj extends EventEmitter {
64 | constructor(...args) {
65 | super();
66 | // Unfortunately necessary for backwards compatibility
67 | this.init(...args);
68 | }
69 |
70 | init() {}
71 |
72 | get typename() {
73 | return this.constructor.name;
74 | }
75 |
76 | static extend(name, props) {
77 | if (typeof name === 'object') {
78 | props = name;
79 | name = 'anonymous';
80 | }
81 | return extendClass(this, name, props);
82 | }
83 | }
84 |
85 | module.exports = { Obj, EmitterObj };
86 |
--------------------------------------------------------------------------------
/nunjucks/src/precompile-global.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function precompileGlobal(templates, opts) {
4 | var out = '';
5 | opts = opts || {};
6 |
7 | for (let i = 0; i < templates.length; i++) {
8 | const name = JSON.stringify(templates[i].name);
9 | const template = templates[i].template;
10 |
11 | out += '(function() {' +
12 | '(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})' +
13 | '[' + name + '] = (function() {\n' + template + '\n})();\n';
14 |
15 | if (opts.asFunction) {
16 | out += 'return function(ctx, cb) { return nunjucks.render(' + name + ', ctx, cb); }\n';
17 | }
18 |
19 | out += '})();\n';
20 | }
21 | return out;
22 | }
23 |
24 | module.exports = precompileGlobal;
25 |
--------------------------------------------------------------------------------
/nunjucks/src/precompiled-loader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Loader = require('./loader');
4 |
5 | class PrecompiledLoader extends Loader {
6 | constructor(compiledTemplates) {
7 | super();
8 | this.precompiled = compiledTemplates || {};
9 | }
10 |
11 | getSource(name) {
12 | if (this.precompiled[name]) {
13 | return {
14 | src: {
15 | type: 'code',
16 | obj: this.precompiled[name]
17 | },
18 | path: name
19 | };
20 | }
21 | return null;
22 | }
23 | }
24 |
25 | module.exports = {
26 | PrecompiledLoader: PrecompiledLoader,
27 | };
28 |
--------------------------------------------------------------------------------
/nunjucks/src/web-loaders.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Loader = require('./loader');
4 | const {PrecompiledLoader} = require('./precompiled-loader.js');
5 |
6 | class WebLoader extends Loader {
7 | constructor(baseURL, opts) {
8 | super();
9 | this.baseURL = baseURL || '.';
10 | opts = opts || {};
11 |
12 | // By default, the cache is turned off because there's no way
13 | // to "watch" templates over HTTP, so they are re-downloaded
14 | // and compiled each time. (Remember, PRECOMPILE YOUR
15 | // TEMPLATES in production!)
16 | this.useCache = !!opts.useCache;
17 |
18 | // We default `async` to false so that the simple synchronous
19 | // API can be used when you aren't doing anything async in
20 | // your templates (which is most of the time). This performs a
21 | // sync ajax request, but that's ok because it should *only*
22 | // happen in development. PRECOMPILE YOUR TEMPLATES.
23 | this.async = !!opts.async;
24 | }
25 |
26 | resolve(from, to) {
27 | throw new Error('relative templates not support in the browser yet');
28 | }
29 |
30 | getSource(name, cb) {
31 | var useCache = this.useCache;
32 | var result;
33 | this.fetch(this.baseURL + '/' + name, (err, src) => {
34 | if (err) {
35 | if (cb) {
36 | cb(err.content);
37 | } else if (err.status === 404) {
38 | result = null;
39 | } else {
40 | throw err.content;
41 | }
42 | } else {
43 | result = {
44 | src: src,
45 | path: name,
46 | noCache: !useCache
47 | };
48 | this.emit('load', name, result);
49 | if (cb) {
50 | cb(null, result);
51 | }
52 | }
53 | });
54 |
55 | // if this WebLoader isn't running asynchronously, the
56 | // fetch above would actually run sync and we'll have a
57 | // result here
58 | return result;
59 | }
60 |
61 | fetch(url, cb) {
62 | // Only in the browser please
63 | if (typeof window === 'undefined') {
64 | throw new Error('WebLoader can only by used in a browser');
65 | }
66 |
67 | const ajax = new XMLHttpRequest();
68 | let loading = true;
69 |
70 | ajax.onreadystatechange = () => {
71 | if (ajax.readyState === 4 && loading) {
72 | loading = false;
73 | if (ajax.status === 0 || ajax.status === 200) {
74 | cb(null, ajax.responseText);
75 | } else {
76 | cb({
77 | status: ajax.status,
78 | content: ajax.responseText
79 | });
80 | }
81 | }
82 | };
83 |
84 | url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' +
85 | (new Date().getTime());
86 |
87 | ajax.open('GET', url, this.async);
88 | ajax.send();
89 | }
90 | }
91 |
92 | module.exports = {
93 | WebLoader: WebLoader,
94 | PrecompiledLoader: PrecompiledLoader
95 | };
96 |
--------------------------------------------------------------------------------
/samples/express/js/app.js:
--------------------------------------------------------------------------------
1 |
2 | nunjucks.configure('views', {
3 | autoescape: true
4 | });
5 |
6 | // aboutTmpl({ poop: 'pooop<><>' }, function(err, res) {
7 | // console.log(res);
8 | // });
9 |
--------------------------------------------------------------------------------
/samples/express/js/extensions.js:
--------------------------------------------------------------------------------
1 |
2 | function RemoteExtension() {
3 | this.tags = ['remote'];
4 |
5 | this.parse = function(parser, nodes, lexer) {
6 | // get the tag token
7 | var tok = parser.nextToken();
8 |
9 | // parse the args and move after the block end. passing true
10 | // as the second arg is required if there are no parentheses
11 | var args = parser.parseSignature(null, true);
12 | parser.advanceAfterBlockEnd(tok.value);
13 |
14 | // parse the body and move after block end
15 | var body = parser.parseUntilBlocks('error', 'endtruncate');
16 | var errorBody = null;
17 |
18 | if (parser.skipSymbol('error')) {
19 | parser.skip(lexer.TOKEN_BLOCK_END);
20 | errorBody = parser.parseUntilBlocks('endremote');
21 | }
22 |
23 | parser.advanceAfterBlockEnd();
24 |
25 | return new nodes.CallExtension(this, 'run', args, [body, errorBody]);
26 | };
27 |
28 | this.run = function(context, url, body, errorBody) {
29 | var id = 'el' + Math.floor(Math.random() * 10000);
30 | var ret = new nunjucks.runtime.SafeString('
' + body() + '
');
31 | var ajax = new XMLHttpRequest();
32 |
33 | ajax.onreadystatechange = function() {
34 | if (ajax.readyState == 4) {
35 | if (ajax.status == 200) {
36 | document.getElementById(id).innerHTML = ajax.responseText;
37 | } else {
38 | document.getElementById(id).innerHTML = errorBody();
39 | }
40 | }
41 | };
42 |
43 | ajax.open('GET', url, true);
44 | ajax.send();
45 |
46 | return ret;
47 | };
48 | }
49 |
--------------------------------------------------------------------------------
/samples/express/main.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names */
2 |
3 | 'use strict';
4 |
5 | var path = require('path');
6 | var nunjucks = require('../..');
7 | var express = require('express');
8 |
9 | var app = express();
10 | nunjucks.configure(path.join(__dirname, 'views'), {
11 | autoescape: true,
12 | express: app,
13 | watch: true
14 | });
15 |
16 | // app
17 |
18 | app.use(express.static(__dirname));
19 |
20 | app.use(function(req, res, next) {
21 | res.locals.user = 'hello';
22 | next();
23 | });
24 |
25 | app.get('/', function(req, res) {
26 | res.render('index.html', {
27 | username: 'James Long
copyright '
28 | });
29 | });
30 |
31 | app.get('/about', function(req, res) {
32 | res.render('about.html');
33 | });
34 |
35 | app.listen(4000, function() {
36 | console.log('Express server running on http://localhost:4000');
37 | });
38 |
--------------------------------------------------------------------------------
/samples/express/pre.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | var precompileString = require('../..').precompileString;
6 | var fs = require('fs');
7 | var path = require('path');
8 |
9 |
10 | var out = 'window.baseTmpl = ' +
11 | precompileString(
12 | fs.readFileSync(path.join(__dirname, 'views/base.html'), 'utf-8'), {
13 | name: 'base.html',
14 | asFunction: true
15 | });
16 |
17 | out += 'window.aboutTmpl = ' +
18 | precompileString(
19 | fs.readFileSync(path.join(__dirname, 'views/about.html'), 'utf-8'), {
20 | name: 'about.html',
21 | asFunction: true
22 | });
23 |
24 | fs.writeFileSync(path.join(__dirname, 'js/templates.js'), out, 'utf-8');
25 |
26 | fs.writeFileSync(path.join(__dirname, 'js/nunjucks.js'),
27 | fs.readFileSync(path.join(__dirname, '../../browser/nunjucks.js'), 'utf-8'),
28 | 'utf-8');
29 |
--------------------------------------------------------------------------------
/samples/express/views/about.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | This is just the about page
5 | {% endblock %}
6 |
7 | {% block footer %}
8 | {{ super() }}
9 | You really should read this!
10 |
11 | {{ poop }}
12 | {% endblock %}
13 |
--------------------------------------------------------------------------------
/samples/express/views/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
A quick app
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {% block content %}{% endblock %}
23 |
24 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/samples/express/views/import-context-set.html:
--------------------------------------------------------------------------------
1 | {% set bar = "FOO" %}
2 |
--------------------------------------------------------------------------------
/samples/express/views/index.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | Hello, {{ username | default('poop') | safe }}! This is just some content.
5 |
6 |
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/samples/express/views/item-base.html:
--------------------------------------------------------------------------------
1 |
2 | Editing item: {{ name }}
3 |
4 | {% block description %}
5 | A basic description is: {{ desc }}
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/samples/express/views/item.html:
--------------------------------------------------------------------------------
1 | {% extends "item-base.html" %}
2 |
3 | {% block description %}
4 | I told you, it's name is {{ name }}.
5 |
6 | It also has the description: {{ desc }}.
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/samples/express/views/set.html:
--------------------------------------------------------------------------------
1 | {% set username = "foooo" %}
2 |
--------------------------------------------------------------------------------
/scripts/lib/arrow-function-coverage-fix.js:
--------------------------------------------------------------------------------
1 | // Restore old babylon behavior for istanbul.
2 | // https://github.com/babel/babel/pull/6836
3 | // https://github.com/istanbuljs/istanbuljs/issues/119
4 | module.exports = function hacks() {
5 | return {
6 | visitor: {
7 | Program: function Program(programPath) {
8 | programPath.traverse({
9 | ArrowFunctionExpression: function ArrowFunctionExpression(path) {
10 | var node = path.node;
11 | node.expression = node.body.type !== 'BlockStatement';
12 | },
13 | });
14 | },
15 | },
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/scripts/lib/is-main-module.js:
--------------------------------------------------------------------------------
1 | module.exports = function isMainModule() {
2 | // generate a stack trace
3 | var stack = (new Error()).stack;
4 | // the third line refers to our caller
5 | var stackLine = stack.split('\n')[2];
6 | // extract the module name from that line
7 | var callerModuleName = /\((.*):\d+:\d+\)$/.exec(stackLine)[1];
8 |
9 | return require.main.filename === callerModuleName;
10 | };
11 |
--------------------------------------------------------------------------------
/scripts/lib/mocha-phantomjs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var spawn = require('child_process').spawn;
4 | var path = require('path');
5 | var lookup = require('./utils').lookup;
6 |
7 | module.exports = function mochaPhantomJS(url, options) {
8 | options = options || {};
9 | const coverageFile = path.join(
10 | __dirname, '../../.nyc_output',
11 | (url.indexOf('slim') > -1) ? 'browser-slim.json' : 'browser-std.json');
12 |
13 | return new Promise((resolve, reject) => {
14 | try {
15 | const scriptPath = require.resolve('mocha-phantomjs-core/mocha-phantomjs-core.js');
16 |
17 | if (!scriptPath) {
18 | throw new Error('mocha-phantomjs-core.js not found');
19 | }
20 |
21 | const args = [
22 | scriptPath,
23 | url,
24 | options.reporter || 'dot',
25 | JSON.stringify(Object.assign({
26 | useColors: true,
27 | hooks: 'mocha-phantomjs-istanbul',
28 | coverageFile: coverageFile,
29 | }, options.phantomjs || {})),
30 | ];
31 | const phantomjsPath = lookup('.bin/phantomjs', true) || lookup('phantomjs-prebuilt/bin/phantomjs', true);
32 |
33 | if (!phantomjsPath) {
34 | throw new Error('PhantomJS not found');
35 | }
36 |
37 | const proc = spawn(phantomjsPath, args, {cwd: path.join(__dirname, '../..')});
38 |
39 | proc.stdout.pipe(process.stdout);
40 | proc.stderr.pipe(process.stderr);
41 |
42 | proc.on('error', (err) => {
43 | reject(err);
44 | });
45 |
46 | proc.on('exit', (code) => {
47 | if (code === 0) {
48 | resolve();
49 | } else {
50 | reject(new Error('test failed. phantomjs exit code: ' + code));
51 | }
52 | });
53 | } catch (err) {
54 | reject(err);
55 | }
56 | });
57 | };
58 |
--------------------------------------------------------------------------------
/scripts/lib/precompile.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const precompile = require('../../nunjucks/src/precompile').precompile;
4 |
5 | var testDir = path.join(__dirname, '../../tests');
6 |
7 | function precompileTestTemplates() {
8 | return new Promise((resolve, reject) => {
9 | try {
10 | const output = precompile(path.join(testDir, 'templates'), {
11 | include: [/\.(njk|html)$/],
12 | });
13 | fs.writeFileSync(path.join(testDir, 'browser/precompiled-templates.js'), output);
14 | resolve();
15 | } catch (err) {
16 | reject(err);
17 | }
18 | });
19 | }
20 |
21 | module.exports = precompileTestTemplates;
22 |
--------------------------------------------------------------------------------
/scripts/lib/runtests.js:
--------------------------------------------------------------------------------
1 | var mochaPhantom = require('./mocha-phantomjs');
2 | var spawn = require('child_process').spawn;
3 | var getStaticServer = require('./static-server');
4 | var path = require('path');
5 |
6 | var utils = require('./utils');
7 | var lookup = utils.lookup;
8 | var promiseSequence = utils.promiseSequence;
9 |
10 | function mochaRun({cliTest = false} = {}) {
11 | // We need to run the cli test without nyc because of weird behavior
12 | // with spawn-wrap
13 | const bin = lookup((cliTest) ? '.bin/mocha' : '.bin/nyc', true);
14 | const runArgs = (cliTest)
15 | ? []
16 | : [
17 | '--require', '@babel/register',
18 | '--exclude',
19 | 'tests/**',
20 | '--silent',
21 | '--no-clean',
22 | require.resolve('mocha/bin/mocha'),
23 | ];
24 |
25 | const mochaArgs = (cliTest)
26 | ? ['tests/cli.js']
27 | : ['--grep', 'precompile cli', '--invert', 'tests'];
28 |
29 | return new Promise((resolve, reject) => {
30 | try {
31 | const proc = spawn(bin, [
32 | ...runArgs,
33 | '-R', 'spec',
34 | '-r', 'tests/setup',
35 | '-r', '@babel/register',
36 | ...mochaArgs,
37 | ], {
38 | cwd: path.join(__dirname, '../..'),
39 | env: process.env
40 | });
41 |
42 | proc.stdout.pipe(process.stdout);
43 | proc.stderr.pipe(process.stderr);
44 |
45 | proc.on('error', (err) => reject(err));
46 |
47 | proc.on('exit', (code) => {
48 | if (code === 0) {
49 | resolve();
50 | } else {
51 | reject(new Error('test failed. nyc/mocha exit code: ' + code));
52 | }
53 | });
54 | } catch (err) {
55 | reject(err);
56 | }
57 | });
58 | }
59 |
60 | function runtests() {
61 | return new Promise((resolve, reject) => {
62 | var server;
63 |
64 | const mochaPromise = promiseSequence([
65 | () => mochaRun({cliTest: false}),
66 | () => mochaRun({cliTest: true}),
67 | ]);
68 |
69 | return mochaPromise.then(() => {
70 | return getStaticServer().then((args) => {
71 | server = args[0];
72 | const port = args[1];
73 | const promises = ['index', 'slim'].map(
74 | f => (() => mochaPhantom(`http://localhost:${port}/tests/browser/${f}.html`)));
75 | return promiseSequence(promises).then(() => {
76 | server.close();
77 | resolve();
78 | });
79 | });
80 | }).catch((err) => {
81 | if (server) {
82 | server.close();
83 | }
84 | reject(err);
85 | });
86 | });
87 | }
88 |
89 | module.exports = runtests;
90 |
--------------------------------------------------------------------------------
/scripts/lib/static-server.js:
--------------------------------------------------------------------------------
1 | var connect = require('connect');
2 | var getPort = require('get-port');
3 | var serveStatic = require('serve-static');
4 | var http = require('http');
5 | var path = require('path');
6 |
7 |
8 | function getStaticServer(port) {
9 | var staticRoot = path.join(__dirname, '../..');
10 | var portPromise = (typeof port === 'undefined') ? getPort() : Promise.resolve(port);
11 | return portPromise.then((port) => { // eslint-disable-line no-shadow
12 | return new Promise((resolve, reject) => {
13 | try {
14 | const app = connect().use(serveStatic(staticRoot));
15 | const server = http.createServer(app);
16 | server.listen(port, () => {
17 | console.log('Test server listening on port ' + port); // eslint-disable-line no-console
18 | resolve([server, port]);
19 | });
20 | } catch (e) {
21 | reject(e);
22 | }
23 | });
24 | });
25 | }
26 |
27 | module.exports = getStaticServer;
28 |
--------------------------------------------------------------------------------
/scripts/lib/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 |
6 | function lookup(relPath, isExecutable) {
7 | for (let i = 0; i < module.paths.length; i++) {
8 | let absPath = path.join(module.paths[i], relPath);
9 | if (isExecutable && process.platform === 'win32') {
10 | absPath += '.cmd';
11 | }
12 | if (fs.existsSync(absPath)) {
13 | return absPath;
14 | }
15 | }
16 | return undefined;
17 | }
18 |
19 | function promiseSequence(promises) {
20 | return new Promise((resolve, reject) => {
21 | var results = [];
22 |
23 | function iterator(prev, curr) {
24 | return prev.then((result) => {
25 | results.push(result);
26 | return curr(result, results);
27 | }).catch((err) => {
28 | reject(err);
29 | });
30 | }
31 |
32 | promises.push(() => Promise.resolve());
33 | promises.reduce(iterator, Promise.resolve(false)).then((res) => resolve(res));
34 | });
35 | }
36 |
37 | module.exports = {
38 | lookup: lookup,
39 | promiseSequence: promiseSequence
40 | };
41 |
--------------------------------------------------------------------------------
/scripts/testrunner.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | var NYC = require('nyc');
6 |
7 | process.env.NODE_ENV = 'test';
8 |
9 | const nyc = new NYC({
10 | exclude: ['*.min.js', 'scripts/**', 'tests/**'],
11 | reporter: ['text', 'html', 'lcovonly'],
12 | showProcessTree: true
13 | });
14 | nyc.reset();
15 |
16 | require('@babel/register');
17 |
18 | const runtests = require('./lib/runtests');
19 | const precompileTestTemplates = require('./lib/precompile');
20 |
21 | let err;
22 |
23 | precompileTestTemplates()
24 | .then(() => runtests())
25 | .catch((e) => {
26 | err = e;
27 | console.log(err); // eslint-disable-line no-console
28 | })
29 | .then(() => {
30 | nyc.writeCoverageFile();
31 | nyc.report();
32 |
33 | if (err) {
34 | process.exit(1);
35 | }
36 | });
37 |
--------------------------------------------------------------------------------
/tests/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'env': {
3 | node: true,
4 | es6: false,
5 | mocha: true,
6 | browser: true,
7 | },
8 | 'rules': {
9 | // func-names is annoying when you don't have arrow syntax
10 | 'func-names': 'off',
11 | // To deal with browser environments, we need to have require
12 | // calls inside a conditional
13 | 'global-require': 'off',
14 | 'spaced-comment': ['error', 'always', { 'exceptions': ['*', ','] }],
15 | // This is another rule that doesn't make sense when you don't have block-level
16 | // variable declarations
17 | 'one-var': 'off',
18 | 'one-var-declaration-per-line': 'off',
19 | // We need tests to run without babel on browsers that might not have Object.keys
20 | // and related functions
21 | 'no-restricted-syntax': 'off',
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/tests/api.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var expect;
5 | var util;
6 | var Environment;
7 | var Loader;
8 | var templatesPath;
9 | var path;
10 |
11 | if (typeof require !== 'undefined') {
12 | expect = require('expect.js');
13 | util = require('./util');
14 | Environment = require('../nunjucks/src/environment').Environment;
15 | Loader = require('../nunjucks/src/node-loaders').FileSystemLoader;
16 | templatesPath = 'tests/templates';
17 | path = require('path');
18 | } else {
19 | expect = window.expect;
20 | Environment = nunjucks.Environment;
21 | Loader = nunjucks.WebLoader;
22 | templatesPath = '../templates';
23 | }
24 |
25 | describe('api', function() {
26 | it('should always force compilation of parent template', function() {
27 | var env = new Environment(new Loader(templatesPath));
28 |
29 | var child = env.getTemplate('base-inherit.njk');
30 | expect(child.render()).to.be('Foo*Bar*BazFizzle');
31 | });
32 |
33 | it('should only call the callback once when conditional import fails', function(done) {
34 | var env = new Environment(new Loader(templatesPath));
35 | var called = 0;
36 | env.render('broken-conditional-include.njk',
37 | function() {
38 | expect(++called).to.be(1);
39 | }
40 | );
41 | setTimeout(done, 0);
42 | });
43 |
44 |
45 | it('should handle correctly relative paths', function() {
46 | var env;
47 | var child1;
48 | var child2;
49 | if (typeof path === 'undefined') {
50 | this.skip();
51 | return;
52 | }
53 | env = new Environment(new Loader(templatesPath));
54 | child1 = env.getTemplate('relative/test1.njk');
55 | child2 = env.getTemplate('relative/test2.njk');
56 |
57 | expect(child1.render()).to.be('FooTest1BazFizzle');
58 | expect(child2.render()).to.be('FooTest2BazFizzle');
59 | });
60 |
61 | it('should handle correctly cache for relative paths', function() {
62 | var env;
63 | var test;
64 | if (typeof path === 'undefined') {
65 | this.skip();
66 | return;
67 | }
68 | env = new Environment(new Loader(templatesPath));
69 | test = env.getTemplate('relative/test-cache.njk');
70 |
71 | expect(util.normEOL(test.render())).to.be('Test1\nTest2');
72 | });
73 |
74 | it('should handle correctly relative paths in renderString', function() {
75 | var env;
76 | if (typeof path === 'undefined') {
77 | this.skip();
78 | return;
79 | }
80 | env = new Environment(new Loader(templatesPath));
81 | expect(env.renderString('{% extends "./relative/test1.njk" %}{% block block1 %}Test3{% endblock %}', {}, {
82 | path: path.resolve(templatesPath, 'string.njk')
83 | })).to.be('FooTest3BazFizzle');
84 | });
85 |
86 | it('should emit "load" event on Environment instance', function(done) {
87 | var env = new Environment(new Loader(templatesPath));
88 | env.on('load', function(name, source) {
89 | expect(name).to.equal('item.njk');
90 | done();
91 | });
92 | env.render('item.njk', {});
93 | });
94 | });
95 | }());
96 |
--------------------------------------------------------------------------------
/tests/browser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Mocha Tests
6 |
7 |
20 |
21 |
22 |
23 | Tests do not indicate performance. They are much slower because a
24 | new environment is created for every single template and is
25 | recompiled from scratch, and you can see there are
26 |
quite
27 | a
28 |
lot
29 | of
30 |
tests .
31 |
32 |
33 |
34 |
35 |
36 |
37 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/tests/browser/slim.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Mocha Tests (slim)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/tests/cli.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var path = require('path');
5 | var execFile = require('child_process').execFile;
6 | var expect = require('expect.js');
7 |
8 | var rootDir = path.resolve(path.join(__dirname, '..'));
9 | var precompileBin = path.join(rootDir, 'bin', 'precompile');
10 |
11 | if (process.platform === 'win32') {
12 | precompileBin += '.cmd';
13 | }
14 |
15 | function execPrecompile(args, cb) {
16 | execFile(precompileBin, args, {cwd: rootDir}, cb);
17 | }
18 |
19 | describe('precompile cli', function() {
20 | it('should echo a compiled template to stdout', function(done) {
21 | execPrecompile(['tests/templates/item.njk'], function(err, stdout, stderr) {
22 | if (err) {
23 | done(err);
24 | return;
25 | }
26 | expect(stdout).to.contain('window.nunjucksPrecompiled');
27 | expect(stderr).to.equal('');
28 | done();
29 | });
30 | });
31 |
32 | it('should support --name', function(done) {
33 | var args = [
34 | '--name', 'item.njk',
35 | 'tests/templates/item.njk',
36 | ];
37 | execPrecompile(args, function(err, stdout, stderr) {
38 | if (err) {
39 | done(err);
40 | return;
41 | }
42 | expect(stdout).to.contain('"item.njk"');
43 | expect(stderr).to.equal('');
44 | done();
45 | });
46 | });
47 | });
48 | }());
49 |
--------------------------------------------------------------------------------
/tests/core.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var expect,
5 | nunjucks,
6 | fs,
7 | os,
8 | path;
9 |
10 | if (typeof require !== 'undefined') {
11 | expect = require('expect.js');
12 | nunjucks = require('../nunjucks/index');
13 | fs = require('fs-extra');
14 | path = require('path');
15 | os = require('os');
16 | } else {
17 | expect = window.expect;
18 | nunjucks = window.nunjucks;
19 | }
20 |
21 | function rmdir(dirPath) {
22 | fs.emptyDirSync(dirPath);
23 | fs.rmdirSync(dirPath);
24 | }
25 |
26 | describe('nunjucks.configure', function() {
27 | var tempdir;
28 |
29 | before(function() {
30 | if (fs && path && os) {
31 | try {
32 | tempdir = fs.mkdtempSync(path.join(os.tmpdir(), 'templates'));
33 | fs.emptyDirSync(tempdir);
34 | } catch (e) {
35 | rmdir(tempdir);
36 | throw e;
37 | }
38 | }
39 | });
40 |
41 | after(function() {
42 | nunjucks.reset();
43 | if (typeof tempdir !== 'undefined') {
44 | rmdir(tempdir);
45 | }
46 | });
47 |
48 | it('should cache templates by default', function() {
49 | if (typeof fs === 'undefined') {
50 | this.skip();
51 | return;
52 | }
53 | nunjucks.configure(tempdir);
54 |
55 | fs.writeFileSync(tempdir + '/test.html', '{{ name }}', 'utf-8');
56 | expect(nunjucks.render('test.html', {name: 'foo'})).to.be('foo');
57 |
58 | fs.writeFileSync(tempdir + '/test.html', '{{ name }}-changed', 'utf-8');
59 | expect(nunjucks.render('test.html', {name: 'foo'})).to.be('foo');
60 | });
61 |
62 | it('should not cache templates with {noCache: true}', function() {
63 | if (typeof fs === 'undefined') {
64 | this.skip();
65 | return;
66 | }
67 | nunjucks.configure(tempdir, {noCache: true});
68 |
69 | fs.writeFileSync(tempdir + '/test.html', '{{ name }}', 'utf-8');
70 | expect(nunjucks.render('test.html', {name: 'foo'})).to.be('foo');
71 |
72 | fs.writeFileSync(tempdir + '/test.html', '{{ name }}-changed', 'utf-8');
73 | expect(nunjucks.render('test.html', {name: 'foo'})).to.be('foo-changed');
74 | });
75 | });
76 | }());
77 |
--------------------------------------------------------------------------------
/tests/express.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var express = require('express');
5 | var expect = require('expect.js');
6 | var request = require('supertest');
7 | var nunjucks = require('../nunjucks/index');
8 |
9 | var VIEWS = path.join(__dirname, '../samples/express/views');
10 |
11 | describe('express', function() {
12 | var app;
13 | var env;
14 |
15 | beforeEach(function() {
16 | app = express();
17 | env = new nunjucks.Environment(new nunjucks.FileSystemLoader(VIEWS));
18 | env.express(app);
19 | });
20 |
21 | it('should have reference to nunjucks env', function() {
22 | expect(app.settings.nunjucksEnv).to.be(env);
23 | });
24 |
25 | it('should render a view with extension', function(done) {
26 | app.get('/', function(req, res) {
27 | res.render('about.html');
28 | });
29 | request(app)
30 | .get('/')
31 | .expect(/This is just the about page/)
32 | .end(done);
33 | });
34 |
35 | it('should render a view without extension', function(done) {
36 | app.get('/', function(req, res) {
37 | res.render('about');
38 | });
39 | app.set('view engine', 'html');
40 | request(app)
41 | .get('/')
42 | .expect(/This is just the about page/)
43 | .end(done);
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/tests/precompile.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | var expect,
5 | precompile,
6 | precompileString;
7 |
8 | if (typeof require !== 'undefined') {
9 | expect = require('expect.js');
10 | precompile = require('../nunjucks/src/precompile').precompile;
11 | precompileString = require('../nunjucks/src/precompile').precompileString;
12 | } else {
13 | expect = window.expect;
14 | precompile = nunjucks.precompile;
15 | precompileString = nunjucks.precompileString;
16 | }
17 |
18 | describe('precompile', function() {
19 | it('should return a string', function() {
20 | expect(precompileString('{{ test }}', {
21 | name: 'test.njk'
22 | })).to.be.an('string');
23 | });
24 |
25 | describe('templates', function() {
26 | it('should return *NIX path seperators', function() {
27 | var fileName;
28 |
29 | precompile('./tests/templates/item.njk', {
30 | wrapper: function(templates) {
31 | fileName = templates[0].name;
32 | }
33 | });
34 |
35 | expect(fileName).to.equal('./tests/templates/item.njk');
36 | });
37 |
38 | it('should return *NIX path seperators, when name is passed as option', function() {
39 | var fileName;
40 |
41 | precompile('
test ', {
42 | name: 'path\\to\\file.j2',
43 | isString: true,
44 | wrapper: function(templates) {
45 | fileName = templates[0].name;
46 | }
47 | });
48 |
49 | expect(fileName).to.equal('path/to/file.j2');
50 | });
51 | });
52 | });
53 | }());
54 |
--------------------------------------------------------------------------------
/tests/setup.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 |
3 |
--------------------------------------------------------------------------------
/tests/templates/async.njk:
--------------------------------------------------------------------------------
1 | {{ tmpl | getContents }}
2 |
--------------------------------------------------------------------------------
/tests/templates/base-inherit.njk:
--------------------------------------------------------------------------------
1 | {% extends "base.njk" %}
2 |
3 | {% block block1 %}*{{ super() }}*{% endblock %}
4 |
--------------------------------------------------------------------------------
/tests/templates/base-set-and-show.njk:
--------------------------------------------------------------------------------
1 | {% set var = 'parent' %}{% block main %}{% set var = 'inner' %}{% endblock %}{{ var }}
--------------------------------------------------------------------------------
/tests/templates/base-set-inside-block.njk:
--------------------------------------------------------------------------------
1 | {% block main %}{% set var = 'inner' %}{% endblock %}
--------------------------------------------------------------------------------
/tests/templates/base-set-wraps-block.njk:
--------------------------------------------------------------------------------
1 | {% set somevar %}{% block somevar %}{% endblock %}{% endset %}{{ somevar }}
2 |
--------------------------------------------------------------------------------
/tests/templates/base-set.njk:
--------------------------------------------------------------------------------
1 | {% set var = 'parent' %}{% block main %}{% set var = 'inner' %}{% endblock %}
--------------------------------------------------------------------------------
/tests/templates/base-show.njk:
--------------------------------------------------------------------------------
1 | {% block main %}{{ var }}{% endblock %}
--------------------------------------------------------------------------------
/tests/templates/base.njk:
--------------------------------------------------------------------------------
1 | Foo{% block block1 %}Bar{% endblock %}{% block block2 %}Baz{% endblock %}Fizzle
--------------------------------------------------------------------------------
/tests/templates/base2.njk:
--------------------------------------------------------------------------------
1 | {% for item in [1,2] %}{% block item %}{{ item }}{% endblock %}{% endfor %}
--------------------------------------------------------------------------------
/tests/templates/base3.njk:
--------------------------------------------------------------------------------
1 | {% block block1 %}
Foo {% endblock %}
--------------------------------------------------------------------------------
/tests/templates/broken-conditional-include.njk:
--------------------------------------------------------------------------------
1 | {% if not whatever %}
2 | {% include "throws.njk" %}
3 | {% endif %}
4 |
--------------------------------------------------------------------------------
/tests/templates/broken-import.njk:
--------------------------------------------------------------------------------
1 | {% import 'doesnotexist' as doesnotexist %}
2 | str = {{ str | undefinedfilter }}
--------------------------------------------------------------------------------
/tests/templates/filter-block.html:
--------------------------------------------------------------------------------
1 | may the {% filter replace("force", "forth") %}{% block block1 %}bar{% endblock %}{% endfilter %} be with you
2 |
--------------------------------------------------------------------------------
/tests/templates/for-async-content.njk:
--------------------------------------------------------------------------------
1 | somecontenthere
--------------------------------------------------------------------------------
/tests/templates/import-context-set.njk:
--------------------------------------------------------------------------------
1 | {% set bar = "FOO" %}
2 |
3 | {# create a new scope #}
4 | {% for i in [1] %}
5 | {% set buzz = "buzz" %}
6 | {% endfor %}
7 |
--------------------------------------------------------------------------------
/tests/templates/import-context.njk:
--------------------------------------------------------------------------------
1 | {% macro foo() %}Here's {{ bar }}{% endmacro %}
--------------------------------------------------------------------------------
/tests/templates/import-macro-call-undefined-macro.njk:
--------------------------------------------------------------------------------
1 | {% import 'macro-call-undefined-macro.njk' as t %}
2 | {% for el in list %}
3 | {{ t.defined_macro() }}
4 | {% endfor %}
5 |
--------------------------------------------------------------------------------
/tests/templates/import.njk:
--------------------------------------------------------------------------------
1 | {% macro foo() %}Here's a macro{% endmacro %}
2 |
3 | {% set bar = 'baz' %}
4 |
5 | {% macro wrap(el) %}<{{ el }}>{{ caller() }}{{ el }}>{% endmacro %}
6 |
--------------------------------------------------------------------------------
/tests/templates/include-in-loop.njk:
--------------------------------------------------------------------------------
1 | {{ loop.index }},{{ loop.index0 }},{{ loop.first }}
2 |
--------------------------------------------------------------------------------
/tests/templates/include-set.njk:
--------------------------------------------------------------------------------
1 | {{ var }}{% set var = 2 %}{{ var }}
2 |
--------------------------------------------------------------------------------
/tests/templates/include.njk:
--------------------------------------------------------------------------------
1 | FooInclude {{ name }}
--------------------------------------------------------------------------------
/tests/templates/item.njk:
--------------------------------------------------------------------------------
1 | showing {{ item }}
--------------------------------------------------------------------------------
/tests/templates/macro-call-undefined-macro.njk:
--------------------------------------------------------------------------------
1 | {% macro defined_macro(useless) %}
2 | {% include "undefined-macro.njk" %}
3 | {% endmacro %}
4 |
--------------------------------------------------------------------------------
/tests/templates/relative/dir1/index.njk:
--------------------------------------------------------------------------------
1 | {% include "./macros.njk" %}
--------------------------------------------------------------------------------
/tests/templates/relative/dir1/macros.njk:
--------------------------------------------------------------------------------
1 | Test1
--------------------------------------------------------------------------------
/tests/templates/relative/dir2/index.njk:
--------------------------------------------------------------------------------
1 | {% include "./macros.njk" %}
--------------------------------------------------------------------------------
/tests/templates/relative/dir2/macros.njk:
--------------------------------------------------------------------------------
1 | Test2
--------------------------------------------------------------------------------
/tests/templates/relative/test-cache.njk:
--------------------------------------------------------------------------------
1 | {% include "./dir1/index.njk" %}
2 | {% include "./dir2/index.njk" %}
--------------------------------------------------------------------------------
/tests/templates/relative/test1.njk:
--------------------------------------------------------------------------------
1 | {% extends "../base.njk" %}
2 |
3 | {% block block1 %}Test1{% endblock %}
4 |
--------------------------------------------------------------------------------
/tests/templates/relative/test2.njk:
--------------------------------------------------------------------------------
1 | {% extends "./test1.njk" %}
2 |
3 | {% block block1 %}Test2{% endblock %}
4 |
--------------------------------------------------------------------------------
/tests/templates/set.njk:
--------------------------------------------------------------------------------
1 | {% set foo = "mumble" %}
--------------------------------------------------------------------------------
/tests/templates/simple-base.njk:
--------------------------------------------------------------------------------
1 | {% block test %}{% endblock test %}
2 |
--------------------------------------------------------------------------------
/tests/templates/throws.njk:
--------------------------------------------------------------------------------
1 | {{ nonExistentFn() }}
2 |
--------------------------------------------------------------------------------
/tests/templates/undefined-macro.njk:
--------------------------------------------------------------------------------
1 | {{ undef() }}
2 |
--------------------------------------------------------------------------------
/tests/test-node-pkgs/dummy-pkg/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/nunjucks/ea0d6d5396d39d9eed1b864febb36fbeca908f23/tests/test-node-pkgs/dummy-pkg/index.js
--------------------------------------------------------------------------------
/tests/test-node-pkgs/dummy-pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dummy-pkg",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "Frankie Dintino
(http://www.frankiedintino.com/)",
11 | "license": "ISC"
12 | }
13 |
--------------------------------------------------------------------------------
/tests/test-node-pkgs/dummy-pkg/simple-template.html:
--------------------------------------------------------------------------------
1 | {{ foo }}
--------------------------------------------------------------------------------