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 | |
10 |
|
11 |
|
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';
|
30 | const path = require('path');
|
31 | const Promisie = require('promisie');
|
32 | const ejs = require('ejs');
|
33 | const fs = Promisie.promisifyAll(require('fs-extra'));
|
34 | const 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 | */
|
42 | var 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 | */
|
66 | const _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' && typeof fileext === 'string') dirs.push(path.join(__dirname, '../../../content/themes', themename, 'views', `${ viewname }${ (/^\./.test(fileext)) ? fileext : '.' + fileext }`));
|
79 | if (typeof extname === 'string' && 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 | */
|
102 | const _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 | */
|
121 | const 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 && 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 && 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 && 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 && 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 && options.res) {
|
205 | let flash_messages = (typeof options.req.flash === 'function') ? options.req.flash() : {};
|
206 | if (options.dirname && 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 && 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 && 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 |
|
242 | module.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>
|