From 6c31f7eaad635845967294e5e18fe35d84057cbc Mon Sep 17 00:00:00 2001 From: Peter Hinz Date: Mon, 15 Oct 2012 10:42:48 +0200 Subject: [PATCH] First commit --- .gitignore | 1 + .npmignore | 6 ++ History.md | 4 + README.md | 58 +++++++++++++ out/csv.plugin.js | 206 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 47 +++++++++++ 6 files changed, 322 insertions(+) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 History.md create mode 100644 README.md create mode 100644 out/csv.plugin.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..faba7e0 --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +.travis* +Makefile + +src/ +out/test/ +test/ \ No newline at end of file diff --git a/History.md b/History.md new file mode 100644 index 0000000..48623b9 --- /dev/null +++ b/History.md @@ -0,0 +1,4 @@ +## History + +- v0.1.0 Spetmber 21, 2012 + - Started work on csv plugin. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ffaac7 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# CSV Plugin for DocPad +This plugin provides [DocPad](https://github.com/bevry/docpad) with CSV data mapping. CSV are numbers that represent the cost of an item or a mapping from one value to another. + + +## Install + +``` +npm install --save docpad-plugin-csv +``` + + +## Usage + +### Setup + +To use, first create the `src/csv` directory, and place any set of config files you want to use in there. + +Then in our templates we will be exposed with the `@csv(config_file,data_point)` function. The `data_point` argument is NOT optional, and is used to send custom data to the csv's `templateData`. + +The following options are available: +csvPath - [csv] directory name under `src' where the csv files are loaded from +currency - [''] What currency symbol you want to use if you are outputting prices +decimal - [2] How many decimal places are displayed +decimalPoint - ['.'] What symbol is used to represent the decimal point +thausandSep - [','] What symbol is used to represent the thousand seperator in numbers. Use '' if you dont want any. +defExtension - ['csv'] This is added to each of the data filenames used into the commands. Just makes it shorter to type. +zeroIs - ['TBD'] When a price is created and the value is 0 then this is used to represent the 0. + +### Example +Create a file called `test.csv` in the `src/csv` folder. +Add the following two lines: +ABC, 1559 +DEF, 12.99 +XYZ, Hello there + +This basically is a mapping from `ABC` to `1559` and from `DEF` to `12`. + +Inside a test document we can use this command to replace `ABC` entries with the value from the csv file. +`<%- @csv('test', 'ABC') %>` will produce `559` +`<%- @csv('test', 'DEF') %>` will produce `12.99` +`<%- @csv('test', 'XYZ') %>` will produce `Hello there` + +If you are working with numbers then you can also do this: +`<%- @csvPrice('test', 'ABC') %>` will produce `1,559.00` +`<%- @csvPrice('test', 'DEF') %>` will produce `12.99` + +or if you want numbers but no decimals: +`<%- @csvPriceNoDec('test', 'ABC') %>` will produce `1,559` +`<%- @csvPriceNoDec('test', 'DEF') %>` will produce `12` + + +## History +You can discover the history inside the `History.md` file + + +## License +Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) +
Copyright © 2012 [Cerebus Software CC](http://cerebus.co.za) \ No newline at end of file diff --git a/out/csv.plugin.js b/out/csv.plugin.js new file mode 100644 index 0000000..42079a5 --- /dev/null +++ b/out/csv.plugin.js @@ -0,0 +1,206 @@ +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + module.exports = function(BasePlugin) { + var CSVPlugin, balUtil, pathUtil, csvUtils; + balUtil = require('bal-util'); + pathUtil = require('path'); + csvUtils = require('csv'); + return CSVPlugin = (function(_super) { + + __extends(CSVPlugin, _super); + + CSVPlugin.prototype.name = 'csv'; + + CSVPlugin.prototype.config = { + csvPath: 'csv', + currency: '', + decimal: 2, + decimalPoint: '.', + thousandSep: ',', + defExtension: '.csv', + zeroIs: "TBD" + }; + + CSVPlugin.prototype.foundCSVs = null; + CSVPlugin.prototype.foundCSVQueries = null; + CSVPlugin.prototype.csvRequestNr = 0; + + function CSVPlugin() { + var config, docpad; + CSVPlugin.__super__.constructor.apply(this, arguments); + docpad = this.docpad; + config = this.config; + config.csvPath = pathUtil.resolve(docpad.config.srcPath, config.csvPath); + // + // check the docpad.plugins.csv key for configurations + if (docpad.config.docpad) { + if (docpad.config.docpad.plugins) { + if (docpad.config.docpad.plugins.csv) { + // console.dir(docpad.config.docpad.plugins.csv); + for(key in docpad.config.docpad.plugins.csv) { + config[key] = docpad.config.docpad.plugins.csv[key]; + } + // console.dir(config); + } + } + } + // console.dir(docpad.config); + } + + Number.prototype.formatMoney = function(c, d, t){ + var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0; + return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ""); + }; + + CSVPlugin.prototype.fJustText = function (csv, inText) { + return inText; + } + + CSVPlugin.prototype.fPrice = function (csv, inText) { + var num = +inText; + var config = csv.plugin.config; + if (inText.length === 0 && config.zeroIs.length > 0) { + return config.zeroIs; + } + if (isNaN(inText)) { + return inText; + } + + return config.currency + num.formatMoney(config.decimal, config.decimalPoint, config.thousandSep); + } + + CSVPlugin.prototype.fPriceNoDec = function (csv, inText) { + var num = +inText; + var config = csv.plugin.config; + if (inText.length === 0 && config.zeroIs.length > 0) { + return config.zeroIs; + } + if (isNaN(inText)) { + return inText; + } + + return config.currency + num.formatMoney(0, config.decimalPoint, config.thousandSep); + } + + CSVPlugin.prototype.renderCSVSync = function(outOp, name, data) { + var config, id, oneCSVQuery; + config = this.config; + + if (config.defExtension !== undefined) { + name += config.defExtension; + } + ++this.csvRequestNr; + id = name+this.csvRequestNr; + oneCSVQuery = { + id: id, + plugin: this, + name: name, + data: data, + path: pathUtil.join(config.csvPath, name), + container: "[csv:" + id + "]", + outOp: outOp + }; + this.foundCSVQueries[id] = oneCSVQuery; + return oneCSVQuery.container; + }; + + CSVPlugin.prototype.renderCSV = function(csv, next) { + var docpad; + docpad = this.docpad; + balUtil.exists(csv.path, function(exists) { + var err; + if (!exists) { + err = new Error("The csv file [" + csv.name + "] was not found, and as such will not be rendered."); + if (err) { + return next(err); + } + } + // Load the CSV data and then call the render function + var csvParsedData = csv.plugin.foundCSVs[csv.name]; + if (csvParsedData === undefined) { + csv.csvData = {}; + csvUtils() + .fromPath(csv.path, {trim: true}) + .on('data', function(data, index) {csv.csvData[data[0]] = data[1]; }) + .on('end', function(count) { + csv.plugin.foundCSVs[csv.name] = csv.csvData; + if (csv.csvData[csv.data] === undefined) { + return next(new Error("Unable to find entry [" +csv.data+"] in CSV file [" + csv.name + "]")); + } else { + return docpad.renderText(csv.outOp(csv, csv.csvData[csv.data]), {filename: csv.path}, next); + } + }) + .on('error',function(error) {return next(new Error("Unable to parse CSV file [" + csv.name + "]")); }); + } else { + csv.csvData = csvParsedData; + if (csv.csvData[csv.data] === undefined) { + return next(new Error("Unable to find entry [" +csv.data+"] in CSV file [" + csv.name + "]")); + } else { + return docpad.renderText(csv.outOp(csv, csv.csvData[csv.data]), {filename: csv.path}, next); + } + } + }); + return this; + }; + + + CSVPlugin.prototype.extendTemplateData = function(_arg) { + var me, templateData; + templateData = _arg.templateData; + me = this; + this.foundCSVs = {}; + this.foundCSVQueries = {}; + this.csvRequestNr = 0; + + // Hookup the csv function call from within the document + templateData.csv = function(name, data) { + return me.renderCSVSync(me.fJustText, name, data); + }; + templateData.csvPrice = function(name, data) { + return me.renderCSVSync(me.fPrice, name, data); + }; + templateData.csvPriceNoDec = function(name, data) { + return me.renderCSVSync(me.fPriceNoDec, name, data); + }; + return this; + }; + + CSVPlugin.prototype.renderDocument = function(opts, next) { + var config, docpad, file, foundCSVQueries, me, tasks, templateData; + templateData = opts.templateData, file = opts.file; + me = this; + docpad = this.docpad; + config = this.config; + foundCSVQueries = this.foundCSVQueries; + tasks = new balUtil.Group(next); + // Run over all the CSV entries we have and check if the source 'content' has got an entry for it. + balUtil.each(foundCSVQueries, function(oneQuery) { + return tasks.push(function(complete) { + if (opts.content.indexOf(oneQuery.container) === -1) { + return complete(); + } + docpad.log('debug', "Rendering csv: " + oneQuery.name+oneQuery.data); + + return me.renderCSV(oneQuery, function(err, contentRendered) { + if (err) { + docpad.warn("Rendering csv failed: " + oneQuery.name+oneQuery.data + ". The error follows:", err); + } else { + docpad.log('debug', "Rendered csv: " + oneQuery.name+oneQuery.data); + opts.content = opts.content.replace(oneQuery.container, contentRendered); + } + return complete(); + }); + }); + }); + tasks.sync(); + return this; + }; + + return CSVPlugin; + + })(BasePlugin); + }; + +}).call(this); diff --git a/package.json b/package.json new file mode 100644 index 0000000..a018011 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "docpad-plugin-csv", + "version": "0.1.0", + "description": "Adds support for csv (data mapping) to DocPad", + "homepage": "https://github.com/bevry/docpad-extras", + "keywords": [ + "docpad", + "docpad-plugin", + "csv", + "templates", + "templating", + "template" + ], + "author": { + "name": "Cerebus Software CC", + "email": "peter@cerebus.co.za", + "url": "http://www.cerebus.co.za" + }, + "maintainers": [ + { + "name": "Benjamin Lupton", + "email": "b@lupton.cc", + "url": "http://balupton.com" + } + ], + "bugs": { + "url": "https://github.com/bevry/docpad-extras/issues" + }, + "repository": { + "type": "git", + "url": "http://github.com/bevry/docpad-extras.git" + }, + "engines": { + "node": ">=0.8.0", + "docpad": ">=6.1.x" + }, + "dependencies": { + "bal-util": "1.13.x" + }, + "main": "./out/csv.plugin.js", + "scripts": { + "test": "node ./test/csv.test.js" + }, + "readme": "# csv Plugin for DocPad\nThis plugin provides [DocPad](https://github.com/bevry/docpad) with csv data mappings.", + "_id": "docpad-plugin-csv@0.1.0", + "_from": "docpad-plugin-csv" +}