#!/usr/bin/env node var fs = require('fs'); var m_path = require('path'); var util = require('util'); var QCore = require('./QCore.js'); /* qwiki Node.js based Implementation of the proposed qwiki document */ /********************************* * QWiki * *********************************/ var QWiki = function() { QCore.call(this); this.initialize(); }; util.inherits(QWiki, QCore); /* QWiki.initialize() Checks for and creates the following directories: * wiki/ * cache/ * tmp/ Checks for and copies the following directories/files: * index.html * acts/ */ QWiki.prototype.listen = function(port, cb) { this.loadWikiIndex(); this.constructor.super_.prototype.listen.call(this, port, cb); }; QWiki.prototype.initialize = function() { // check if QWiki instance is running in a different directory than the module, // and if so, copy over default files var cwd = process.cwd(); if (cwd !== __dirname) { console.log('Running from: ' + cwd); // TODO: copy acts/, wiki/, and index.html from __dirname to cwd if not existing } else { console.log('Running from: ' + __dirname); } // make wiki directory try { var stats = fs.statSync('wiki'); if (!stats.isDirectory()) { console.log('error, "wiki" is not a directory'); } } catch (err) { if (err.code == 'ENOENT') { fs.mkdirSync('wiki'); console.log('Created "wiki/" -- this is where the wiki source files are stored'); } else { console.log('error while loading wiki directory'); } } // make cache directory try { var stats = fs.statSync('cache'); if (!stats.isDirectory()) { console.log('error, "cache" is not a directory'); } } catch (err) { if (err.code == 'ENOENT') { fs.mkdirSync('cache'); console.log('Created "cache/" -- this is where processed wiki pages are stored as HTML'); } else { console.log('error while loading cache'); } } // make tmp directory try { var stats = fs.statSync('tmp'); if (!stats.isDirectory()) { console.log('error, "tmp" is not a directory'); } } catch (err) { if (err.code == 'ENOENT') { fs.mkdirSync('tmp'); console.log('Created "tmp/" -- this is where uploaded files are temporarily stored'); } else { console.log('error while loading tmp directory'); } } }; QWiki.prototype.loadWikiIndex = function() { var self = this; try { this.wiki_index = JSON.parse(fs.readFileSync('index.json')); } catch (e) { this.wiki_index = { pages: {} }; console.log(e); } var wiki_index = this.wiki_index; console.log('loaded indices for ' + Object.keys(this.wiki_index.pages).length + ' pages'); QCore.prototype.readFiles('wiki', function(err, file, is_dir) { var wiki_file = file.replace('wiki/', ''); if (is_dir) { if (wiki_file in wiki_index.pages) { if (wiki_index.pages[wiki_file].dir != true) wiki_index.pages[wiki_file].dir = true; } else { wiki_index.pages[wiki_file] = { dir: true }; } } else { if (QCore.prototype.getExt(file) == 'qwk') { if (wiki_file in wiki_index.pages) { } else { var name = wiki_file.slice(0, -4); wiki_index.pages[name] = { format: 'md' }; // TODO: this.config.default_type } } else { if (wiki_file in wiki_index.pages) { } else { wiki_index.pages[wiki_file] = { format: 'file' }; } } } }); } QWiki.prototype.formats = { raw: { name: 'raw', fullname: 'Raw', convert: function(source) { return source; }, }, html: { name: 'html', fullname: 'HTML', convert: function(source) { return source; } } }; QWiki.prototype.addFormat = function(name, fullname, convertor_cb, pre_cb, post_cb) { this.formats[name] = { 'name': name, 'fullname': fullname, 'convert': convertor_cb, 'pre': pre_cb, 'post': post_cb }; }; QWiki.prototype.convertAndSave = function(path, name, source, cb) { if (typeof cb === 'undefined') cb = function() {}; if (!(name in this.formats)) { name = 'raw'; } console.log('converting to ' + name + ' with path ' + path); var converted = this.formats[name].convert(source); QCore.prototype.r_mkdir(m_path.dirname('cache/'+path+'.html'), 0777, function() { fs.writeFile('cache/'+path+'.html', converted, function(err) { if (err) { console.log('error writing "cache'+ path + '.html"'); } else { console.log('wrote "cache' + path + '.html"'); } cb(); }); }); }; QWiki.prototype.deleteCache = function(wiki_page, cb) { fs.unlink('cache/'+wiki_page+'.html', cb); }; QWiki.prototype.createCache = function(wiki_page, source, cb) { if (typeof cb === 'undefined') cb = function() {}; var format = this.defaults.format; if (typeof this.wiki_index.pages[wiki_page] !== 'undefined') { format = this.wiki_index.pages[wiki_page].format; } if (!(format in this.formats)) { format = 'raw'; } console.log('createCache: caching ' + wiki_page + ' as ' + format); var converted = this.formats[format].convert(source); var path = 'cache/' + wiki_page + '.html'; QCore.prototype.r_mkdir(m_path.dirname(path), 0777, function() { fs.writeFile(path, converted, function(err) { if (err) { console.log('createCache: error writing "' + path + '"'); } else { console.log('createCache: created "' + path + '"'); } cb(err); }); }); }; QWiki.prototype.deletePage = function(wiki_page, cb) { fs.unlink('wiki/'+wiki_page+'.qwk', cb); }; QWiki.prototype.savePage = function(wiki_page, content, cb) { var self = this; var path = 'wiki/' + wiki_page + '.qwk'; QCore.prototype.r_mkdir(m_path.dirname(path), 0777, function() { console.log('savePage: writing ' + path); self.deleteCache(wiki_page, function() { fs.writeFile(path, content, function(err) { console.log('savePage: wrote ' + path); cb(err); }); }); }); }; QWiki.prototype.deleteFile = function(file, cb) { fs.unlink('wiki/'+file, cb); }; if (require.main === module) { var port = 8080; process.argv.forEach(function (val, index, array) { var parts = val.split('='); var key = ''; var value = ''; if (parts[0].substr(0, 2) == '--') { key = parts[0].substr(2); value = parts[1]; } if (key == 'port') { if (value == '') { console.log(key + ' needs a value'); } else { port = Number(value); } } }); var qwiki = new QWiki(); qwiki.addMIMEtype('png', 'image/png'); qwiki.addMIMEtype('jpg', 'image/jpg'); qwiki.addMIMEtype('svg', 'image/svg+xml'); qwiki.addMIMEtype('css', 'text/css'); var m_markdownit = require('markdown-it')({ typographer: true }); m_markdownit.use(require('markdown-it-anchor')); m_markdownit.use(require('markdown-it-table-of-contents'), {includeLevel: "2-8"}); m_markdownit.use(require('markdown-it-deflist')); m_markdownit.use(require('markdown-it-header-sections')); m_markdownit.use(require('markdown-it-sup')); qwiki.addFormat('md', 'Markdown', function(source) { // source is a Buffer, but render seems to need a String return m_markdownit.render(source.toString()); }); qwiki.setDefault('format', 'md'); qwiki.listen(port); } module.exports = QWiki;