blob: 661a59c632ad7180daeb7a1fa682f853c2d696b3 [file] [log] [blame]
/**
* @license Handlebars hbs 2.0.0 - Alex Sexton, but Handlebars has its own licensing junk
*
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/require-cs for details on the plugin this was based off of
*/
/* Yes, deliciously evil. */
/*jslint evil: true, strict: false, plusplus: false, regexp: false */
/*global require: false, XMLHttpRequest: false, ActiveXObject: false,
define: false, process: false, window: false */
define(['handlebars', 'underscore'], function (Handlebars, _) {
function precompile(string, _unused, options) {
var ast, environment;
options = options || {};
if (!('data' in options)) {
options.data = true;
}
if (options.compat) {
options.useDepths = true;
}
ast = Handlebars.parse(string);
environment = new Handlebars.Compiler().compile(ast, options);
return new Handlebars.JavaScriptCompiler().compile(environment, options);
}
var fs;
var getXhr;
var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
var fetchText = function () {
throw new Error('Environment unsupported.');
};
var buildMap = [];
var filecode = 'w+';
var templateExtension = 'hbs';
var customNameExtension = '@hbs';
var devStyleDirectory = '/styles/';
var buildStyleDirectory = '/demo-build/styles/';
var helperDirectory = 'templates/helpers/';
var buildCSSFileName = 'screen.build.css';
var onHbsReadMethod = "onHbsRead";
Handlebars.registerHelper('$', function() {
//placeholder for translation helper
});
if (typeof window !== 'undefined' && window.navigator && window.document && !window.navigator.userAgent.match(/Node.js/)) {
// Browser action
getXhr = function () {
// Would love to dump the ActiveX crap in here. Need IE 6 to die first.
var xhr;
var i;
var progId;
if (typeof XMLHttpRequest !== 'undefined') {
return ((arguments[0] === true)) ? new XDomainRequest() : new XMLHttpRequest();
}
else {
for (i = 0; i < 3; i++) {
progId = progIds[i];
try {
xhr = new ActiveXObject(progId);
}
catch (e) {}
if (xhr) {
// Faster next time
progIds = [progId];
break;
}
}
}
if (!xhr) {
throw new Error('getXhr(): XMLHttpRequest not available');
}
return xhr;
};
// Returns the version of Windows Internet Explorer or a -1
// (indicating the use of another browser).
// Note: this is only for development mode. Does not run in production.
getIEVersion = function(){
// Return value assumes failure.
var rv = -1;
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
var re = new RegExp('MSIE ([0-9]{1,}[\.0-9]{0,})');
if (re.exec(ua) != null) {
rv = parseFloat( RegExp.$1 );
}
}
return rv;
};
fetchText = function (url, callback) {
var xdm = false;
// If url is a fully qualified URL, it might be a cross domain request. Check for that.
// IF url is a relative url, it cannot be cross domain.
if (url.indexOf('http') != 0 ){
xdm = false;
}else{
var uidx = (url.substr(0,5) === 'https') ? 8 : 7;
var hidx = (window.location.href.substr(0,5) === 'https') ? 8 : 7;
var dom = url.substr(uidx).split('/').shift();
var msie = getIEVersion();
xdm = ( dom != window.location.href.substr(hidx).split('/').shift() ) && (msie >= 7);
}
if ( xdm ) {
var xdr = getXhr(true);
xdr.open('GET', url);
xdr.onload = function() {
callback(xdr.responseText, url);
};
xdr.onprogress = function(){};
xdr.ontimeout = function(){};
xdr.onerror = function(){};
setTimeout(function(){
xdr.send();
}, 0);
}
else {
var xhr = getXhr();
xhr.open('GET', url, true);
xhr.onreadystatechange = function (evt) {
//Do not explicitly handle errors, those should be
//visible via console output in the browser.
if (xhr.readyState === 4) {
callback(xhr.responseText, url);
}
};
xhr.send(null);
}
};
}
else if (
typeof process !== 'undefined' &&
process.versions &&
!!process.versions.node
) {
//Using special require.nodeRequire, something added by r.js.
fs = require.nodeRequire('fs');
fetchText = function ( path, callback ) {
var body = fs.readFileSync(path, 'utf8') || '';
// we need to remove BOM stuff from the file content
body = body.replace(/^\uFEFF/, '');
callback(body, path);
};
}
else if (typeof java !== 'undefined' && typeof java.io !== 'undefined') {
fetchText = function(path, callback) {
var fis = new java.io.FileInputStream(path);
var streamReader = new java.io.InputStreamReader(fis, "UTF-8");
var reader = new java.io.BufferedReader(streamReader);
var line;
var text = '';
while ((line = reader.readLine()) !== null) {
text += new String(line) + '\n';
}
reader.close();
callback(text, path);
};
}
var cache = {};
var fetchOrGetCached = function ( path, callback ){
if ( cache[path] ){
callback(cache[path]);
}
else {
fetchText(path, function(data, path){
cache[path] = data;
callback.call(this, data);
});
}
};
var styleList = [];
var styleMap = {};
var config;
var filesToRemove = [];
return {
get: function () {
return Handlebars;
},
write: function (pluginName, name, write) {
if ( (name + customNameExtension ) in buildMap) {
var text = buildMap[name + customNameExtension];
write.asModule(pluginName + '!' + name, text);
}
},
version: '3.0.3',
load: function (name, parentRequire, load, _config) {
config = config || _config;
var compiledName = name + customNameExtension;
config.hbs = config.hbs || {};
var disableHelpers = (config.hbs.helpers == false); // be default we enable helpers unless config.hbs.helpers is false
var partialsUrl = '';
if(config.hbs.partialsUrl) {
partialsUrl = config.hbs.partialsUrl;
if(!partialsUrl.match(/\/$/)) partialsUrl += '/';
}
// Let redefine default fetchText
if(config.hbs.fetchText) {
fetchText = config.hbs.fetchText;
}
var partialDeps = [];
function recursiveNodeSearch( statements, res ) {
_(statements).forEach(function ( statement ) {
if ( statement && statement.type && statement.type === 'PartialStatement' ) {
//Don't register dynamic partials as undefined
if(statement.name.type !== "SubExpression"){
res.push(statement.name.original);
}
}
if ( statement && statement.program && statement.program.body ) {
recursiveNodeSearch( statement.program.body, res );
}
if ( statement && statement.inverse && statement.inverse.body ) {
recursiveNodeSearch( statement.inverse.body, res );
}
});
return res;
}
// TODO :: use the parser to do this!
function findPartialDeps( nodes , metaObj) {
var res = [];
if ( nodes && nodes.body ) {
res = recursiveNodeSearch( nodes.body, [] );
}
if(metaObj && metaObj.partials && metaObj.partials.length){
_(metaObj.partials).forEach(function ( partial ) {
res.push(partial);
});
}
return _.unique(res);
}
// See if the first item is a comment that's json
function getMetaData( nodes ) {
var statement, res, test;
if ( nodes && nodes.body ) {
statement = nodes.body[0];
if ( statement && statement.type === 'CommentStatement' ) {
try {
res = ( statement.value ).replace(new RegExp('^[\\s]+|[\\s]+$', 'g'), '');
test = JSON.parse(res);
return res;
}
catch (e) {
return JSON.stringify({
description: res
});
}
}
}
return '{}';
}
function composeParts ( parts ) {
if ( !parts ) {
return [];
}
var res = [parts[0]];
var cur = parts[0];
var i;
for (i = 1; i < parts.length; ++i) {
if ( parts.hasOwnProperty(i) ) {
cur += '.' + parts[i];
res.push( cur );
}
}
return res;
}
//Taken from Handlebar.AST.helpers.helperExpression with slight modification
function isHelper(statement){
return !!(statement.type === 'SubExpression' || (statement.params && statement.params.length) || statement.hash);
}
function checkStatementForHelpers(statement, helpersres){
if(isHelper(statement)){
if(typeof statement.path !== 'undefined'){
registerHelper(statement.path.original,helpersres);
}
}
if(statement && statement.params){
statement.params.forEach(function (param) {
checkStatementForHelpers(param, helpersres);
});
}
if(statement && statement.hash && statement.hash.pairs){
_(statement.hash.pairs).forEach(function(pair) {
checkStatementForHelpers(pair.value, helpersres);
});
}
}
function registerHelper(helperName,helpersres){
if(typeof Handlebars.helpers[helperName] === 'undefined'){
helpersres.push(helperName);
}
}
function recursiveVarSearch( statements, res, prefix, helpersres ) {
prefix = prefix ? prefix + '.' : '';
var newprefix = '';
var flag = false;
// loop through each statement
_(statements).forEach(function(statement) {
var parts;
var part;
var sideways;
//Its a helper or a mustache statement
if (isHelper(statement) || statement.type === 'MustacheStatement') {
checkStatementForHelpers(statement, helpersres);
}
// If it's a meta block, not sure what this is. It should probably never happen
if ( statement && statement.mustache ) {
recursiveVarSearch( [statement.mustache], res, prefix + newprefix, helpersres );
}
// if it's a whole new program
if ( statement && statement.program && statement.program.body ) {
sideways = recursiveVarSearch([statement.path],[], '', helpersres)[0] || '';
if ( statement.inverse && statement.inverse.body ) {
recursiveVarSearch( statement.inverse.body, res, prefix + newprefix + (sideways ? (prefix+newprefix) ? '.'+sideways : sideways : ''), helpersres);
}
recursiveVarSearch( statement.program.body, res, prefix + newprefix + (sideways ? (prefix+newprefix) ? '.'+sideways : sideways : ''), helpersres);
}
});
return res;
}
// This finds the Helper dependencies since it's soooo similar
function getExternalDeps( nodes ) {
var res = [];
var helpersres = [];
if ( nodes && nodes.body ) {
res = recursiveVarSearch( nodes.body, [], undefined, helpersres );
}
var defaultHelpers = [
'helperMissing',
'blockHelperMissing',
'each',
'if',
'unless',
'with',
'log',
'lookup'
];
return {
vars: _(res).chain().unique().map(function(e) {
if ( e === '' ) {
return '.';
}
if ( e.length && e[e.length-1] === '.' ) {
return e.substr(0,e.length-1) + '[]';
}
return e;
}).value(),
helpers: _(helpersres).chain().unique().map(function(e){
if ( _(defaultHelpers).contains(e) ) {
return undefined;
}
return e;
}).compact().value()
};
}
function cleanPath(path) {
var tokens = path.split('/');
for(var i=0;i<tokens.length; i++) {
if(tokens[i] === '..') {
delete tokens[i-1];
delete tokens[i];
} else if (tokens[i] === '.') {
delete tokens[i];
}
}
return tokens.join('/').replace(/\/\/+/g,'/');
}
function fetchAndRegister(langMap) {
fetchText(path, function(text, path) {
var readCallback = (config.isBuild && config[onHbsReadMethod]) ? config[onHbsReadMethod]: function(name,path,text){return text} ;
// for some reason it doesn't include hbs _first_ when i don't add it here...
var nodes = Handlebars.parse( readCallback(name, path, text));
var meta = getMetaData( nodes );
var extDeps = getExternalDeps( nodes );
var vars = extDeps.vars;
var helps = (extDeps.helpers || []);
var debugOutputStart = '';
var debugOutputEnd = '';
var debugProperties = '';
var deps = [];
var depStr, helpDepStr, metaObj, head, linkElem;
var baseDir = name.substr(0,name.lastIndexOf('/')+1);
if(meta !== '{}') {
try {
metaObj = JSON.parse(meta);
} catch(e) {
console.log('couldn\'t parse meta for %s', path);
}
}
var partials = findPartialDeps( nodes,metaObj );
config.hbs = config.hbs || {};
config.hbs._partials = config.hbs._partials || {};
for ( var i in partials ) {
if ( partials.hasOwnProperty(i) && typeof partials[i] === 'string') { // make sure string, because we're iterating over all props
var partialReference = partials[i];
var partialPath;
if(partialReference.match(/^(\.|\/)+/)) {
// relative path
partialPath = cleanPath(baseDir + partialReference);
}
else {
// absolute path relative to config.hbs.partialsUrl if defined
partialPath = cleanPath(partialsUrl + partialReference);
}
// check for recursive partials
if (omitExtension) {
if(path === parentRequire.toUrl(partialPath)) {
continue;
}
} else {
if(path === parentRequire.toUrl(partialPath +'.'+ (config.hbs && config.hbs.templateExtension ? config.hbs.templateExtension : templateExtension))) {
continue;
}
}
config.hbs._partials[partialPath] = config.hbs._partials[partialPath] || [];
// we can reference a same template with different paths (with absolute or relative)
config.hbs._partials[partialPath].references = config.hbs._partials[partialPath].references || [];
config.hbs._partials[partialPath].references.push(partialReference);
config.hbs._loadedDeps = config.hbs._loadedDeps || {};
deps[i] = "hbs!"+partialPath;
}
}
depStr = deps.join("', '");
helps = helps.concat((metaObj && metaObj.helpers) ? metaObj.helpers : []);
helpDepStr = disableHelpers ?
'' : (function (){
var i;
var paths = [];
var pathGetter = config.hbs && config.hbs.helperPathCallback
? config.hbs.helperPathCallback
: function (name){
return (config.hbs && config.hbs.helperDirectory ? config.hbs.helperDirectory : helperDirectory) + name;
};
for ( i = 0; i < helps.length; i++ ) {
paths[i] = "'" + pathGetter(helps[i], path) + "'"
}
return paths;
})().join(',');
if ( helpDepStr ) {
helpDepStr = ',' + helpDepStr;
}
if (metaObj) {
try {
if (metaObj.styles) {
styleList = _.union(styleList, metaObj.styles);
// In dev mode in the browser
if ( require.isBrowser && ! config.isBuild ) {
head = document.head || document.getElementsByTagName('head')[0];
_(metaObj.styles).forEach(function (style) {
if ( !styleMap[style] ) {
linkElem = document.createElement('link');
linkElem.href = config.baseUrl + devStyleDirectory + style + '.css';
linkElem.media = 'all';
linkElem.rel = 'stylesheet';
linkElem.type = 'text/css';
head.appendChild(linkElem);
styleMap[style] = linkElem;
}
});
}
else if ( config.isBuild ) {
(function(){
var fs = require.nodeRequire('fs');
var str = _(metaObj.styles).map(function (style) {
if (!styleMap[style]) {
styleMap[style] = true;
return '@import url('+style+'.css);\n';
}
return '';
}).join('\n');
// I write out my import statements to a file in order to help me build stuff.
// Then I use a tool to inline my import statements afterwards. (you can run r.js on it too)
fs.open(__dirname + buildStyleDirectory + buildCSSFileName, filecode, '0666', function( e, id ) {
fs.writeSync(id, str, null, encoding='utf8');
fs.close(id);
});
filecode = 'a';
})();
}
}
}
catch(e){
console.log('error injecting styles');
}
}
if ( ! config.isBuild && ! config.serverRender ) {
debugOutputStart = '<!-- START - ' + name + ' -->';
debugOutputEnd = '<!-- END - ' + name + ' -->';
debugProperties = 't.meta = ' + meta + ';\n' +
't.helpers = ' + JSON.stringify(helps) + ';\n' +
't.deps = ' + JSON.stringify(deps) + ';\n' +
't.vars = ' + JSON.stringify(vars) + ';\n';
}
var mapping = false;
var configHbs = config.hbs || {};
var options = _.extend(configHbs.compileOptions || {}, { originalKeyFallback: configHbs.originalKeyFallback });
var prec = precompile( text, mapping, options);
var tmplName = "'hbs!" + name + "',";
if(depStr) depStr = ", '"+depStr+"'";
var partialReferences = [];
if(config.hbs._partials[name])
partialReferences = config.hbs._partials[name].references;
var handlebarsPath = (config.hbs && config.hbs.handlebarsPath) ? config.hbs.handlebarsPath : 'handlebars';
text = '/* START_TEMPLATE */\n' +
'define('+tmplName+"['"+handlebarsPath+"'"+depStr+helpDepStr+'], function( Handlebars ){ \n' +
'var t = Handlebars.template(' + prec + ');\n' +
"Handlebars.registerPartial('" + name + "', t);\n";
for(var i=0; i<partialReferences.length;i++)
text += "Handlebars.registerPartial('" + partialReferences[i] + "', t);\n";
text += debugProperties +
'return t;\n' +
'});\n' +
'/* END_TEMPLATE */\n';
//Hold on to the transformed text if a build.
if (config.isBuild) {
buildMap[compiledName] = text;
}
//IE with conditional comments on cannot handle the
//sourceURL trick, so skip it if enabled.
/*@if (@_jscript) @else @*/
if (!config.isBuild) {
text += '\r\n//# sourceURL=' + path;
}
/*@end@*/
if ( !config.isBuild ) {
parentRequire( deps, function (){
load.fromText(text);
//Give result to load. Need to wait until the module
//is fully parse, which will happen after this
//execution.
parentRequire([name], function (value) {
load(value);
});
});
}
else {
load.fromText(name, text);
//Give result to load. Need to wait until the module
//is fully parse, which will happen after this
//execution.
parentRequire([name], function (value) {
load(value);
});
}
if ( config.removeCombined && path ) {
filesToRemove.push(path);
}
});
}
var path;
var omitExtension = config.hbs && config.hbs.templateExtension === false;
if (omitExtension) {
path = parentRequire.toUrl(name);
}
else {
path = parentRequire.toUrl(name +'.'+ (config.hbs && config.hbs.templateExtension ? config.hbs.templateExtension : templateExtension));
}
fetchAndRegister(false);
},
onLayerEnd: function () {
if (config.removeCombined && fs) {
filesToRemove.forEach(function (path) {
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
});
}
}
};
});
/* END_hbs_PLUGIN */