directory-encoder.js 5.17 KB
/*global require:true*/
/*global module:true*/
(function(){
	"use strict";

	var fs = require( 'fs-extra' );
	var path = require( 'path' );
	var Handlebars = require( 'handlebars' );
	var SvgURIEncoder = require( './svg-uri-encoder' );
	var PngURIEncoder = require( './png-uri-encoder' );

	function DirectoryEncoder( input, output, options ){
		var files;
		if( typeof input === "string" && fs.lstatSync( input ).isDirectory()){
			files = fs.readdirSync( input ).map( function( file ){
				return path.join( input, file );
			});
		} else if( Array.isArray( input ) ){
			files = input;
		} else {
			throw new Error( "Input must be Array of files or String that is a directory" );
		}

		if( typeof output !== "string" ){
			throw new Error( "Output must be file name of desired encoded file" );
		}

		this.output = output;
		this.options = options || {};
		this.files = files;
		this.prefix = this.options.prefix || ".icon-";

		this.options.pngfolder = this.options.pngfolder || "";
		this.options.pngpath = this.options.pngpath || this.options.pngfolder;

		this.customselectors = this.options.customselectors || {};
		this.template = this._loadTemplate( this.options.template );
		this.templatePrepend = this.options.templatePrepend || "";
		this.templateAppend = this.options.templateAppend || "";
	}

	DirectoryEncoder.encoders = {
		svg: SvgURIEncoder,
		png: PngURIEncoder
	};

	DirectoryEncoder.prototype.encode = function() {
		var self = this, seen = {};

		// remove the file if it's there
		if( fs.existsSync(this.output) ) {
			fs.unlinkSync( this.output );
		}

		if( !fs.existsSync(path.dirname( this.output )) ){
			fs.mkdirpSync( path.dirname( this.output ) );
		}
		
		// add templatePrepend to the output file
		fs.appendFileSync( self.output, self.templatePrepend );

		// append each selector
		this.files.filter(function( filepath ){
			var file = path.basename( filepath ),
				extension = path.extname( file );
			return extension === ".svg" || extension === ".png";
		})
		.filter(function( filepath ){
			return fs.lstatSync( filepath ).isFile();
		})
		.forEach(function( filepath ) {
			var css, datauri, stats,
				file = path.basename( filepath ),
				extension = path.extname( file );

			self._checkName(seen, file.replace( extension, '' ));

			stats = self._stats( filepath );
			datauri = self._datauri( filepath );

			css = self._css( file.replace( extension, '' ), datauri, stats );

			fs.appendFileSync( self.output, css + "\n\n" );
		});
		
		// add templateAppend to the output file
		fs.appendFileSync( self.output, self.templateAppend );
		
	};
	DirectoryEncoder.prototype._css = function( name, datauri, stats ) {
		var self = this, width, height;

		if( stats ){
			width = stats.width;
			height = stats.height;
		}
		this.customselectors = this.customselectors || {};
		this.prefix = this.prefix || ".icon-";

		if( this.customselectors[ "*" ] ){
			this.customselectors[ name ] = this.customselectors[ name ] || [];
			var selectors = this.customselectors[ "*" ];
			selectors.forEach( function( el ){
				var s = name.replace( new RegExp( "(" + name + ")" ), el );
				if( self.customselectors[ name ].indexOf( s ) === -1 ) {
					self.customselectors[ name ].push( s );
				}
			});
		}

		var data = {
			prefix: this.prefix,
			name: name,
			datauri: datauri,
			width: width,
			height: height,
			customselectors: this.customselectors[ name ]
		}, css = "";

		if( this.template ){
			css = this.template( data );
		} else {
			for( var i in data.customselectors ){
				if( data.customselectors.hasOwnProperty( i ) ){
					css += data.customselectors[i] + ",\n";
				}
			}
			css += this.prefix + name +
				" { background-image: url('" +
				datauri +
				"'); background-repeat: no-repeat; }";
		}

		return css;
	};

	DirectoryEncoder.prototype._stats = function( file ){
		var encoder, extension = path.extname( file );

		if( typeof DirectoryEncoder.encoders[extension.replace(".", "")] === "undefined" ){
			throw new Error( "Encoder does not recognize file type: " + file );
		}

		encoder = new DirectoryEncoder.encoders[extension.replace(".", "")]( file );

		return encoder.stats();
	};

	DirectoryEncoder.prototype._datauri = function( file ) {
		var encoder, extension = path.extname( file );

		if( typeof DirectoryEncoder.encoders[extension.replace(".", "")] === "undefined" ){
			throw new Error( "Encoder does not recognize file type: " + file );
		}

		encoder = new DirectoryEncoder.encoders[extension.replace(".", "")]( file );

		// TODO passthrough of options is generally a code smell
		return encoder.encode( this.options );
	};

	DirectoryEncoder.prototype._checkName = function( seen, name ) {
		if( seen[name] ){
			throw new Error("Two files with the same name: `" + name + "` exist in the input directory");
		}

		seen[name] = true;
	};

	DirectoryEncoder.prototype._loadTemplate = function( templateFile ) {
		var tmpl;

		if( !templateFile ) { return false; }

		if( fs.existsSync( templateFile ) && fs.lstatSync( templateFile ).isFile() ){
			var source = fs.readFileSync( templateFile ).toString( 'utf-8' );
			tmpl = Handlebars.compile(source);
		} else {
			throw new Error( "Template file either doesn't exist or isn't a file" );
		}

		return tmpl;
	};

	module.exports = DirectoryEncoder;
}());