UNPKG

11.1 kBJavaScriptView Raw
1/**
2 *
3 * Copyright 2013 David Herron
4 *
5 * This file is part of AkashaCMS-tagged-content (http://akashacms.com/).
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20var path = require('path');
21var util = require('util');
22var fs = require('fs');
23var async = require('async');
24var taggen = require('tagcloud-generator');
25var Tempdir = require('temporary/lib/dir');
26
27var tagCloudData = undefined;
28var tempDir = undefined;
29
30var logger;
31
32/**
33 * Add ourselves to the config data.
34 **/
35module.exports.config = function(akasha, config) {
36
37 logger = akasha.getLogger("tagged-content");
38
39 config.root_partials.push(path.join(__dirname, 'partials'));
40
41 if (config.mahabhuta) {
42 config.mahabhuta.push(function($, metadata, dirty, done) {
43 // util.log('tagged-content <tag-cloud>');
44 $('tag-cloud').each(function(i, elem) {
45 genTagCloudData(akasha, config);
46 $(this).replaceWith(
47 taggen.generateSimpleCloud(tagCloudData.tagData, function(tagName) {
48 return tagPageUrl(config, tagName);
49 }, "")
50 );
51 });
52 done();
53 });
54 config.mahabhuta.push(function($, metadata, dirty, done) {
55 // util.log('tagged-content <tag-for-document>');
56 var tfds = [];
57 $('tags-for-document').each(function(i, elem) { tfds.push(elem); });
58 async.each(tfds,
59 function(tfd, cb) {
60 if (tfd)
61 doTagsForDocument(metadata, "tagged-content-doctags.html.ejs", function(err, tags) {
62 if (err) cb(err);
63 else {
64 $(tfd).replaceWith(tags);
65 cb();
66 }
67 });
68 else cb();
69 },
70 function(err) {
71 if (err) done(err);
72 else done();
73 });
74 });
75 }
76
77 config.funcs.tagCloud = function(arg, callback) {
78 genTagCloudData(akasha, config);
79 var val = taggen.generateSimpleCloud(tagCloudData.tagData, function(tagName) {
80 return tagPageUrl(config, tagName);
81 }, "");
82 // util.log('tagCloud ' + val);
83 if (callback) callback(undefined, val);
84 return val;
85 }
86
87 var doTagsForDocument = function(arg, template, done) {
88 akasha.readDocumentEntry(config, arg.documentPath, function(err, entry) {
89 if (err) done(err);
90 else {
91 var taglist = entryTags(entry);
92
93 var val = "";
94 if (taglist) {
95 var tagz = [];
96 for (var i = 0; i < taglist.length; i++) {
97 tagz.push({
98 tagName: taglist[i],
99 tagUrl: tagPageUrl(config, taglist[i])
100 });
101 }
102 val = akasha.partialSync(template, { tagz: tagz });
103 }
104 done(undefined, val);
105 }
106 });
107 }
108
109
110 config.funcs.tagsForDocument = function(arg, callback) {
111 throw new Error("do not call tagsForDocument - use <tags-for-document>");
112 doTagsForDocument(arg, "tagged-content-doctags.html.ejs", callback);
113 }
114
115 /* We don't want an xyzzyBootstrap function
116 config.funcs.tagsForDocumentBootstrap = function(arg, callback) {
117 return doTagsForDocument(arg, "tagged-content-doctags-bootstrap.html.ejs", callback);
118 }*/
119
120 akasha.emitter.on('before-render-files', function(cb) {
121 util.log('before-render-files received');
122 module.exports.generateTagIndexes(akasha, config, function(err) {
123 if (err) cb(err); else cb();
124 });
125 });
126 akasha.emitter.on('done-render-files', function(cb) {
127 util.log('done-render-files received');
128 // fs.rmdirSync(tempDir.path);
129 cb();
130 });
131}
132
133var tagPageUrl = function(config, tagName) {
134 return config.tags.pathIndexes + tag2encode4url(tagName) +'.html';
135}
136
137var tagParse = function(tags) {
138 var taglist = [];
139 var re = /\s*,\s*/;
140 if (tags) tags.split(re).forEach(function(tag) {
141 taglist.push(tag.trim());
142 });
143 return taglist;
144}
145
146var entryTags = function(entry) {
147 if (entry.frontmatter
148 && entry.frontmatter.hasOwnProperty('yaml')
149 && entry.frontmatter.yaml
150 && entry.frontmatter.yaml.hasOwnProperty('tags')) {
151 // parse tags
152 // foreach tag:- tagCloudData[tag] .. if null, give it an array .push(entry)
153 // util.log(entry.frontmatter.tags);
154 var taglist = tagParse(entry.frontmatter.yaml.tags);
155 return taglist;
156 } else {
157 return undefined;
158 }
159}
160
161/**
162 * Generate a section of a URL for a tag name. We want to convert this into
163 * something that's safe for URL's, hence changing some of the characters into -'s.
164 *
165 * TBD: There's no attempt to avoid two different tag names mapping to the same
166 * underlying URL.
167 **/
168var tag2encode4url = function(tagName) {
169 return tagName.toLowerCase()
170 .replace(/ /g, '-')
171 .replace(/\//g, '-')
172 .replace(/\?/g, '-')
173 .replace(/=/g, '-')
174 .replace(/&/g, '-');
175}
176
177var sortByTitle = function(a,b) {
178 if (a.frontmatter.yaml.title < b.frontmatter.yaml.title) return -1;
179 else if (a.frontmatter.yaml.title === b.frontmatter.yaml.title) return 0;
180 else return 1;
181};
182
183var sortByDate = function(a,b) {
184 var aPublicationDate = Date.parse(
185 a.frontmatter.yaml.publicationDate ? a.frontmatter.yaml.publicationDate : a.stat.mtime
186 );
187 var bPublicationDate = Date.parse(
188 b.frontmatter.yaml.publicationDate ? b.frontmatter.yaml.publicationDate : b.stat.mtime
189 );
190 if (aPublicationDate < bPublicationDate) return -1;
191 else if (aPublicationDate === bPublicationDate) return 0;
192 else return 1;
193};
194
195module.exports.generateTagIndexes = function(akasha, config, cb) {
196 genTagCloudData(akasha, config);
197 tempDir = new Tempdir;
198 config.root_docs.push(tempDir.path);
199 var tagsDir = path.join(tempDir.path, config.tags.pathIndexes);
200 fs.mkdirSync(tagsDir);
201
202 for (tagnm in tagCloudData.tagData) {
203 var tagData = tagCloudData.tagData[tagnm];
204 var tagNameEncoded = tag2encode4url(tagData.tagName);
205
206 if (config.tags.sortBy === 'date') {
207 tagData.entries.sort(sortByDate);
208 tagData.entries.reverse();
209 } else if (config.tags.sortBy === 'title') {
210 tagData.entries.sort(sortByTitle);
211 } else {
212 tagData.entries.sort(sortByTitle);
213 };
214
215 var entryText = config.tags.header
216 .replace("@title@", tagData.tagName)
217 .replace("@tagName@", tagData.tagName);
218
219 var entriez = [];
220 for (var j = 0; j < tagData.entries.length; j++) {
221 var entry = tagData.entries[j];
222 entriez.push({
223 url: akasha.urlForFile(entry.path),
224 title: entry.frontmatter.yaml.title,
225 teaser: entry.frontmatter.yaml.teaser
226 ? entry.frontmatter.yaml.teaser
227 : "",
228 youtubeThumbnail: entry.frontmatter.yaml.youtubeThumbnail
229 ? entry.frontmatter.yaml.youtubeThumbnail
230 : undefined
231 });
232 }
233
234 // Optionally generate an RSS feed for the tag page
235 var rsslink = "";
236 if (config.rss) {
237 // logger.trace(tagnm +' writing RSS');
238 // Ensure it's sorted by date
239 tagData.entries.sort(sortByDate);
240 tagData.entries.reverse();
241
242 var rssitems = [];
243 for (var q = 0; q < tagData.entries.length; q++) {
244 var entry = tagData.entries[q];
245 rssitems.push({
246 title: entry.frontmatter.yaml.title,
247 description: entry.frontmatter.yaml.teaser // TBD what about supporting full feeds?
248 ? entry.frontmatter.yaml.teaser
249 : "",
250 url: config.root_url +'/'+ entry.renderedFileName,
251 date: entry.frontmatter.yaml.publicationDate
252 ? entry.frontmatter.yaml.publicationDate
253 : entry.stat.mtime
254 });
255 }
256 // logger.trace(tagnm +' rss feed entry count='+ rssitems.length);
257
258 var feedRenderTo = path.join(config.tags.pathIndexes, tagNameEncoded +".xml");
259 logger.trace(tagnm +' writing RSS to '+ feedRenderTo);
260
261 akasha.generateRSS(config, {
262 feed_url: config.root_url + feedRenderTo,
263 pubDate: new Date()
264 },
265 rssitems, feedRenderTo, function(err) {
266 if (err) logger.error(err);
267 });
268
269 rsslink = '<a href="'+ feedRenderTo +'"><img src="/img/rss_button.gif" align="right" width="50"/></a>';
270 }
271
272 // logger.trace(tagnm +' tag entry count='+ entriez.length);
273 entryText += akasha.partialSync("tagged-content-tagpagelist.html.ejs", {
274 entries: entriez
275 });
276 if (rsslink !== "") {
277 entryText += '<div>' + rsslink + '</div>';
278 entryText += '<rss-header-meta href="'+ config.root_url + feedRenderTo +'"></rss-header-meta>';
279 }
280 var tagFileName = path.join(tagsDir, tagNameEncoded +".html.ejs");
281 // logger.trace(tagnm +' writing to '+ tagFileName);
282 fs.writeFileSync(tagFileName, entryText, {
283 encoding: 'utf8'
284 });
285 }
286
287 akasha.gatherDir(config, tempDir.path, function(err) {
288 if (err) cb(err); else cb();
289 });
290}
291
292var genTagCloudData = function(akasha, config) {
293 if (!tagCloudData) {
294 tagCloudData = {
295 tagData: []
296 };
297 akasha.eachDocument(config, function(entry) {
298 // util.log('eachDocument '+ entry.path);
299 var taglist = entryTags(entry);
300 if (taglist) {
301 for (var i = 0; i < taglist.length; i++) {
302 var tagnm = taglist[i];
303 if (! tagCloudData.tagData[tagnm]) {
304 tagCloudData.tagData[tagnm] = { tagName: tagnm, entries: [] };
305 }
306 // util.log('*** adding '+ entry.path +' to entries for '+ tagnm);
307 tagCloudData.tagData[tagnm].entries.push(entry);
308 }
309 }
310 });
311 util.log('******** DONE akasha.eachDocument count='+ tagCloudData.tagData.length);
312 /*tagCloudData.tagData.sort(function(a, b) {
313 if (a.tagName < b.tagName) return -1;
314 else if (a.tagName === b.tagName) return 0;
315 else return 1;
316 });*/
317 for (tagnm in tagCloudData.tagData) {
318 tagCloudData.tagData[tagnm].count = tagCloudData.tagData[tagnm].entries.length;
319 // util.log(tagCloudData.tagData[tagnm].tagName +' = '+ tagCloudData.tagData[tagnm].entries.length);
320 }
321 taggen.generateFontSizes(tagCloudData.tagData);
322 // util.log(util.inspect(tagCloudData));
323 }
324}
\No newline at end of file