/*------------------------------------*\
$%FRONT-END PART
\*------------------------------------*/
/* jslint node: true */
/**
* Open a temlpate file.
* @private
* @function openTemplate
* @memberOf NA#
* @param {Object} currentRouteParameters Parameters set into `routes[<currentRoute>]`.
* @param {Object} templatesPath Path to template file.
* @param {openTemplate~callback} callback Next steps after opening file.
*/
exports.openTemplate = function (currentRouteParameters, templatesPath, callback) {
var NA = this,
fs = NA.modules.fs;
fs.readFile(templatesPath, 'utf-8', function (err, data) {
if (err) {
err.templatesPath = templatesPath;
if (typeof currentRouteParameters.template === 'undefined') {
NA.log(NA.appLabels.templateNotSet);
} else {
NA.log(NA.appLabels.templateNotFound.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
}
} else {
/**
* Next steps after opening file.
* @callback openTemplate~callback
* @param {string} data All HTML data from template.
*/
callback(data);
}
});
};
/**
* Open a variation file.
* @private
* @function openVariation
* @memberOf NA#
* @param {string} variationName Name of JSON file.
* @param {string} languageCode Current language for this variation.
* @param {boolean|undefined} errorDisabled Force no error message.
* @returns {Object|boolean} Return all data from JSON or false if an error occured.
*/
exports.openVariation = function (variationName, languageCode, errorDisabled) {
var NA = this,
fs = NA.modules.fs,
path = NA.modules.path,
variationsPath;
/* Find the correct path for variations. */
variationsPath = path.join(
NA.websitePhysicalPath,
NA.webconfig.variationsRelativePath,
(languageCode) ? languageCode : '',
(variationName) ? variationName : ''
);
/* Explain errors. */
function explainError(err) {
err.variationsPath = variationsPath;
if (err.code === 'ENOENT' && !errorDisabled && !languageCode) {
NA.log(NA.appLabels.variationNotFound.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
} else if (err.toString().indexOf('SyntaxError') !== -1) {
err.syntaxError = err.toString();
NA.log(NA.appLabels.variationSyntaxError.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
} else if (err.code !== 'ENOENT') {
NA.log(err);
}
return false;
}
if (typeof variationName !== 'undefined') {
try {
/* Return the variations variable into an object. */
return JSON.parse(fs.readFileSync(variationsPath, 'utf-8'));
} catch (err) {
/* Explain errors. */
explainError(err);
}
}
};
/**
* Create some variable for manage path for render.
* @private
* @function prepareRenderLanguage
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
* @param {string} path Url path for this render.
*/
exports.prepareRenderLanguage = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path) {
var NA = this;
/**
* Expose the current language code for the page if setted else expose the global if setted.
* @public
* @alias languageCode
* @type {string}
* @memberOf NA#currentVariation
* @default undefined
*/
currentVariation.languageCode =
/**
* Represent the language code for this page.
* @public
* @alias languageCode
* @type {string}
* @memberOf NA#currentRouteParameters
* @default undefined
*/
currentRouteParameters.languageCode ||
/**
* Represent the global and main language code for website.
* @public
* @alias languageCode
* @type {string}
* @memberOf NA#webconfig
* @default undefined.
*/
NA.webconfig.languageCode;
/* Next preparation render for variation. */
NA.prepareRenderPath(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path);
};
/**
* Create some variable for manage path for render.
* @private
* @function prepareRenderPath
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
* @param {string} path Url path for this render.
*/
exports.prepareRenderPath = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path) {
var NA = this;
/**
* Idem as `NA#variation.urlBasePath` without "/" at the end.
* @public
* @alias urlBasePathSlice
* @type {string}
* @memberOf NA#currentVariation
* @example http://localhost:7777/subpath
* https://www.example.here
*/
currentVariation.urlBasePathSlice = NA.webconfig.urlWithoutFileName.replace(/\/$/g, "") + NA.webconfig.urlRelativeSubPath;
/**
* Expose the current URL of page with `NA#webconfig.urlWithoutFileName` and `NA#webconfig.urlRelativeSubPath`.
* @public
* @alias urlBasePath
* @type {string}
* @memberOf NA#currentVariation
* @example http://localhost:7777/subpath/
* https://www.example.here/
*/
currentVariation.urlBasePath = currentVariation.urlBasePathSlice + '/';
/**
* Expose the current URL of page with `NA#webconfig.urlBasePath` and the current page route.
* @public
* @alias urlPath
* @type {string}
* @memberOf NA#currentVariation
* @example http://localhost:7777/subpath/example.html (if current route is '/example.html')
* https://www.example.here/example/this/ (if current route is '/example/this/')
*/
currentVariation.urlPath = currentVariation.urlBasePath.replace(/\/$/g, "") + currentPath;
if (request) {
currentVariation.urlPath = "http" + ((NA.webconfig.httpSecure) ? 's' : '') + '://' + request.get('host') + request.originalUrl;
}
/**
* Same as `NA#variations.pathname`.
* @public
* @alias pathname
* @type {string}
* @memberOf NA#currentVariation
*/
currentVariation.pathname = NA.variations.pathname;
/**
* Same as `NA#variations.filename`.
* @public
* @alias filename
* @type {string}
* @memberOf NA#currentVariation
*/
currentVariation.filename = NA.variations.filename;
console.log("urlWithoutFileName", NA.webconfig.urlWithoutFileName);
console.log("urlBasePath", currentVariation.urlBasePath);
console.log("urlPath", currentVariation.urlPath);
console.log("urlPath", currentVariation.pathname);
console.log("urlPath", currentVariation.filename);
/* Next preparation render for variation. */
NA.prepareRenderVariation(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path);
};
/**
* Create some variable for manage variation into render.
* @private
* @function prepareRenderVariation
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
* @param {string} path Url path for this render.
*/
exports.prepareRenderVariation = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path) {
var NA = this,
extend = NA.modules.extend;
if (request) {
/**
* Expose list of selector used into page.
* @public
* @alias params
* @type {string}
* @memberOf NA#currentVariation
* @example If current route is '/example/:selector/'
* At http://localhost/example/test/ the value of `NA.variations#params` is
* { "selector": "test" }
*/
currentVariation.params = request.params;
}
/**
* Name of file for `common` variation.
* @public
* @alias commonVariation
* @type {string}
* @memberOf NA#webconfig
*/
currentVariation.common = NA.openVariation(NA.webconfig.commonVariation, currentVariation.languageCode);
if (currentVariation.languageCode) {
/**
* Expose all JSON data from `commonVariation` file.
* @public
* @alias common
* @type {Object}
* @memberOf NA#currentVariation
*/
currentVariation.common = extend(true, NA.openVariation(NA.webconfig.commonVariation, undefined, true), currentVariation.common);
}
/**
* Name of file for `specific` variation.
* @public
* @alias variation
* @type {string}
* @memberOf NA#currentRouteParameters
*/
currentVariation.specific = NA.openVariation(currentRouteParameters.variation, currentVariation.languageCode);
if (currentVariation.languageCode) {
/**
* Expose all JSON data from `routes[<currentRoute>].variation` file.
* @public
* @alias specific
* @type {Object}
* @memberOf NA#currentVariation
*/
currentVariation.specific = extend(true, NA.openVariation(currentRouteParameters.variation, undefined, true), currentVariation.specific);
}
/* Nexts Step for render. */
NA.prepareRenderParameters(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path);
};
/**
* Create some variable for manage parameters into render.
* @private
* @function prepareRenderParameters
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
* @param {string} path Url path for this render.
*/
exports.prepareRenderParameters = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path) {
var NA = this;
/**
* Expose all data from `routes[<currentRoute>]` object from webconfig.
* @public
* @alias currentRouteParameters
* @type {Object}
* @memberOf NA#currentVariation
*/
currentVariation.currentRouteParameters = currentRouteParameters;
/**
* Expose the key from `<currentRoute>` object from webconfig.
* @public
* @alias currentRouteName
* @type {Object}
* @memberOf NA#currentVariation
*/
if (currentVariation.currentRouteParameters.url) {
currentVariation.currentRouteName = path;
}
/**
* Expose route of current page from current webconfig `routes`.
* @public
* @alias currentRoute
* @type {string}
* @memberOf NA#currentVariation
* @example /categories/:category/
*/
currentVariation.currentRoute = currentPath;
/**
* Expose all webconfig values.
* @public
* @alias webconfig
* @type {Object}
* @memberOf NA#currentVariation
*/
currentVariation.webconfig = NA.webconfig;
/* Nexts Step for render. */
NA.changeVariationCommon(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path);
};
/**
* Intercept Variation from common file.
* @private
* @function changeVariationCommon
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.changeVariationCommon = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath) {
var NA = this;
/* Use the `NA.websiteController[<commonController>].changeVariation(...)` function if set... */
if (typeof NA.websiteController[NA.webconfig.commonController] !== 'undefined' &&
typeof NA.websiteController[NA.webconfig.commonController].changeVariation !== 'undefined') {
/**
* Define this function for intercept Variation object and modify it. Both `common` and `specific` controller.
* @function changeVariation
* @memberOf NA#websiteController[]
* @param {Object} params Collection of property.
* @param {string} params.variation Variation object of current page.
* @param {Object} params.request Initial request.
* @param {Object} params.response Initial response.
* @param {changeVariation~callback} callback Next steps after configuration is done.
*/
NA.websiteController[NA.webconfig.commonController].changeVariation.call(NA, { variation: currentVariation, request: request, response: response },
/**
* Next steps after changeVariation is done.
* @callback changeVariation~callback
* @param {Object} [currentVariation] Variation object with new values.
*/
function (tempVariation) {
currentVariation = (tempVariation) ? tempVariation : currentVariation;
NA.changeVariationSpecific(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath);
});
/* ...else, just continue. */
} else {
NA.changeVariationSpecific(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath);
}
};
/**
* Intercept Variation from specific file.
* @private
* @function changeVariationSpecific
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.changeVariationSpecific = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath) {
var NA = this;
if (typeof NA.websiteController[currentRouteParameters.controller] !== 'undefined' &&
typeof NA.websiteController[currentRouteParameters.controller].changeVariation !== 'undefined') {
/* Use the `NA.websiteController[<controller>].changeVariation(...)` function if set... */
NA.websiteController[currentRouteParameters.controller].changeVariation.call(NA, { variation: currentVariation, request: request, response: response }, function (tempVariation) {
currentVariation = (tempVariation) ? tempVariation : currentVariation;
NA.changeDomCommon(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath);
});
} else {
/* ...else, just continue. */
NA.changeDomCommon(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath);
}
};
/**
* Intercept DOM from common file.
* @private
* @function changeDomCommon
* @memberOf NA#
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} templatesPath Path to the based template.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.changeDomCommon = function (currentVariation, currentRouteParameters, request, response, templatesPath, currentPath) {
var NA = this,
ejs = NA.modules.ejs,
pathM = NA.modules.path;
/* Open the template file */
NA.openTemplate(currentRouteParameters, templatesPath, function (data) {
/* Set the file currently in use. */
currentVariation.filename = pathM.join(currentVariation.pathname, currentRouteParameters.template);
try {
/* Transform ejs data and inject incduded file. */
data = ejs.render(data, currentVariation);
} catch (err) {
/* Make error more readable. */
data = err.toString()
.replace(/[\n]/g, "<br>")
.replace(/ /g, "<span style='display:inline-block;width:32px'></span>")
.replace(/ >> /g, "<span style='display:inline-block;width:32px'>>></span>");
}
/* Use the `NA.websiteController[<commonController>].changeDom(...)` function if set... */
if (typeof NA.websiteController[NA.webconfig.commonController] !== 'undefined' &&
typeof NA.websiteController[NA.webconfig.commonController].changeDom !== 'undefined') {
/**
* Define this function for intercept DOM and modify it with jQuery for example. Both `common` and `specific` controller.
* @function changeDom
* @memberOf NA#websiteController[]
* @param {Object} params Collection of property.
* @param {string} params.dom DOM of current page.
* @param {Object} params.request Initial request.
* @param {Object} params.response Initial response.
* @param {changeDom~callback} callback Next steps after configuration is done.
*/
NA.websiteController[NA.webconfig.commonController].changeDom.call(NA, { dom: data, variation: currentVariation, request: request, response: response },
/**
* Next steps after changeDomSpecific is done.
* @callback changeDomSpecific~callback
* @param {string} data DOM with modifications.
*/
function (data) {
NA.changeDomSpecific(data, currentVariation, currentRouteParameters, request, response, currentPath);
});
/* ...else, just continue. */
} else {
NA.changeDomSpecific(data, currentVariation, currentRouteParameters, request, response, currentPath);
}
});
};
/**
* Intercept DOM from specific file.
* @private
* @function changeDomSpecific
* @memberOf NA#
* @param {string} dom DOM Generated.
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.changeDomSpecific = function (data, currentVariation, currentRouteParameters, request, response, currentPath) {
var NA = this;
if (typeof NA.websiteController[currentRouteParameters.controller] !== 'undefined' &&
typeof NA.websiteController[currentRouteParameters.controller].changeDom !== 'undefined') {
/** Use the `NA.websiteController[<controller>].changeVariation(...)` function if set... */
NA.websiteController[currentRouteParameters.controller].changeDom.call(NA, { dom: data, variation: currentVariation, request: request, response: response }, function (data) {
NA.intoBrowserAndFiles(data, currentVariation, currentRouteParameters, request, response, currentPath);
});
} else {
/** ...else, just continue. */
NA.intoBrowserAndFiles(data, currentVariation, currentRouteParameters, request, response, currentPath);
}
};
/**
* Inject CSS into DOM if needed.
* @private
* @function intoBrowserAndFiles
* @memberOf NA#
* @param {string} data DOM Generated.
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.intoBrowserAndFiles = function (data, currentVariation, currentRouteParameters, request, response, currentPath) {
var NA = this;
/* Inject CSS into DOM... */
if (NA.webconfig.injectCss || currentRouteParameters.injectCss) {
NA.injectCss(data, currentRouteParameters.injectCss, function (data) {
NA.renderTemplate(data, currentVariation, currentRouteParameters, request, response, currentPath);
});
/* ...or do nothing. */
} else {
NA.renderTemplate(data, currentVariation, currentRouteParameters, request, response, currentPath);
}
};
/**
* Write file or/and send response.
* @private
* @function renderTemplate
* @memberOf NA#
* @param {string} data HTML DOM ready for sending.
* @param {Object} currentVariation Variations for the current page.
* @param {Object} currentRouteParameters All parameters from current route.
* @param {Object} request Information from request.
* @param {Object} response Information from response.
* @param {string} currentPath Url from `url` value for this render.
*/
exports.renderTemplate = function (data, currentVariation, currentRouteParameters, request, response, currentPath) {
var NA = this,
async = NA.modules.async,
/**
* Allow NodeAtlas to generate real file into `NA#webconfig.generatesRelativePath` directory if set to true.
* @public
* @alias htmlGeneratesBeforeResponse
* @type {boolean}
* @memberOf NA#webconfig
* @default false
*/
htmlGeneratesBeforeResponse = NA.webconfig.htmlGeneratesBeforeResponse,
htmlGenerateEnable = (typeof NA.webconfig.htmlGenerateEnable === 'boolean') ? NA.webconfig.htmlGenerateEnable : true,
templateRenderName;
/* Create the file for asset mode */
if (typeof response === 'undefined' || (htmlGeneratesBeforeResponse && htmlGenerateEnable)) {
/**
* Output name of file generate if `NA#webconfig.htmlGeneratesBeforeResponse` is set to true or if `--generate` command is used.
* If value is set to `false`, no generate page will be generated.
* @public
* @alias generate
* @type {string|boolean}
* @memberOf NA#currentRouteParameters
*/
templateRenderName = currentPath;
if (typeof currentRouteParameters.generate !== 'undefined') {
templateRenderName = currentRouteParameters.generate;
}
NA.saveTemplateRender(data, templateRenderName);
}
/* Run page into browser. */
if (typeof response !== 'undefined') {
/* Compression of CSS, JS and Images if required. */
async.parallel([
NA.cssCompilation.bind(NA),
NA.jsObfuscation.bind(NA),
NA.imgOptimization.bind(NA)
], function () {
NA.response(request, response, data, currentRouteParameters, currentVariation);
});
}
};
/**
* Generate the HTML output for send to client.
* @private
* @function render
* @memberOf NA#
* @param {string} path The url listening.
* @param {Object} options Option associate to this url.
* @param {Object} request Initial request.
* @param {Object} response Initial response.
*/
exports.render = function (path, options, request, response) {
var NA = this,
pathM = NA.modules.path,
/**
* All parameters from a specific page.
* @namespace currentRouteParameters
* @public
* @alias currentRouteParameters
* @type {Object}
* @memberOf NA#
*/
currentRouteParameters = options[path],
templatesPath,
/**
* All variation for a specific page.
* @namespace currentVariation
* @public
* @alias currentVariation
* @type {Object}
* @memberOf NA#
*/
currentVariation = {},
currentPath = path;
/* Inject template shortcut to template. */
if (typeof currentRouteParameters === 'string') {
/* templatesPath is just use like temp var in this if statement. */
templatesPath = currentRouteParameters;
currentRouteParameters = {};
/**
* This is the file name of template used for render of page behind the route.
* @public
* @alias template
* @type {string}
* @memberOf NA#currentRouteParameters
*/
currentRouteParameters.template = templatesPath;
}
/* Generate the server path to the template file. */
templatesPath = pathM.join(
NA.websitePhysicalPath,
NA.webconfig.templatesRelativePath,
(currentRouteParameters.template) ? currentRouteParameters.template : ""
);
/* Case of `currentRouteParameters.url` replace `path` because `path` is used like a key. */
if (currentRouteParameters.url) {
currentPath = currentRouteParameters.url;
}
/* Loading the controller file if `currentRouteParameters.controller` exist. */
NA.loadController(
/**
* This is the file name of specific controller used for back-end part of this page.
* @public
* @alias controller
* @type {string}
* @memberOf NA#currentRouteParameters
*/
currentRouteParameters.controller,
function () {
/* Next preparation path render. */
NA.prepareRenderLanguage(currentVariation, currentRouteParameters, request, response, templatesPath, currentPath, path);
}
);
};