diff --git a/package.json b/package.json index f2a53e2..b07f9ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fluentcv", - "version": "0.7.2", + "version": "0.8.0", "description": "Generate beautiful, targeted resumes from your command line, shell, or in Javascript with Node.js.", "repository": { "type": "git", @@ -24,7 +24,7 @@ }, "homepage": "https://github.com/fluentdesk/fluentcv", "dependencies": { - "fluent-themes": "0.2.0-beta", + "fluent-themes": "0.4.0-beta", "fs-extra": "^0.24.0", "html": "0.0.10", "is-my-json-valid": "^2.12.2", diff --git a/src/core/sheet.js b/src/core/sheet.js index e3a644b..9d8e666 100644 --- a/src/core/sheet.js +++ b/src/core/sheet.js @@ -39,8 +39,8 @@ Abstract character/resume sheet representation. Save the sheet to disk (for environments that have disk access). */ Sheet.prototype.save = function( filename ) { - filename = filename || this.meta.fileName; - FS.writeFileSync( filename, this.stringify(), 'utf8' ); + this.meta.fileName = filename || this.meta.fileName; + FS.writeFileSync( this.meta.fileName, this.stringify(), 'utf8' ); return this; }; @@ -52,7 +52,7 @@ Abstract character/resume sheet representation. function replacer( key,value ) { // Exclude these keys from stringification return _.some(['meta', 'warnings', 'computed', 'filt', 'ctrl', 'index', 'safeStartDate', 'safeEndDate', 'safeDate', 'safeReleaseDate', 'result', - 'isModified', 'htmlPreview'], + 'isModified', 'htmlPreview', 'display_progress_bar'], function( val ) { return key.trim() === val; } ) ? undefined : value; } @@ -119,6 +119,7 @@ Abstract character/resume sheet representation. delete this.publications; delete this.interests; delete this.skills; + delete this.basics.profiles; }; /** diff --git a/src/core/theme.js b/src/core/theme.js index 4150d0c..9ade483 100644 --- a/src/core/theme.js +++ b/src/core/theme.js @@ -31,6 +31,11 @@ Abstract theme representation. return friendly[val] || val; } + // Remember the theme folder; might be custom + this.folder = themeFolder; + + // Iterate over all files in the theme folder, producing an array, fmts, + // containing info for each file. var tplFolder = PATH.join( themeFolder, 'templates' ); var fmts = FS.readdirSync( tplFolder ).map( function( file ) { var absPath = PATH.join( tplFolder, file ); @@ -46,20 +51,24 @@ Abstract theme representation. return temp; }); - // Freebie formats every theme gets + // Add freebie formats every theme gets fmts.push( [ 'json', { title: 'json', pre: 'json', ext: 'json', path: null, data: null } ] ); fmts.push( [ 'yml', { title: 'yaml', pre: 'yml', ext: 'yml', path: null, data: null } ] ); - // Handle CSS files - var cssFiles = fmts.filter(function( fmt ){ - return fmt[1].ext === 'css'; - }); - cssFiles.forEach(function( cssf ) { + // Now, get all the CSS files... + this.cssFiles = fmts.filter(function( fmt ){ return fmt[1].ext === 'css'; }); + + // ...and assemble information on them + this.cssFiles.forEach(function( cssf ) { // For each CSS file, get its corresponding HTML file - var idx = _.findIndex(fmts, function( fmt ) { return fmt[1].pre === cssf[1].pre && fmt[1].ext === 'html' }); + var idx = _.findIndex(fmts, function( fmt ) { + return fmt[1].pre === cssf[1].pre && fmt[1].ext === 'html' + }); fmts[ idx ][1].css = cssf[1].data; fmts[ idx ][1].cssPath = cssf[1].path; }); + + // Remove CSS files from the formats array fmts = fmts.filter( function( fmt) { return fmt[1].ext !== 'css'; }); @@ -67,7 +76,9 @@ Abstract theme representation. // Create a hash out of the formats for this theme this.formats = _.object( fmts ); + // Set the official theme name this.name = PATH.parse( themeFolder ).name; + return this; }; diff --git a/src/fluentcmd.js b/src/fluentcmd.js index 3a68852..92df228 100644 --- a/src/fluentcmd.js +++ b/src/fluentcmd.js @@ -123,7 +123,7 @@ module.exports = function () { ]; /** - Default FluentCMD options. + Default FluentCV options. */ var _opts = { theme: 'modern', diff --git a/src/fluentlib.js b/src/fluentlib.js index f442705..ddb4fd2 100644 --- a/src/fluentlib.js +++ b/src/fluentlib.js @@ -6,6 +6,7 @@ Core resume generation module for FluentCV. module.exports = { Sheet: require('./core/sheet'), Theme: require('./core/theme'), + FluentDate: require('./core/fluent-date'), HtmlGenerator: require('./gen/html-generator'), TextGenerator: require('./gen/text-generator'), HtmlPdfGenerator: require('./gen/html-pdf-generator'), diff --git a/src/gen/html-generator.js b/src/gen/html-generator.js index 1522b70..b0f2992 100644 --- a/src/gen/html-generator.js +++ b/src/gen/html-generator.js @@ -1,32 +1,40 @@ /** HTML resume generator for FluentCV. -@license Copyright (c) 2015 by James M. Devlin. All rights reserved. +@license Copyright (c) 2015 James M. Devlin / FluentDesk */ -var TemplateGenerator = require('./template-generator'); -var FS = require('fs-extra'); -var HTML = require( 'html' ); +(function() { -var HtmlGenerator = module.exports = TemplateGenerator.extend({ + var TemplateGenerator = require('./template-generator') + , FS = require('fs-extra') + , HTML = require( 'html' ) + , PATH = require('path'); - init: function() { - this._super( 'html' ); - }, + var HtmlGenerator = module.exports = TemplateGenerator.extend({ - /** - Generate an HTML resume with optional pretty printing. - */ - onBeforeSave: function( mk, theme, outputFile ) { - var themeFile = theme.getFormat('html').path; - var cssSrc = themeFile.replace( /.html$/g, '.css' ); - var cssDst = outputFile.replace( /.html$/g, '.css' ); - var that = this; - FS.copySync( cssSrc, cssDst, { clobber: true }, function( e ) { - throw { fluenterror: that.codes.copyCss, data: [cssSrc,cssDst] }; - }); + init: function() { + this._super( 'html' ); + }, - return this.opts.prettify ? - HTML.prettyPrint( mk, this.opts.prettify ) : mk; - } + /** + Copy satellite CSS files to the destination and optionally pretty-print + the HTML resume prior to saving. + */ + onBeforeSave: function( info ) { + var cssSrc = PATH.join( info.theme.folder, 'templates', '*.css' ) + , outFolder = PATH.parse( info.outputFile ).dir, that = this; -}); + info.theme.cssFiles.forEach( function( f ) { + var fi = PATH.parse( f[1].path ); + FS.copySync( f[1].path, PATH.join( outFolder, fi.base ), { clobber: true }, function( e ) { + throw { fluenterror: that.codes.copyCss, data: [cssSrc,cssDst] }; + }); + }); + + return this.opts.prettify ? + HTML.prettyPrint( info.mk, this.opts.prettify ) : info.mk; + } + + }); + +}()); diff --git a/src/gen/html-pdf-generator.js b/src/gen/html-pdf-generator.js index 549c787..ae55e10 100644 --- a/src/gen/html-pdf-generator.js +++ b/src/gen/html-pdf-generator.js @@ -1,74 +1,71 @@ /** -HTML-based PDF resume generator for FluentCV. -@license Copyright (c) 2015 by James M. Devlin. All rights reserved. +Definition of the HtmlPdfGenerator class. +@license Copyright (c) 2015 James M. Devlin / FluentDesk */ -var TemplateGenerator = require('./template-generator'); -var FS = require('fs-extra'); -var HTML = require( 'html' ); +(function() { -var HtmlPdfGenerator = module.exports = TemplateGenerator.extend({ - - init: function() { - this._super( 'pdf', 'html' ); - }, + var TemplateGenerator = require('./template-generator') + , FS = require('fs-extra') + , HTML = require( 'html' ); /** - Generate an HTML resume with optional pretty printing. - TODO: Avoid copying the CSS file to dest if we don't need to. + An HTML-based PDF resume generator for FluentCV. */ - onBeforeSave: function( mk, themeFile, outputFile ) { - // var cssSrc = themeFile.replace( /pdf\.html$/gi, 'html.css' ); - // var cssDst = outputFile.replace( /\.pdf$/gi, '.css' ); - // var that = this; - // FS.copySync( cssSrc, cssDst, { clobber: true }, function( e ) { - // if( e ) that.err( "Couldn't copy CSS file to destination: " + e); - // }); - // return true ? - // HTML.prettyPrint( mk, { indent_size: 2 } ) : mk; + var HtmlPdfGenerator = module.exports = TemplateGenerator.extend({ - pdf(mk, outputFile); - return mk; - } + init: function() { + this._super( 'pdf', 'html' ); + }, -}); - -/** -Generate a PDF from HTML. -*/ -function pdf( markup, fOut ) { - - var pdfCount = 0; - if( false ) { //( _opts.pdf === 'phantom' || _opts.pdf == 'all' ) { - pdfCount++; - require('phantom').create( function( ph ) { - ph.createPage( function( page ) { - page.setContent( markup ); - page.set('paperSize', { - format: 'A4', - orientation: 'portrait', - margin: '1cm' - }); - page.set("viewportSize", { - width: 1024, // TODO: option-ify - height: 768 // TODO: Use "A" sizes - }); - page.set('onLoadFinished', function(success) { - page.render( fOut ); - pdfCount++; - ph.exit(); - }); - }, - { dnodeOpts: { weak: false } } ); - }); - } - if( true ) { // _opts.pdf === 'wkhtmltopdf' || _opts.pdf == 'all' ) { - var fOut2 = fOut; - if( pdfCount == 1 ) { - fOut2 = fOut2.replace(/\.pdf$/g, '.b.pdf'); + /** + Generate the binary PDF. + */ + onBeforeSave: function( info ) { + pdf(info.mk, info.outputFile); + return info.mk; } - require('wkhtmltopdf')( markup, { pageSize: 'letter' } ) - .pipe( FS.createWriteStream( fOut2 ) ); + + }); + + /** + Generate a PDF from HTML. + */ + function pdf( markup, fOut ) { + + var pdfCount = 0; + if( false ) { //( _opts.pdf === 'phantom' || _opts.pdf == 'all' ) { pdfCount++; + require('phantom').create( function( ph ) { + ph.createPage( function( page ) { + page.setContent( markup ); + page.set('paperSize', { + format: 'A4', + orientation: 'portrait', + margin: '1cm' + }); + page.set("viewportSize", { + width: 1024, // TODO: option-ify + height: 768 // TODO: Use "A" sizes + }); + page.set('onLoadFinished', function(success) { + page.render( fOut ); + pdfCount++; + ph.exit(); + }); + }, + { dnodeOpts: { weak: false } } ); + }); + } + if( true ) { // _opts.pdf === 'wkhtmltopdf' || _opts.pdf == 'all' ) { + var fOut2 = fOut; + if( pdfCount == 1 ) { + fOut2 = fOut2.replace(/\.pdf$/g, '.b.pdf'); + } + require('wkhtmltopdf')( markup, { pageSize: 'letter' } ) + .pipe( FS.createWriteStream( fOut2 ) ); + pdfCount++; + } } -} + +}()); diff --git a/src/gen/template-generator.js b/src/gen/template-generator.js index d9a7833..2e5e00f 100644 --- a/src/gen/template-generator.js +++ b/src/gen/template-generator.js @@ -89,11 +89,11 @@ var TemplateGenerator = module.exports = BaseGenerator.extend({ // Load theme and CSS data var tplFolder = PATH.join( tFolder, 'templates' ); var curFmt = theme.getFormat( this.format ); - var ctx = { file: curFmt.css ? curFmt.cssPath : null, data: curFmt.css || null }; + var cssInfo = { file: curFmt.css ? curFmt.cssPath : null, data: curFmt.css || null }; // Compile and invoke the template! - var mk = this.single( rez, curFmt.data, this.format, ctx, opts ); - this.onBeforeSave && (mk = this.onBeforeSave( mk, theme, f )); + var mk = this.single( rez, curFmt.data, this.format, cssInfo, opts ); + this.onBeforeSave && (mk = this.onBeforeSave( { mk: mk, theme: theme, outputFile: f } )); FS.writeFileSync( f, mk, { encoding: 'utf8', flags: 'w' } ); },