UNPKG

13.7 kBHTMLView Raw
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>JSDoc: Source: adapters/html_content.js</title>
6
7 <script src="scripts/prettify/prettify.js"> </script>
8 <script src="scripts/prettify/lang-css.js"> </script>
9 <!--[if lt IE 9]>
10 <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13 <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14</head>
15
16<body>
17
18<div id="main">
19
20 <h1 class="page-title">Source: adapters/html_content.js</h1>
21
22
23
24
25
26
27 <section>
28 <article>
29 <pre class="prettyprint source linenums"><code>'use strict';
30const path = require('path');
31const Promisie = require('promisie');
32const ejs = require('ejs');
33const fs = Promisie.promisifyAll(require('fs-extra'));
34const JSON_Adapter = require(path.join(__dirname, './json_content'));
35
36/**
37 * Iterates through an array of file paths resolving after it finds a valid path or resolves with the default value
38 * @param {string} _default A default value to resolve if no provided file path is valid
39 * @param {string[]} [dirs=[]] File paths to check for validity (file exists)
40 * @return {Object} Returns a Promise which resolves with a file path or the default value
41 */
42var findValidViewFromPaths = function (_default, dirs = []) {
43 if (!dirs.length) return Promisie.resolve(_default);
44 return Promisie.retry(() => {
45 let filePath = dirs.shift();
46 return fs.statAsync(filePath)
47 .then(() => filePath, e => Promise.reject(e));
48 }, { times: dirs.length, timeout: 0 })
49 .then(fp => fp)
50 .catch(() => _default);
51};
52
53/**
54 * Renders an HTML string from provided data
55 * @param {Object} data Template data should conform to EJS template by default or custom templating engine
56 * @param {Object} options Configurable options for the rendering of HTML string
57 * @param {string} [options.themename=this.themename] Specifies a periodic theme folder that will be checked when looking for a matching template
58 * @param {string} [options.viewname=this.viewname] Specifies the filename of the template
59 * @param {string} [options.extname=this.extname] Specifies a periodicjs extension folder that should be checked when looking for a matching template
60 * @param {Boolean} [options.resolve_filepath] If true a valid file path will be returned and rendering of the template file will be skipped
61 * @param {string} [options.fileext=this.fileext] Specifies the extension name of the template file
62 * @param {string|string[]} [options.dirname] Optional custom directories to be checked for template
63 * @param {Object} [options.engine_configuration=this.engine_configuration] Custom configuration object for whichever templating engine being used see EJS documentation for details on options for EJS
64 * @param {Function} cb Callback function
65 */
66const _RENDER = function (data, options) {
67 try {
68 let { themename, viewname, extname, fileext } = ['themename','viewname','extname','fileext'].reduce((result, key) => {
69 result[key] = options[key] || this[key];
70 return result;
71 }, {});
72 if (typeof viewname !== 'string') throw new TypeError('viewname must be specified in order to render template');
73 let dirs = [];
74 if (options.dirname) {
75 if (Array.isArray(options.dirname)) options.dirname.forEach(dir => dirs.push(path.join(dir, `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`)));
76 else dirs.push(path.join(options.dirname, `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`));
77 }
78 if (typeof themename == 'string' &amp;&amp; typeof fileext === 'string') dirs.push(path.join(__dirname, '../../../content/themes', themename, 'views', `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`));
79 if (typeof extname === 'string' &amp;&amp; typeof fileext === 'string') dirs.push(path.join(__dirname, '../../', extname, 'views', `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`));
80 dirs.push(path.join(__dirname, '../../../app/views', `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`));
81 if (options.resolve_filepath === true) return findValidViewFromPaths(viewname, dirs);
82 return findValidViewFromPaths(`${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`, dirs)
83 .then(filePath => Promisie.all(fs.readFileAsync(filePath, 'utf8'), filePath))
84 .spread((filestr, filename) => {
85 filestr = filestr.toString();
86 return Promisie.resolve(this.engine.render(filestr, data, Object.assign({ filename }, options.engine_configuration || this.engine_configuration)));
87 })
88 .catch(e => Promisie.reject(e));
89 }
90 catch (e) {
91 return Promisie.reject(e);
92 }
93};
94
95/**
96 * Renders an HTML error page template
97 * @param {Object} err If err is an instanceof Error or has a .message property only the error message will be included
98 * @param {Object} options Configurable options for error template rendering see _RENDER for further details on options
99 * @param {string} [options.viewname="home/error404"] Overrideable view name for the error template
100 * @param {Function} cb Callback function
101 */
102const _ERROR = function (err, options) {
103 try {
104 if (this.custom_error_path) options.viewname = (options.viewname) ? path.join(this.custom_error_path, options.viewname) : path.join(this.custom_error_path, 'home/error404');
105 else options.viewname = options.viewname || 'home/error404';
106 return _RENDER.call(this, Object.assign({ flash_messages: {} }, options.locals || {}, {
107 pagedata: { title: 'Not Found', error: (err instanceof Error || err.message) ? err.message : err },
108 url: options.viewname
109 }), options);
110 }
111 catch (e) {
112 return Promise.reject(e);
113 }
114};
115
116/**
117 * HTML response adapter class which renders templates from provided data and template names
118 * @type {HTML_Adapter}
119 * @extends {JSON_Adapter}
120 */
121const HTML_ADAPTER = class HTML_Adapter extends JSON_Adapter {
122 /**
123 * @constructor
124 * @param {Object} options Configurable options for HTML adapter
125 * @param {Object} [options.engine=ejs] Defines which templating engine to use when rendering template files
126 * @param {Function} options.engine.render If providing a custom rendering engine module must include a .render function which is synchronous or returns a Promise. Render function should also expect the following arguments in this order: (template_string, template_data, options)
127 * @param {Object} [options.engine_configuration] Defines a default set of configuration options that are passed to the rendering function
128 * @param {string} [options.extname] Name of a periodicjs extension. Used in finding valid template
129 * @param {string} [options.themename="periodicjs.theme.default"] Name of a periodicjs theme. Used in finding valid template
130 * @param {Object} [options.locals={}] Shared local values for rendering. Only used when express rendering is not available.
131 * @param {string} [options.viewname] Defines a default view name that should be used in rendering
132 * @param {string} [options.fileext=".ejs"] Defines the default extension name of the template file
133 */
134 constructor (options = {}) {
135 super(options);
136 this.engine = (options.engine &amp;&amp; typeof options.engine.render === 'function') ? options.engine : ejs;
137 this.engine_configuration = options.engine_configuration;
138 this.extname = options.extname;
139 this.themename = options.themename || 'periodicjs.theme.default';
140 this.viewname = options.viewname;
141 this.fileext = options.fileext || '.ejs';
142 this.locals = (options.locals &amp;&amp; typeof options.locals === 'object') ? options.locals : {};
143 this.custom_error_path = options.custom_error_path;
144 }
145 /**
146 * Renders HTML from provided data and template
147 * @param {Object} data Data that is passed to render template
148 * @param {Object} [options={}] Configurable options for rendering see _RENDER for full details
149 * @param {Function} [options.formatRender=_RENDER] Custom rendering function. It is not recommended to override the default value of this property and may no longer work properly
150 * @param {Object} [options.req] Express request object. If options.req and options.res are defined the express .render method will be used to render template
151 * @param {Object} [options.res] Express response object. If options.res and options.req are defined the express .render method will be used to render template
152 * @param {Boolean} [options.skip_response] If true function will resolve with the rendered template instead of sending a response
153 * @param {Function} cb Optional callback function. If arugment is not passed function will
154 * @return {Object} Returns a Promise if cb arguement is not provided
155 */
156 render (data, options = {}, cb = false) {
157 if (typeof options === 'function') {
158 cb = options;
159 options = {};
160 }
161 if (options.req &amp;&amp; options.res) {
162 data.flash_messages = (typeof options.req.flash === 'function') ? options.req.flash() : {};
163 return _RENDER.call(this, {}, Object.assign(options, { resolve_filepath: true }))
164 .then(filepath => Promisie.promisify(options.res.render, options.res)(filepath, data))
165 .then(rendered => {
166 if (typeof cb === 'function') cb(null, rendered);
167 else if (options.skip_response &amp;&amp; typeof cb !== 'function') return Promisie.resolve(rendered);
168 else {
169 options.res.status(200).send(rendered);
170 return Promisie.resolve(rendered);
171 }
172 })
173 .catch(err => this.error(err, options, cb));
174 }
175 else {
176 options.formatRender = (typeof options.formatRender === 'function') ? options.formatRender : _RENDER.bind(this);
177 options.sync = true;
178 return super.render(Object.assign({ flash_messages: {} }, this.locals, data), options)
179 .then(result => {
180 if (typeof cb === 'function') cb(null, result);
181 else return result;
182 }, e => {
183 if (typeof cb === 'function') cb(e);
184 else return Promisie.reject(e);
185 });
186 }
187 }
188 /**
189 * Renders error view from template
190 * @param {*} err Any error data that should be passed to template
191 * @param {Object} [options={}] Configurable options for rendering see _ERROR for full details
192 * @param {Function} [options.formatError=_RENDER] Custom rendering function. It is not recommended to override the default value of this property and may no longer work properly
193 * @param {Object} [options.req] Express request object. If options.req and options.res are defined the express .render method will be used to render template
194 * @param {Object} [options.res] Express response object. If options.res and options.req are defined the express .render method will be used to render template
195 * @param {Boolean} [options.skip_response] If true function will resolve with the rendered
196 * @param {Function} cb Optional callback function. If arugment is not passed function will
197 * @return {Object} Returns a Promise if cb arguement is not provided
198 */
199 error (err, options = {}, cb = false) {
200 if (typeof options === 'function') {
201 cb = options;
202 options = {};
203 }
204 if (options.req &amp;&amp; options.res) {
205 let flash_messages = (typeof options.req.flash === 'function') ? options.req.flash() : {};
206 if (options.dirname &amp;&amp; this.custom_error_path) options.dirname = (Array.isArray(options.dirname)) ? options.dirname.concat(this.custom_error_path) : [options.dirname].concat(this.custom_error_path);
207 else if (!options.dirname &amp;&amp; this.custom_error_path) options.dirname = this.custom_error_path;
208 return _RENDER.call(this, {}, Object.assign(options, { resolve_filepath: true }))
209 .then(filepath => Promisie.promisify(options.res.render, options.res)(filepath, Object.assign({
210 pagedata: { title: 'Not Found', error: (err instanceof Error || err.message) ? err.message : err },
211 url: options.viewname
212 }, { flash_messages, error: err, message: err.message })))
213 .then(rendered => {
214 if (typeof cb === 'function') cb(null, rendered);
215 else if (options.skip_response &amp;&amp; typeof cb !== 'function') return Promisie.resolve(rendered);
216 else {
217 options.res.status(500).send(rendered);
218 return Promisie.resolve(rendered);
219 }
220 })
221 .catch(err => {
222 if (typeof cb === 'function') cb(err);
223 else return Promisie.reject(err);
224 });
225 }
226 else {
227 options.formatError = (typeof options.formatError === 'function') ? options.formatError : _ERROR.bind(this);
228 options.sync = true;
229 options.locals = this.locals;
230 return super.error(err, options)
231 .then(result => {
232 if (typeof cb === 'function') cb(null, result);
233 else return result;
234 }, e => {
235 if (typeof cb === 'function') cb(e);
236 else return Promisie.reject(e);
237 });
238 }
239 }
240};
241
242module.exports = { HTML_ADAPTER, findValidViewFromPaths };
243</code></pre>
244 </article>
245 </section>
246
247
248
249
250</div>
251
252<nav>
253 <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="CONTENT_ADAPTER_INTERFACE.html">CONTENT_ADAPTER_INTERFACE</a></li><li><a href="HTML_ADAPTER.html">HTML_ADAPTER</a></li><li><a href="JSON_ADAPTER.html">JSON_ADAPTER</a></li><li><a href="XML_ADAPTER.html">XML_ADAPTER</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_ERROR">_ERROR</a></li><li><a href="global.html#_RENDER">_RENDER</a></li><li><a href="global.html#findValidViewFromPaths">findValidViewFromPaths</a></li></ul>
254</nav>
255
256<br class="clear">
257
258<footer>
259 Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Thu Dec 22 2016 14:40:43 GMT-0500 (EST)
260</footer>
261
262<script> prettyPrint(); </script>
263<script src="scripts/linenumber.js"> </script>
264</body>
265</html>