Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
82e77a26
Commit
82e77a26
authored
12 years ago
by
Chris Dodge
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add mustache.js to common static repo
parent
90861c22
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
613 additions
and
0 deletions
+613
-0
common/static/js/vendor/mustache.js
+613
-0
No files found.
common/static/js/vendor/mustache.js
0 → 100644
View file @
82e77a26
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
var
Mustache
;
(
function
(
exports
)
{
if
(
typeof
module
!==
"undefined"
)
{
module
.
exports
=
exports
;
// CommonJS
}
else
if
(
typeof
define
===
"function"
)
{
define
(
exports
);
// AMD
}
else
{
Mustache
=
exports
;
// <script>
}
}(
function
()
{
var
exports
=
{};
exports
.
name
=
"mustache.js"
;
exports
.
version
=
"0.5.1-dev"
;
exports
.
tags
=
[
"{{"
,
"}}"
];
exports
.
parse
=
parse
;
exports
.
clearCache
=
clearCache
;
exports
.
compile
=
compile
;
exports
.
compilePartial
=
compilePartial
;
exports
.
render
=
render
;
exports
.
Scanner
=
Scanner
;
exports
.
Context
=
Context
;
exports
.
Renderer
=
Renderer
;
// This is here for backwards compatibility with 0.4.x.
exports
.
to_html
=
function
(
template
,
view
,
partials
,
send
)
{
var
result
=
render
(
template
,
view
,
partials
);
if
(
typeof
send
===
"function"
)
{
send
(
result
);
}
else
{
return
result
;
}
};
var
whiteRe
=
/
\s
*/
;
var
spaceRe
=
/
\s
+/
;
var
nonSpaceRe
=
/
\S
/
;
var
eqRe
=
/
\s
*=/
;
var
curlyRe
=
/
\s
*
\}
/
;
var
tagRe
=
/#|
\^
|
\/
|>|
\{
|&|=|!/
;
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
// See https://github.com/janl/mustache.js/issues/189
function
testRe
(
re
,
string
)
{
return
RegExp
.
prototype
.
test
.
call
(
re
,
string
);
}
function
isWhitespace
(
string
)
{
return
!
testRe
(
nonSpaceRe
,
string
);
}
var
isArray
=
Array
.
isArray
||
function
(
obj
)
{
return
Object
.
prototype
.
toString
.
call
(
obj
)
===
"[object Array]"
;
};
// OSWASP Guidelines: escape all non alphanumeric characters in ASCII space.
var
jsCharsRe
=
/
[\x
00-
\x
2F
\x
3A-
\x
40
\x
5B-
\x
60
\x
7B-
\x
FF
\u
2028
\u
2029
]
/gm
;
function
quote
(
text
)
{
var
escaped
=
text
.
replace
(
jsCharsRe
,
function
(
c
)
{
return
"
\\
u"
+
(
'0000'
+
c
.
charCodeAt
(
0
).
toString
(
16
)).
slice
(
-
4
);
});
return
'"'
+
escaped
+
'"'
;
}
function
escapeRe
(
string
)
{
return
string
.
replace
(
/
[\-\[\]
{}()*+?.,
\\\^
$|#
\s]
/g
,
"
\\
$&"
);
}
var
entityMap
=
{
"&"
:
"&"
,
"<"
:
"<"
,
">"
:
">"
,
'"'
:
'"'
,
"'"
:
'''
,
"/"
:
'/'
};
function
escapeHtml
(
string
)
{
return
String
(
string
).
replace
(
/
[
&<>"'
\/]
/g
,
function
(
s
)
{
return
entityMap
[
s
];
});
}
// Export these utility functions.
exports
.
isWhitespace
=
isWhitespace
;
exports
.
isArray
=
isArray
;
exports
.
quote
=
quote
;
exports
.
escapeRe
=
escapeRe
;
exports
.
escapeHtml
=
escapeHtml
;
function
Scanner
(
string
)
{
this
.
string
=
string
;
this
.
tail
=
string
;
this
.
pos
=
0
;
}
/**
* Returns `true` if the tail is empty (end of string).
*/
Scanner
.
prototype
.
eos
=
function
()
{
return
this
.
tail
===
""
;
};
/**
* Tries to match the given regular expression at the current position.
* Returns the matched text if it can match, `null` otherwise.
*/
Scanner
.
prototype
.
scan
=
function
(
re
)
{
var
match
=
this
.
tail
.
match
(
re
);
if
(
match
&&
match
.
index
===
0
)
{
this
.
tail
=
this
.
tail
.
substring
(
match
[
0
].
length
);
this
.
pos
+=
match
[
0
].
length
;
return
match
[
0
];
}
return
null
;
};
/**
* Skips all text until the given regular expression can be matched. Returns
* the skipped string, which is the entire tail of this scanner if no match
* can be made.
*/
Scanner
.
prototype
.
scanUntil
=
function
(
re
)
{
var
match
,
pos
=
this
.
tail
.
search
(
re
);
switch
(
pos
)
{
case
-
1
:
match
=
this
.
tail
;
this
.
pos
+=
this
.
tail
.
length
;
this
.
tail
=
""
;
break
;
case
0
:
match
=
null
;
break
;
default
:
match
=
this
.
tail
.
substring
(
0
,
pos
);
this
.
tail
=
this
.
tail
.
substring
(
pos
);
this
.
pos
+=
pos
;
}
return
match
;
};
function
Context
(
view
,
parent
)
{
this
.
view
=
view
;
this
.
parent
=
parent
;
this
.
clearCache
();
}
Context
.
make
=
function
(
view
)
{
return
(
view
instanceof
Context
)
?
view
:
new
Context
(
view
);
};
Context
.
prototype
.
clearCache
=
function
()
{
this
.
_cache
=
{};
};
Context
.
prototype
.
push
=
function
(
view
)
{
return
new
Context
(
view
,
this
);
};
Context
.
prototype
.
lookup
=
function
(
name
)
{
var
value
=
this
.
_cache
[
name
];
if
(
!
value
)
{
if
(
name
===
"."
)
{
value
=
this
.
view
;
}
else
{
var
context
=
this
;
while
(
context
)
{
if
(
name
.
indexOf
(
"."
)
>
0
)
{
var
names
=
name
.
split
(
"."
),
i
=
0
;
value
=
context
.
view
;
while
(
value
&&
i
<
names
.
length
)
{
value
=
value
[
names
[
i
++
]];
}
}
else
{
value
=
context
.
view
[
name
];
}
if
(
value
!=
null
)
{
break
;
}
context
=
context
.
parent
;
}
}
this
.
_cache
[
name
]
=
value
;
}
if
(
typeof
value
===
"function"
)
{
value
=
value
.
call
(
this
.
view
);
}
return
value
;
};
function
Renderer
()
{
this
.
clearCache
();
}
Renderer
.
prototype
.
clearCache
=
function
()
{
this
.
_cache
=
{};
this
.
_partialCache
=
{};
};
Renderer
.
prototype
.
compile
=
function
(
tokens
,
tags
)
{
if
(
typeof
tokens
===
"string"
)
{
tokens
=
parse
(
tokens
,
tags
);
}
var
fn
=
compileTokens
(
tokens
),
self
=
this
;
return
function
(
view
)
{
return
fn
(
Context
.
make
(
view
),
self
);
};
};
Renderer
.
prototype
.
compilePartial
=
function
(
name
,
tokens
,
tags
)
{
this
.
_partialCache
[
name
]
=
this
.
compile
(
tokens
,
tags
);
return
this
.
_partialCache
[
name
];
};
Renderer
.
prototype
.
render
=
function
(
template
,
view
)
{
var
fn
=
this
.
_cache
[
template
];
if
(
!
fn
)
{
fn
=
this
.
compile
(
template
);
this
.
_cache
[
template
]
=
fn
;
}
return
fn
(
view
);
};
Renderer
.
prototype
.
_section
=
function
(
name
,
context
,
callback
)
{
var
value
=
context
.
lookup
(
name
);
switch
(
typeof
value
)
{
case
"object"
:
if
(
isArray
(
value
))
{
var
buffer
=
""
;
for
(
var
i
=
0
,
len
=
value
.
length
;
i
<
len
;
++
i
)
{
buffer
+=
callback
(
context
.
push
(
value
[
i
]),
this
);
}
return
buffer
;
}
return
value
?
callback
(
context
.
push
(
value
),
this
)
:
""
;
case
"function"
:
// TODO: The text should be passed to the callback plain, not rendered.
var
sectionText
=
callback
(
context
,
this
),
self
=
this
;
var
scopedRender
=
function
(
template
)
{
return
self
.
render
(
template
,
context
);
};
return
value
.
call
(
context
.
view
,
sectionText
,
scopedRender
)
||
""
;
default
:
if
(
value
)
{
return
callback
(
context
,
this
);
}
}
return
""
;
};
Renderer
.
prototype
.
_inverted
=
function
(
name
,
context
,
callback
)
{
var
value
=
context
.
lookup
(
name
);
// From the spec: inverted sections may render text once based on the
// inverse value of the key. That is, they will be rendered if the key
// doesn't exist, is false, or is an empty list.
if
(
value
==
null
||
value
===
false
||
(
isArray
(
value
)
&&
value
.
length
===
0
))
{
return
callback
(
context
,
this
);
}
return
""
;
};
Renderer
.
prototype
.
_partial
=
function
(
name
,
context
)
{
var
fn
=
this
.
_partialCache
[
name
];
if
(
fn
)
{
return
fn
(
context
,
this
);
}
return
""
;
};
Renderer
.
prototype
.
_name
=
function
(
name
,
context
,
escape
)
{
var
value
=
context
.
lookup
(
name
);
if
(
typeof
value
===
"function"
)
{
value
=
value
.
call
(
context
.
view
);
}
var
string
=
(
value
==
null
)
?
""
:
String
(
value
);
if
(
escape
)
{
return
escapeHtml
(
string
);
}
return
string
;
};
/**
* Low-level function that compiles the given `tokens` into a
* function that accepts two arguments: a Context and a
* Renderer. Returns the body of the function as a string if
* `returnBody` is true.
*/
function
compileTokens
(
tokens
,
returnBody
)
{
var
body
=
[
'""'
];
var
token
,
method
,
escape
;
for
(
var
i
=
0
,
len
=
tokens
.
length
;
i
<
len
;
++
i
)
{
token
=
tokens
[
i
];
switch
(
token
.
type
)
{
case
"#"
:
case
"^"
:
method
=
(
token
.
type
===
"#"
)
?
"_section"
:
"_inverted"
;
body
.
push
(
"r."
+
method
+
"("
+
quote
(
token
.
value
)
+
", c, function (c, r) {
\
n"
+
" "
+
compileTokens
(
token
.
tokens
,
true
)
+
"
\
n"
+
"})"
);
break
;
case
"{"
:
case
"&"
:
case
"name"
:
escape
=
token
.
type
===
"name"
?
"true"
:
"false"
;
body
.
push
(
"r._name("
+
quote
(
token
.
value
)
+
", c, "
+
escape
+
")"
);
break
;
case
">"
:
body
.
push
(
"r._partial("
+
quote
(
token
.
value
)
+
", c)"
);
break
;
case
"text"
:
body
.
push
(
quote
(
token
.
value
));
break
;
}
}
// Convert to a string body.
body
=
"return "
+
body
.
join
(
" + "
)
+
";"
;
// Good for debugging.
// console.log(body);
if
(
returnBody
)
{
return
body
;
}
// For great evil!
return
new
Function
(
"c, r"
,
body
);
}
function
escapeTags
(
tags
)
{
if
(
tags
.
length
===
2
)
{
return
[
new
RegExp
(
escapeRe
(
tags
[
0
])
+
"
\\
s*"
),
new
RegExp
(
"
\\
s*"
+
escapeRe
(
tags
[
1
]))
];
}
throw
new
Error
(
"Invalid tags: "
+
tags
.
join
(
" "
));
}
/**
* Forms the given linear array of `tokens` into a nested tree structure
* where tokens that represent a section have a "tokens" array property
* that contains all tokens that are in that section.
*/
function
nestTokens
(
tokens
)
{
var
tree
=
[];
var
collector
=
tree
;
var
sections
=
[];
var
token
,
section
;
for
(
var
i
=
0
;
i
<
tokens
.
length
;
++
i
)
{
token
=
tokens
[
i
];
switch
(
token
.
type
)
{
case
"#"
:
case
"^"
:
token
.
tokens
=
[];
sections
.
push
(
token
);
collector
.
push
(
token
);
collector
=
token
.
tokens
;
break
;
case
"/"
:
if
(
sections
.
length
===
0
)
{
throw
new
Error
(
"Unopened section: "
+
token
.
value
);
}
section
=
sections
.
pop
();
if
(
section
.
value
!==
token
.
value
)
{
throw
new
Error
(
"Unclosed section: "
+
section
.
value
);
}
if
(
sections
.
length
>
0
)
{
collector
=
sections
[
sections
.
length
-
1
].
tokens
;
}
else
{
collector
=
tree
;
}
break
;
default
:
collector
.
push
(
token
);
}
}
// Make sure there were no open sections when we're done.
section
=
sections
.
pop
();
if
(
section
)
{
throw
new
Error
(
"Unclosed section: "
+
section
.
value
);
}
return
tree
;
}
/**
* Combines the values of consecutive text tokens in the given `tokens` array
* to a single token.
*/
function
squashTokens
(
tokens
)
{
var
lastToken
;
for
(
var
i
=
0
;
i
<
tokens
.
length
;
++
i
)
{
var
token
=
tokens
[
i
];
if
(
lastToken
&&
lastToken
.
type
===
"text"
&&
token
.
type
===
"text"
)
{
lastToken
.
value
+=
token
.
value
;
tokens
.
splice
(
i
--
,
1
);
// Remove this token from the array.
}
else
{
lastToken
=
token
;
}
}
}
/**
* Breaks up the given `template` string into a tree of token objects. If
* `tags` is given here it must be an array with two string values: the
* opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
* course, the default is to use mustaches (i.e. Mustache.tags).
*/
function
parse
(
template
,
tags
)
{
tags
=
tags
||
exports
.
tags
;
var
tagRes
=
escapeTags
(
tags
);
var
scanner
=
new
Scanner
(
template
);
var
tokens
=
[],
// Buffer to hold the tokens
spaces
=
[],
// Indices of whitespace tokens on the current line
hasTag
=
false
,
// Is there a {{tag}} on the current line?
nonSpace
=
false
;
// Is there a non-space char on the current line?
// Strips all whitespace tokens array for the current line
// if there was a {{#tag}} on it and otherwise only space.
var
stripSpace
=
function
()
{
if
(
hasTag
&&
!
nonSpace
)
{
while
(
spaces
.
length
)
{
tokens
.
splice
(
spaces
.
pop
(),
1
);
}
}
else
{
spaces
=
[];
}
hasTag
=
false
;
nonSpace
=
false
;
};
var
type
,
value
,
chr
;
while
(
!
scanner
.
eos
())
{
value
=
scanner
.
scanUntil
(
tagRes
[
0
]);
if
(
value
)
{
for
(
var
i
=
0
,
len
=
value
.
length
;
i
<
len
;
++
i
)
{
chr
=
value
.
charAt
(
i
);
if
(
isWhitespace
(
chr
))
{
spaces
.
push
(
tokens
.
length
);
}
else
{
nonSpace
=
true
;
}
tokens
.
push
({
type
:
"text"
,
value
:
chr
});
if
(
chr
===
"
\
n"
)
{
stripSpace
();
// Check for whitespace on the current line.
}
}
}
// Match the opening tag.
if
(
!
scanner
.
scan
(
tagRes
[
0
]))
{
break
;
}
hasTag
=
true
;
type
=
scanner
.
scan
(
tagRe
)
||
"name"
;
// Skip any whitespace between tag and value.
scanner
.
scan
(
whiteRe
);
// Extract the tag value.
if
(
type
===
"="
)
{
value
=
scanner
.
scanUntil
(
eqRe
);
scanner
.
scan
(
eqRe
);
scanner
.
scanUntil
(
tagRes
[
1
]);
}
else
if
(
type
===
"{"
)
{
var
closeRe
=
new
RegExp
(
"
\\
s*"
+
escapeRe
(
"}"
+
tags
[
1
]));
value
=
scanner
.
scanUntil
(
closeRe
);
scanner
.
scan
(
curlyRe
);
scanner
.
scanUntil
(
tagRes
[
1
]);
}
else
{
value
=
scanner
.
scanUntil
(
tagRes
[
1
]);
}
// Match the closing tag.
if
(
!
scanner
.
scan
(
tagRes
[
1
]))
{
throw
new
Error
(
"Unclosed tag at "
+
scanner
.
pos
);
}
tokens
.
push
({
type
:
type
,
value
:
value
});
if
(
type
===
"name"
||
type
===
"{"
||
type
===
"&"
)
{
nonSpace
=
true
;
}
// Set the tags for the next time around.
if
(
type
===
"="
)
{
tags
=
value
.
split
(
spaceRe
);
tagRes
=
escapeTags
(
tags
);
}
}
squashTokens
(
tokens
);
return
nestTokens
(
tokens
);
}
// The high-level clearCache, compile, compilePartial, and render functions
// use this default renderer.
var
_renderer
=
new
Renderer
();
/**
* Clears all cached templates and partials.
*/
function
clearCache
()
{
_renderer
.
clearCache
();
}
/**
* High-level API for compiling the given `tokens` down to a reusable
* function. If `tokens` is a string it will be parsed using the given `tags`
* before it is compiled.
*/
function
compile
(
tokens
,
tags
)
{
return
_renderer
.
compile
(
tokens
,
tags
);
}
/**
* High-level API for compiling the `tokens` for the partial with the given
* `name` down to a reusable function. If `tokens` is a string it will be
* parsed using the given `tags` before it is compiled.
*/
function
compilePartial
(
name
,
tokens
,
tags
)
{
return
_renderer
.
compilePartial
(
name
,
tokens
,
tags
);
}
/**
* High-level API for rendering the `template` using the given `view`. The
* optional `partials` object may be given here for convenience, but note that
* it will cause all partials to be re-compiled, thus hurting performance. Of
* course, this only matters if you're going to render the same template more
* than once. If so, it is best to call `compilePartial` before calling this
* function and to leave the `partials` argument blank.
*/
function
render
(
template
,
view
,
partials
)
{
if
(
partials
)
{
for
(
var
name
in
partials
)
{
compilePartial
(
name
,
partials
[
name
]);
}
}
return
_renderer
.
render
(
template
,
view
);
}
return
exports
;
}()));
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment