src/factories/$TemplateCache.js
/**
* @module $TemplateCache.js
* @author Joe Groseclose <@benderTheCrime>
* @date 8/16/2015
*/
// System Modules
import fs from 'fs';
import {default as $Injector} from 'angie-injector';
// Angie Modules
import {config} from '../Config';
import $CacheFactory from './$CacheFactory';
import {
$StringUtil,
$FileUtil
} from '../util/Util';
class $TemplateCache extends $CacheFactory {
constructor() {
super('templateCache');
}
get(url) {
let template = super.get(url);
if (!template) {
template = $$templateLoader(url);
}
if (template && config.cacheStaticAssets) {
this.put(url, template);
}
return template;
}
}
// TODO remove static dir conglomeration to constants!!
function $$templateLoader(url, type = 'template', encoding) {
// Clone the template dirs
const TEMPLATE_DIRS = $Injector.get('ANGIE_TEMPLATE_DIRS');
let template;
// Deliberately use a for loop so that we can break out of it
for (var i = TEMPLATE_DIRS.length - 1; i >= 0; --i) {
let dir = TEMPLATE_DIRS[i],
path = $FileUtil.find(dir, url);
if (typeof path === 'string') {
template = fs.readFileSync(path, encoding || undefined);
}
if (template) {
break;
}
}
if (!template) {
return false;
} else if (
type === 'static' &&
config.hasOwnProperty('cacheStaticAssets') &&
config.cacheStaticAssets === true
) {
// TODO you may want to put this in the asset loading block
new $CacheFactory('staticAssets').put(url, template);
}
return template;
}
/**
* @desc $resourceLoader is a factory that will attach a JavaScript resource
* to any respose. It will attach it inside of the body if the file is requested
* to be attached on an HTML response.
* @since 0.3.2
* @todo Make this work with .css, .less, .scss, .haml
* @todo Auto load Angular, jQuery, Underscore, etc. from their names alone
* via Bower installs. Must create bower.json & bump bower version.
* @param {string|Array} [param=10] filename Valid JS filename in Angie static
* directories
* @param {string} [param='src'] loadStyle How is this resource attached to the
* document. Options:
* 'src': Include a script tag with the name of the resource
* 'inline': Include the resource content inline
* @returns {boolean} Whether this function successfully finished (not an
* indication that the resource was actually attached)
* @access public
* @example $resourceLoader('test.js');
*/
function $resourceLoader(files = [], loadStyle = 'src') {
let [ $request, $response ] = $Injector.get('$request', '$response');
if (
!$request || typeof $request !== 'object' ||
!$response || typeof $response !== 'object'
) {
return false;
} else if (!$response.content) {
// Just in case the response property was not already defined
$response.content = '';
}
if (typeof files === 'string') {
files = [ files ];
}
files.forEach(function(resource) {
// Return if not a js file
if (resource.split('.').pop() !== 'js') {
return;
}
// TODO put this into a template?
let asset = '<script type="text/javascript"';
if (loadStyle === 'src') {
asset += ` src="${[
$StringUtil.removeTrailingSlashes($request.path)
.replace(/([A-Za-z]+)/g, '..'),
resource
].join('/')}">`;
} else {
let assetCache = new $CacheFactory('staticAssets'),
assetPath = resource.split('/').pop(),
staticAsset;
asset += '>';
if (assetCache.get(assetPath)) {
staticAsset = assetCache.get(assetPath);
} else {
assetCache.put(
assetPath,
staticAsset = $$templateLoader(assetPath, 'static', 'utf8')
);
}
if (staticAsset.length) {
asset += staticAsset;
}
}
asset += '</script>';
const BODY = '</body>',
STR = $response.content;
if (STR.indexOf(BODY) > -1) {
let body = STR.lastIndexOf(BODY);
$response.content =
`${STR.substr(0, body)}${asset}${STR.substr(body)}`;
} else {
$response.content = $response.content + asset;
}
});
// For testing purposes
return true;
}
const $templateCache = new $TemplateCache();
export {
$templateCache,
$$templateLoader,
$resourceLoader
};