<commit_before>/**
 * A Font prototype that wraps both a native java.awt.Font and a
 * com.lowagie.text.pdf.BaseFont pointing to the same TrueType file.
 *
 * BaseFont is then used to apply kerning corrections by reading the tables.
 *
 * Carefull: One Font object is not thread safe, so make sure to retrieve
 * new instances for each rendering session (e.g. when changin size).
 * Font.getInstance and Font#initialize handle this properly.
 */

Font = Base.extend({
	initialize: function(filename, antialias, fractionalMetrics) {
		// Cache the native objects for each font, so creation of new
		// instances of font objects can be very fast.
		// This is better than caching the  font objects itself, since they
		// are not thread safe.
		var fontObj = Font.fontCache[filename];
		if (!fontObj) {
			var file = new File(filename);
			if (file.exists()) {
				// Use BaseFont from itext to read kerning tables
				var BaseFont = Packages.com.lowagie.text.pdf.BaseFont;
				var input = new java.io.FileInputStream(file);
				var nativeFont = java.awt.Font.createFont(
						java.awt.Font.TRUETYPE_FONT, input);
				input.close();
				// Don't use the internal font cache!
				var kernedFont = BaseFont.createFont(filename, BaseFont.WINANSI,
						false, false, null, null);
				fontObj = Font.fontCache[filename] = {
					name: kernedFont.getPostscriptFontName(),
					nativeFont: nativeFont,
					kernedFont: kernedFont
				};
			}
		}
		if (fontObj) {
			this.filename = filename;
			this.name = fontObj.name;
			this.nativeFont = fontObj.nativeFont;
			this.kernedFont = fontObj.kernedFont;
			this.size = this.nativeFont.size;
			this.antialias = antialias;
			this.fractionalMetrics = fractionalMetrics;
			this.charSpacing = 0;
		}
	},

	getRenderInfo: function() {
		if (!this.renderInfo)
			this.renderInfo = Font.getRenderInfo(
					this.antialias, this.fractionalMetrics);
		return this.renderInfo;
	},

	getRenderingHints: function() {
		return this.getRenderInfo().hints;
	},

	finalize: function() {
		if (this.nativeFont != null)
			delete this.nativeFont;
	},

	getKerning: function(c1, c2) {
		return this.kernedFont != null ? this.kernedFont.getKerning(
			c1.charCodeAt(0), c2.charCodeAt(0)) : 0;
	},

	getFont: function() {
		return this.nativeFont;
	},

	getSize: function() {
		return this.size;
	},

	setSize: function(size) {
		if (this.size != size) {
			this.size = parseFloat(size);
			this.uniqueString = null;
			if (this.nativeFont)
				this.nativeFont = this.nativeFont.deriveFont(this.size);
		}
		return this;
	},

	getAntialias: function() {
		return this.antialias;
	},

	setAntialias: function(antialias) {
		if (this.antialias != antialias) {
			this.antialias = antialias;
			this.uniqueString = null;
			this.renderInfo = null;
		}
		return this;
	},

	getCharSpacing: function() {
		return this.charSpacing;
	},

	setCharSpacing: function(spacing) {
		if (this.charSpacing != spacing) {
			this.charSpacing = spacing;
			this.uniqueString = null;
		}
		return this;
	},

	processGlyphLine: function(text, maxWidth, layout) {
		if (this.nativeFont) {
			var renderInfo = this.getRenderInfo();
			var glyphs = this.nativeFont.createGlyphVector(
					renderInfo.context, text);
			// Call getCharSpacing with a the text, so subclasses of Font
			// can alter spacing depending on the case of the chars
			// (used in Lineto)
			var charSpacing = this.getCharSpacing(text);
			// Use the font's size, not this.size, as the font may be scaled
			// (used in Lineto)
			var size = this.nativeFont.getSize();
			var x = 0;
			var num = glyphs.getNumGlyphs();
			for (var i = 0; i < num; i++) {
				if (layout) {
					var pos = glyphs.getGlyphPosition(i);
					pos.x = x;
					glyphs.setGlyphPosition(i, pos);
				}
				x += glyphs.getGlyphMetrics(i).getAdvance();
				if (i < num - 1)
					x += (charSpacing + this.getKerning(text.charAt(i),
							text.charAt(i + 1))) * size / 1000;
				if (maxWidth && x >= maxWidth) {
					text = text.substring(0, i);
					if (layout) {
						// Reproduce glyph vector
						var newGlyphs = this.nativeFont.createGlyphVector(
									renderInfo.context, text);
						for (var j = 0; j < i; j++)
							newGlyphs.setGlyphPosition(j,
									glyphs.getGlyphPosition(j));
						glyphs = newGlyphs;
					}
					break;
				}
			}
			return { text: text, glyphs: glyphs, width: x };
		}
	},

	layoutGlyphLine: function(text, maxWidth) {
		var desc = this.processGlyphLine(text, maxWidth, true);
		if (desc) {
			desc.font = this;
			desc.size = this.size;
			// Instead of using the internal baseLine and height settings, use
			// general ones, depending on the height of font only:
			// this makes code like correctBaseLines in FontRenderer.js obsolete
			// and solves many problems with very differently mastered fonts:
			// the values 0.3 and 1.3 are trial & error values which look
			// quite nice...
			// var bounds = glyphs.getLogicalBounds();
			desc.baseLine = this.size * 0.3; // bounds.getMaxY()
			desc.height = this.size * 1.3; // bounds.getHeight()
		}
		return desc;
	},

	getOutline: function(desc, x, y) {
		return desc.glyphs.getOutline(x, y + desc.height - desc.baseLine);
	},

	drawGlyphs: function(g2d, desc, x, y) {
		if (!this.antialias) g2d.drawGlyphVector(desc.glyphs,
				x, y + desc.height - desc.baseLine);
		else g2d.fill(this.getOutline(desc, x, y));
	},

	// getUniqueString returns a string that represents this font identically.
	// This is used for the image rendering
	getUniqueString: function() {
		return this.uniqueString || (this.uniqueString = [
				this.fontName,
				this.antialias ? '1' : '0',
				Math.round(this.size * 100) / 100,
				this.charSpacing
			].join(','));
	},

	/**
	 * This breaks text into lines based on the maxWidth
	 * Breaking happens on newlines and spaces.
	 * if a single word is wider then maxWidth, it will break on a character.
	 */
	breakIntoLines: function(text, maxWidth) {
		var that = this;
		// Split at linebreaks first
		return text.split(/\r\n|\n|\r/mg).each(function(line) {
			while (line != null) {
				var desc = that.processGlyphLine(line, maxWidth);
				if (desc && desc.text.length < line.length) {
					var part = desc.text;
					var pos = part.lastIndexOf(' ');
					if(pos > 0)
						part = part.substring(0, pos);
					this.push(part);
					line = line.substring(part.length + 1) || null;
				} else {
					this.push(desc.text);
					line = null;
				}
			}
		}, []);
	},

	/**
	 * This cuts a string at maxWidth and appends an optional suffix so the
	 * string fits into the width. This can be used to cut client sided strings,
	 * if a web TTF file is used for calculation of the width of the string.
	 */
	truncate: function(text, maxWidth, suffix) {
		// Cache the results of this process for speed improvements
		var key = encodeMd5([ text, maxWidth, this.getUniqueString() ].join(','));
		var cache = Font.truncateCache;
		var value = cache.lookup[key];
		if (!value) {
			var glyphs = this.layoutGlyphLine(text, maxWidth);
			var truncate = glyphs && glyphs.text.length < text.length;
			if (truncate)
				text = glyphs.text.trim();
			value = cache.lookup[key] = {
				text: text,
				truncated: truncate
			};
			cache.keys.push(key);
			// Clean cache if growing too much
			var del = cache.keys.length - 1024;
			if (del > 0) {
				// Remove lookup objects first
				for (var i = 0; i < del; i++)
					delete cache.lookup[cache.keys[i]];
				// Now remove the keys
				cache.keys.splice(0, del);
			}
		}
		return suffix && value.truncated ? value.text + suffix : value.text;
	},

	renderImage: function(text, param) {
		if (param.transform) {
			var method = ({
				uppercase: 'toUpperCase',
				lowercase: 'toLowerCase',
				capitalize: 'capitalize'
			})[param.transform];
			if (method)
				text = text[method]();
		}
		var lines = this.breakIntoLines(text, param.maxWidth);
		if (lines.length > 0) {
			var width = 0;
			for (var i = 0, l = lines.length; i < l; i++) {
				var desc = lines[i] = this.layoutGlyphLine(lines[i]);
				width = Math.max(width, desc.width);
			}
			var desc = lines[0];
			var calcHeight = Math.ceil(desc.height);
			var lineHeight = param.lineHeight
					? param.lineHeight : calcHeight;
			var height = lineHeight * (lines.length - 1) + calcHeight;
			var image = new Image(width, height);
			var g2d = image.getGraphics();
			g2d.setColor(java.awt.Color.decode(param.bgColor || '#ffffff'));
			g2d.fillRect(0, 0, width, height);
			g2d.setColor(java.awt.Color.decode(param.color || '#000000'));
			g2d.setRenderingHints(this.getRenderingHints());

			var multiplier = param.justification == 'right' ? 1 :
					param.justification == 'centered' ? 0.5 : 0; // 0 == 'left' / default
			for (var i = 0, l = lines.length; i < l; i++) {
				var desc = lines[i];
				this.drawGlyphs(g2d, desc,
						(width - desc.width) * multiplier,
						i * lineHeight);
			}

			image.reduceColors(16, false, true);
			image.setTransparentPixel(image.getPixel(0, 0));
			return image;
		}
	},

	renderText: function(text, param, out) {
		this.setSize((param.size || 16).toFloat());
		this.setCharSpacing((param.charSpacing || 0).toFloat());
		var id = [
				this.getUniqueString(), text,
				param.color, param.bgColor, param.maxWidth,
				param.lineHeight, param.justification
			].join(',');
		var entry = Font.renderCache[id];
		if (!entry) {
			var filename = encodeMd5(id) + '.gif';
			var file = new File(app.properties.fontRenderDir, filename);
			var width, height;
			if (!file.exists()) {
				var image = this.renderImage(text, param);
				width = image.width;
				height = image.height;
				image.saveAs(file.getPath(), 1, true);
				image.dispose();
			} else {
				var info = Image.getInfo(file);
				if (info) {
					width = info.getWidth();
					height = info.getHeight();
				}
			}
			if (width && height) {
				entry = Font.renderCache[id] = {
					src: app.properties.fontRenderUri + filename,
					width: width,
					height: height
				};
			}
		}
		var image = param.attributes || {};
		image.src = entry.src;
		image.width = entry.width;
		image.height = entry.height;
		if (!image.alt)
			image.alt = text.replace('\n', ' ');
		return Html.image(image, out);
	},

	statics: {
		fontCache: {},
		renderInfoCache: {},

		renderCache: {},

		truncateCache: {
			keys: [],
			lookup: {}
		},

		getInstance: function(filename, antialias, fractionalMetrics) {
			return filename ? new Font(
				app.properties.fontDir + filename,
				antialias != null
						? antialias
						: (app.properties.fontAntialias || 'true') == 'true',
				fractionalMetrics != null
						? fractionalMetrics
						: (app.properties.fontFractionalMetrics || 'true') == 'true'
			) : null;
		},

		getRenderInfo: function(antialias, fractionalMetrics) {
			// set defaults if undefined:
			if (antialias === undefined)
				antialias = true;

			if (fractionalMetrics === undefined)
				fractionalMetrics = true;

			// create a infoId an cash the renderingInfo
			var id = (antialias ? '1' : '0') + (fractionalMetrics ? '1' : '0');

			var entry = this.renderInfoCache[id];
			// only create if it's not cached already
			if (!entry) {
				var RenderingHints = java.awt.RenderingHints;
				var map = new java.util.HashMap();
				map.put(RenderingHints.KEY_DITHERING,
						RenderingHints.VALUE_DITHER_DISABLE);
				map.put(RenderingHints.KEY_ANTIALIASING,
						RenderingHints.VALUE_ANTIALIAS_ON);
				map.put(RenderingHints.KEY_RENDERING,
						RenderingHints.VALUE_RENDER_QUALITY);
				map.put(RenderingHints.KEY_TEXT_ANTIALIASING, antialias
						? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
						: RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
				map.put(RenderingHints.KEY_FRACTIONALMETRICS, fractionalMetrics
						? RenderingHints.VALUE_FRACTIONALMETRICS_ON
						: RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
				map.put(RenderingHints.KEY_COLOR_RENDERING,
						RenderingHints.VALUE_COLOR_RENDER_QUALITY);
				entry = this.renderInfoCache[id] = {
					context: new java.awt.font.FontRenderContext(null,
							!!antialias, !!fractionalMetrics),
					hints: new RenderingHints(map)
				};
			}
			return entry;
		}
	}
});<commit_msg>Clean up code.<commit_after>/**
 * A Font prototype that wraps both a native java.awt.Font and a
 * com.lowagie.text.pdf.BaseFont pointing to the same TrueType file.
 *
 * BaseFont is then used to apply kerning corrections by reading the tables.
 *
 * Carefull: One Font object is not thread safe, so make sure to retrieve
 * new instances for each rendering session (e.g. when changin size).
 * Font.getInstance and Font#initialize handle this properly.
 */

Font = Base.extend({
	initialize: function(filename, antialias, fractionalMetrics) {
		// Cache the native objects for each font, so creation of new
		// instances of font objects can be very fast.
		// This is better than caching the  font objects itself, since they
		// are not thread safe.
		var fontObj = Font.fontCache[filename];
		if (!fontObj) {
			var file = new File(filename);
			if (file.exists()) {
				// Use BaseFont from itext to read kerning tables
				var BaseFont = Packages.com.lowagie.text.pdf.BaseFont;
				var input = new java.io.FileInputStream(file);
				var nativeFont = java.awt.Font.createFont(
						java.awt.Font.TRUETYPE_FONT, input);
				input.close();
				// Don't use the internal font cache!
				var kernedFont = BaseFont.createFont(filename, BaseFont.WINANSI,
						false, false, null, null);
				fontObj = Font.fontCache[filename] = {
					name: kernedFont.getPostscriptFontName(),
					nativeFont: nativeFont,
					kernedFont: kernedFont
				};
			}
		}
		if (fontObj) {
			this.filename = filename;
			this.name = fontObj.name;
			this.nativeFont = fontObj.nativeFont;
			this.kernedFont = fontObj.kernedFont;
			this.size = this.nativeFont.size;
			this.antialias = antialias;
			this.fractionalMetrics = fractionalMetrics;
			this.charSpacing = 0;
		}
	},

	getRenderInfo: function() {
		if (!this.renderInfo)
			this.renderInfo = Font.getRenderInfo(
					this.antialias, this.fractionalMetrics);
		return this.renderInfo;
	},

	getRenderingHints: function() {
		return this.getRenderInfo().hints;
	},

	finalize: function() {
		if (this.nativeFont != null)
			delete this.nativeFont;
	},

	getKerning: function(c1, c2) {
		return this.kernedFont != null ? this.kernedFont.getKerning(
			c1.charCodeAt(0), c2.charCodeAt(0)) : 0;
	},

	getFont: function() {
		return this.nativeFont;
	},

	getSize: function() {
		return this.size;
	},

	setSize: function(size) {
		if (this.size != size) {
			this.size = parseFloat(size);
			this.uniqueString = null;
			if (this.nativeFont)
				this.nativeFont = this.nativeFont.deriveFont(this.size);
		}
		return this;
	},

	getAntialias: function() {
		return this.antialias;
	},

	setAntialias: function(antialias) {
		if (this.antialias != antialias) {
			this.antialias = antialias;
			this.uniqueString = null;
			this.renderInfo = null;
		}
		return this;
	},

	getCharSpacing: function() {
		return this.charSpacing;
	},

	setCharSpacing: function(spacing) {
		if (this.charSpacing != spacing) {
			this.charSpacing = spacing;
			this.uniqueString = null;
		}
		return this;
	},

	processGlyphLine: function(text, maxWidth, layout) {
		if (this.nativeFont) {
			var renderInfo = this.getRenderInfo();
			var glyphs = this.nativeFont.createGlyphVector(
					renderInfo.context, text);
			// Call getCharSpacing with a the text, so subclasses of Font
			// can alter spacing depending on the case of the chars
			// (used in Lineto)
			var charSpacing = this.getCharSpacing(text);
			// Use the font's size, not this.size, as the font may be scaled
			// (used in Lineto)
			var size = this.nativeFont.getSize();
			var x = 0;
			var num = glyphs.getNumGlyphs();
			for (var i = 0; i < num; i++) {
				if (layout) {
					var pos = glyphs.getGlyphPosition(i);
					pos.x = x;
					glyphs.setGlyphPosition(i, pos);
				}
				x += glyphs.getGlyphMetrics(i).getAdvance();
				if (i < num - 1)
					x += (charSpacing + this.getKerning(text.charAt(i),
							text.charAt(i + 1))) * size / 1000;
				if (maxWidth && x >= maxWidth) {
					text = text.substring(0, i);
					if (layout) {
						// Reproduce glyph vector
						var newGlyphs = this.nativeFont.createGlyphVector(
									renderInfo.context, text);
						for (var j = 0; j < i; j++)
							newGlyphs.setGlyphPosition(j,
									glyphs.getGlyphPosition(j));
						glyphs = newGlyphs;
					}
					break;
				}
			}
			return { text: text, glyphs: glyphs, width: x };
		}
	},

	layoutGlyphLine: function(text, maxWidth) {
		var desc = this.processGlyphLine(text, maxWidth, true);
		if (desc) {
			desc.font = this;
			desc.size = this.size;
			// Instead of using the internal baseLine and height settings, use
			// general ones, depending on the height of font only:
			// this makes code like correctBaseLines in FontRenderer.js obsolete
			// and solves many problems with very differently mastered fonts:
			// the values 0.3 and 1.3 are trial & error values which look
			// quite nice...
			// var bounds = glyphs.getLogicalBounds();
			desc.baseLine = this.size * 0.3; // bounds.getMaxY()
			desc.height = this.size * 1.3; // bounds.getHeight()
		}
		return desc;
	},

	getOutline: function(desc, x, y) {
		return desc.glyphs.getOutline(x, y + desc.height - desc.baseLine);
	},

	drawGlyphs: function(g2d, desc, x, y) {
		if (!this.antialias) g2d.drawGlyphVector(desc.glyphs,
				x, y + desc.height - desc.baseLine);
		else g2d.fill(this.getOutline(desc, x, y));
	},

	// getUniqueString returns a string that represents this font identically.
	// This is used for the image rendering
	getUniqueString: function() {
		return this.uniqueString || (this.uniqueString = [
				this.fontName,
				this.antialias ? '1' : '0',
				Math.round(this.size * 100) / 100,
				this.charSpacing
			].join(','));
	},

	/**
	 * This breaks text into lines based on the maxWidth
	 * Breaking happens on newlines and spaces.
	 * if a single word is wider then maxWidth, it will break on a character.
	 */
	breakIntoLines: function(text, maxWidth) {
		var that = this;
		// Split at linebreaks first
		return text.split(/\r\n|\n|\r/mg).each(function(line) {
			while (line != null) {
				var desc = that.processGlyphLine(line, maxWidth);
				if (desc && desc.text.length < line.length) {
					var part = desc.text;
					var pos = part.lastIndexOf(' ');
					if(pos > 0)
						part = part.substring(0, pos);
					this.push(part);
					line = line.substring(part.length + 1) || null;
				} else {
					this.push(desc.text);
					line = null;
				}
			}
		}, []);
	},

	/**
	 * This cuts a string at maxWidth and appends an optional suffix so the
	 * string fits into the width. This can be used to cut client sided strings,
	 * if a web TTF file is used for calculation of the width of the string.
	 */
	truncate: function(text, maxWidth, suffix) {
		// Cache the results of this process for speed improvements
		var key = encodeMd5([ text, maxWidth, this.getUniqueString() ].join(','));
		var cache = Font.truncateCache;
		var value = cache.lookup[key];
		if (!value) {
			var glyphs = this.layoutGlyphLine(text, maxWidth);
			var truncate = glyphs && glyphs.text.length < text.length;
			if (truncate)
				text = glyphs.text.trim();
			value = cache.lookup[key] = {
				text: text,
				truncated: truncate
			};
			cache.keys.push(key);
			// Clean cache if growing too much
			var del = cache.keys.length - 1024;
			if (del > 0) {
				// Remove lookup objects first
				for (var i = 0; i < del; i++)
					delete cache.lookup[cache.keys[i]];
				// Now remove the keys
				cache.keys.splice(0, del);
			}
		}
		return suffix && value.truncated ? value.text + suffix : value.text;
	},

	renderImage: function(text, param) {
		if (param.transform) {
			var method = ({
				uppercase: 'toUpperCase',
				lowercase: 'toLowerCase',
				capitalize: 'capitalize'
			})[param.transform];
			if (method)
				text = text[method]();
		}
		var lines = this.breakIntoLines(text, param.maxWidth);
		if (lines.length > 0) {
			var width = 0;
			for (var i = 0, l = lines.length; i < l; i++) {
				var desc = lines[i] = this.layoutGlyphLine(lines[i]);
				width = Math.max(width, desc.width);
			}
			var desc = lines[0];
			var calcHeight = Math.ceil(desc.height);
			var lineHeight = param.lineHeight
					? param.lineHeight : calcHeight;
			var height = lineHeight * (lines.length - 1) + calcHeight;
			var image = new Image(width, height);
			var g2d = image.getGraphics();
			g2d.setColor(java.awt.Color.decode(param.bgColor || '#ffffff'));
			g2d.fillRect(0, 0, width, height);
			g2d.setColor(java.awt.Color.decode(param.color || '#000000'));
			g2d.setRenderingHints(this.getRenderingHints());

			// 0 == 'left' / default
			var multiplier = param.justification == 'right' ? 1 :
					param.justification == 'centered' ? 0.5 : 0;
			for (var i = 0, l = lines.length; i < l; i++) {
				var desc = lines[i];
				this.drawGlyphs(g2d, desc,
						(width - desc.width) * multiplier,
						i * lineHeight);
			}

			image.reduceColors(16, false, true);
			image.setTransparentPixel(image.getPixel(0, 0));
			return image;
		}
	},

	renderText: function(text, param, out) {
		this.setSize((param.size || 16).toFloat());
		this.setCharSpacing((param.charSpacing || 0).toFloat());
		var id = [
				this.getUniqueString(), text,
				param.color, param.bgColor, param.maxWidth,
				param.lineHeight, param.justification
			].join(',');
		var entry = Font.renderCache[id];
		if (!entry) {
			var filename = encodeMd5(id) + '.gif';
			var file = new File(app.properties.fontRenderDir, filename);
			var width, height;
			if (!file.exists()) {
				var image = this.renderImage(text, param);
				width = image.width;
				height = image.height;
				image.saveAs(file.getPath(), 1, true);
				image.dispose();
			} else {
				var info = Image.getInfo(file);
				if (info) {
					width = info.getWidth();
					height = info.getHeight();
				}
			}
			if (width && height) {
				entry = Font.renderCache[id] = {
					src: app.properties.fontRenderUri + filename,
					width: width,
					height: height
				};
			}
		}
		var image = param.attributes || {};
		image.src = entry.src;
		image.width = entry.width;
		image.height = entry.height;
		if (!image.alt)
			image.alt = text.replace('\n', ' ');
		return Html.image(image, out);
	},

	statics: {
		fontCache: {},
		renderInfoCache: {},

		renderCache: {},

		truncateCache: {
			keys: [],
			lookup: {}
		},

		getInstance: function(filename, antialias, fractionalMetrics) {
			return filename ? new Font(
				app.properties.fontDir + filename,
				antialias != null
						? antialias
						: (app.properties.fontAntialias || 'true') == 'true',
				fractionalMetrics != null
						? fractionalMetrics
						: (app.properties.fontFractionalMetrics || 'true') == 'true'
			) : null;
		},

		getRenderInfo: function(antialias, fractionalMetrics) {
			// set defaults if undefined:
			if (antialias === undefined)
				antialias = true;

			if (fractionalMetrics === undefined)
				fractionalMetrics = true;

			// create a infoId an cash the renderingInfo
			var id = (antialias ? '1' : '0') + (fractionalMetrics ? '1' : '0');

			var entry = this.renderInfoCache[id];
			// only create if it's not cached already
			if (!entry) {
				var RenderingHints = java.awt.RenderingHints;
				var map = new java.util.HashMap();
				map.put(RenderingHints.KEY_DITHERING,
						RenderingHints.VALUE_DITHER_DISABLE);
				map.put(RenderingHints.KEY_ANTIALIASING,
						RenderingHints.VALUE_ANTIALIAS_ON);
				map.put(RenderingHints.KEY_RENDERING,
						RenderingHints.VALUE_RENDER_QUALITY);
				map.put(RenderingHints.KEY_TEXT_ANTIALIASING, antialias
						? RenderingHints.VALUE_TEXT_ANTIALIAS_ON
						: RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
				map.put(RenderingHints.KEY_FRACTIONALMETRICS, fractionalMetrics
						? RenderingHints.VALUE_FRACTIONALMETRICS_ON
						: RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
				map.put(RenderingHints.KEY_COLOR_RENDERING,
						RenderingHints.VALUE_COLOR_RENDER_QUALITY);
				entry = this.renderInfoCache[id] = {
					context: new java.awt.font.FontRenderContext(null,
							!!antialias, !!fractionalMetrics),
					hints: new RenderingHints(map)
				};
			}
			return entry;
		}
	}
});<|endoftext|>


<commit_before>/*
  use renderRows and sets-> Original Data !
*/

(function(window) {
  //window.Powerset = window.Powerset || {};
  //var ps = window.Powerset;
  console.log("powerset registered!");
  window.document.title += " - Powerset!";

  $(".header-container").append(" Powerset: <input type='checkbox' onclick='window.Powerset.toggle()'>");

  var ps = window.Powerset = function PowerSet(rr, sets, scale) {
    var svg = d3.select("#bodyVis").select("svg");
    var renderRows = rr;
    var sets = sets;
    var setScale = scale;
    console.log("init powerset with " + renderRows.length + " renderRows");
    console.log("init powerset with " + sets.length + " sets");

    var groupRows = getGroupRows();
    var subsetRows = getSubsetRows();

    function getGroupRows() {
      return renderRows.filter(function(d, i) {
        if (d.data.type === ROW_TYPE.GROUP || d.data.type === ROW_TYPE.AGGREGATE)
          return true;
        return false;
      });
    }

    function getSubsetRows() {
      return renderRows.filter(function(d) {
        return d.data.type === ROW_TYPE.SUBSET;
      });
    }

    function getGroupNames() {
      // get array of group names + subsets
      return groupRows.map(function(o) {
        var text = o.data.elementName;
        o.data.subSets.forEach(function(obj) {
          var setNames = obj.combinedSets.map(function(value, idx) {
            if (value === 1) {
              return idx;
            }
          });
          var name = "";
          setNames.forEach(function(val, idx) {
            if (val) {
              name += (name.length > 0 ? " | " : "") + window.sets[val].elementName;
            }
          });
          if (obj.setSize > 0) {
            text += ":  " + name + "(" + obj.setSize + ")";
          }
        });
        return text;
      });
    }

    function printText() {
      var groupNames = getGroupNames();
      //  write texts for groupnames
      var elem = svg.selectAll("text").data(groupNames).enter();
      elem.append("text")
        .attr("fill", "red")
        .attr("y", function(d, idx) {
          return 20 + (20 * idx);
        })
        .text(function(d, idx) {
          return d;
        });
    }

    this.draw = function() {
      groupRows.forEach(function(group, idx) {
        console.info("groupRow:", group, idx);
      });

      var svgWidth = parseInt(svg.attr("width"), 10);
      var svgHeight = parseInt(svg.attr("height"), 10);

      var degreeHeight = svgHeight / groupRows.length;
      var degreeWidth = svgWidth - 200;

      var setRects = svg.selectAll("rect.pw-gset")
      setRects.data(groupRows)
        .enter()
        .append("rect")
        .attr("class", function(d, idx) {
          return "pw-gset pw-gset-" + idx;
        })
        .attr("x", 200)
        .attr("y", function(d, idx) {
          return (10 + degreeHeight) * idx;
        })
        .attr("width", degreeWidth)
        .attr("height", degreeHeight);

      svg.selectAll("text.pw-gtext")
        .data(groupRows)
        .enter()
        .append("text")
        .text(function(d) {
          return d.data.elementName;
        })
        .attr("class", "pw-gtext")
        .attr("x", 0)
        .attr("y", function(d, idx) {
          return 30 + ( (10 + degreeHeight) * idx);
        });

      updateSubsetRows(setRects, setScale);
    };

    function updateSubsetRows(setRects, setScale) {

      console.warn(setRects);
      setRects.each(function(d, idx) {
        var g = d3.select(this);
        var x = parseInt(g.attr("x"), 10);
        var y = parseInt(g.attr("y"), 10);

        var height = 20;
        var width = 20;

        // TODO maybe use subsetRows --> more information
        var subsets = d.data.subSets;

        subsets.forEach(function(d) {
          console.log(d)
        });

        var subSetRects = svg.selectAll("rect.pw-set-" + idx).data(subsets).enter();
        subSetRects.append("rect")
          .attr("class", "pw-set pw-set-" + idx)
          .attr("x", function(d, idx) {
            return x + ((width * 2) * idx);
          })
          .attr("y", function(d, idx) {
            return y + height;
          })
          .on("mouseenter", function(d) {
            console.info(d.elementName, d.setSize);
          })
          .attr("width", width)
          .attr("height", height);

      });

    };

  };

  /* OPTIONS */
  ps.active = true;
  ps.toggle = function() {
    ps.active = !ps.active;
    console.info("Powerset active: " + ps.active);
    UpSet();
  };

})(window);
<commit_msg> break line on max-width<commit_after>/*
  use renderRows and sets-> Original Data !
*/

(function(window) {
  //window.Powerset = window.Powerset || {};
  //var ps = window.Powerset;
  console.log("powerset registered!");
  window.document.title += " - Powerset!";

  $(".header-container").append(" Powerset: <input type='checkbox' onclick='window.Powerset.toggle()'>");

  var ps = window.Powerset = function PowerSet(rr, sets, scale) {
    var svg = d3.select("#bodyVis").select("svg");
    var renderRows = rr;
    var sets = sets;
    var setScale = scale;
    console.log("init powerset with " + renderRows.length + " renderRows");
    console.log("init powerset with " + sets.length + " sets");

    var groupRows = getGroupRows();
    var subsetRows = getSubsetRows();

    var svgWidth = parseInt(svg.attr("width"), 10);
    var svgHeight = parseInt(svg.attr("height"), 10);
    var degreeHeight = svgHeight / groupRows.length;
    var degreeWidth = svgWidth - 200;

    function getGroupRows() {
      return renderRows.filter(function(d, i) {
        if (d.data.type === ROW_TYPE.GROUP || d.data.type === ROW_TYPE.AGGREGATE)
          return true;
        return false;
      });
    }

    function getSubsetRows() {
      return renderRows.filter(function(d) {
        return d.data.type === ROW_TYPE.SUBSET;
      });
    }

    function getGroupNames() {
      // get array of group names + subsets
      return groupRows.map(function(o) {
        var text = o.data.elementName;
        o.data.subSets.forEach(function(obj) {
          var setNames = obj.combinedSets.map(function(value, idx) {
            if (value === 1) {
              return idx;
            }
          });
          var name = "";
          setNames.forEach(function(val, idx) {
            if (val) {
              name += (name.length > 0 ? " | " : "") + window.sets[val].elementName;
            }
          });
          if (obj.setSize > 0) {
            text += ":  " + name + "(" + obj.setSize + ")";
          }
        });
        return text;
      });
    }

    function printText() {
      var groupNames = getGroupNames();
      //  write texts for groupnames
      var elem = svg.selectAll("text").data(groupNames).enter();
      elem.append("text")
        .attr("fill", "red")
        .attr("y", function(d, idx) {
          return 20 + (20 * idx);
        })
        .text(function(d, idx) {
          return d;
        });
    }

    this.draw = function() {
      groupRows.forEach(function(group, idx) {
        console.info("groupRow:", group, idx);
      });

      var setRects = svg.selectAll("rect.pw-gset")
      setRects.data(groupRows)
        .enter()
        .append("rect")
        .attr("class", function(d, idx) {
          return "pw-gset pw-gset-" + idx;
        })
        .attr("x", 200)
        .attr("y", function(d, idx) {
          return (10 + degreeHeight) * idx;
        })
        .attr("width", degreeWidth)
        .attr("height", degreeHeight);

      svg.selectAll("text.pw-gtext")
        .data(groupRows)
        .enter()
        .append("text")
        .text(function(d) {
          return d.data.elementName;
        })
        .attr("class", "pw-gtext")
        .attr("x", 0)
        .attr("y", function(d, idx) {
          return 30 + ((10 + degreeHeight) * idx);
        });

      drawSubsets(setRects, setScale);
    };

    function drawSubsets(setRects, setScale) {

      console.warn(setRects);
      setRects.each(function(d, idx) {
        var g = d3.select(this);
        var x = parseInt(g.attr("x"), 10);
        var y = parseInt(g.attr("y"), 10);

        var height = 30;
        var width = 30;

        // TODO maybe use subsetRows --> more information
        var subsets = d.data.subSets;

        subsets.forEach(function(d) {
          console.log(d)
        });

        var subSetRects = svg.selectAll("rect.pw-set-" + idx).data(subsets).enter();
        subSetRects.append("rect")
          .attr("class", "pw-set pw-set-" + idx)
          .attr("x", function(d, idx) {
            var val = ((width * 2) * idx);
            var row = parseInt(val / degreeWidth,10);
            return x + (val % degreeWidth);
          })
          .attr("y", function(d, idx) {
            var val = ((height * 2) * idx);
            var row = parseInt(val / degreeWidth,10);
            return y + height + (row * height);
          })
          .on("mouseenter", function(d) {
            console.info(d.elementName, d.setSize);
          })
          .attr("width", width)
          .attr("height", height);

      });

    };

  };

  /* OPTIONS */
  ps.active = true;
  ps.toggle = function() {
    ps.active = !ps.active;
    console.info("Powerset active: " + ps.active);
    UpSet();
  };

})(window);
<|endoftext|>


<commit_before>const { config } = require('./common')

const { apiPrefix } = config
let database = [
  {
    id: '1',
    icon: 'laptop',
    name: '主页',
    module: 'common',
    route: '/dashboard',
  },
  {
    id: '2',
    bpid: '1',
    name: '内容管理',
    icon: 'appstore-o',
    module: 'content',
    route: '/content',
  },
  {
    id: '21',
    bpid: '2',
    mpid: '2',
    name: '文章管理',
    icon: 'file',
    route: '/content/article',
  },
  {
    id: '211',
    mpid: '-1',
    bpid: '21',
    name: '新建文章',
    icon: 'edit',
    route: '/content/article/add',
  },
  {
    id: '212',
    mpid: '-1',
    bpid: '21',
    name: '编辑文章',
    icon: 'edit',
    route: '/content/article/edit/:id',
  },
  {
    id: '213',
    mpid: '-1',
    bpid: '21',
    name: '文章详情',
    icon: 'book',
    route: '/content/article/view/:id',
  },
  {
    id: '22',
    bpid: '2',
    mpid: '2',
    name: '分类管理',
    icon: 'tags-o',
    route: '/content/catalog',
  },
  {
    id: '221',
    mpid: '-1',
    bpid: '22',
    name: '分类详情',
    icon: 'book',
    route: '/content/catalog/view/:id',
  },
  {
    id: '23',
    bpid: '2',
    mpid: '2',
    name: '链接管理',
    icon: 'share-alt',
    route: '/content/link',
  },
  {
    id: '231',
    mpid: '-1',
    bpid: '23',
    name: '链接详情',
    icon: 'book',
    route: '/content/link/view/:id',
  },
  {
    id: '24',
    bpid: '2',
    mpid: '2',
    name: '文件管理',
    icon: 'file',
    route: '/content/media',
  },
  {
    id: '241',
    mpid: '-1',
    bpid: '24',
    name: '文件详情',
    icon: 'book',
    route: '/content/media/view/:id',
  },
  {
    id: '3',
    bpid: '1',
    name: '账号管理',
    module: 'account',
    icon: 'team',
  },
  {
    id: '31',
    bpid: '3',
    mpid: '3',
    name: '用户信息',
    icon: 'user',
    route: '/account/user',
  },
  {
    id: '311',
    mpid: '-1',
    bpid: '31',
    name: '用户详情',
    icon: 'book',
    route: '/account/user/view/:id',
  },
  {
    id: '32',
    bpid: '3',
    mpid: '3',
    name: '分组信息',
    icon: 'folder',
    route: '/account/group',
  },
  {
    id: '321',
    mpid: '-1',
    bpid: '32',
    name: '分组详情',
    icon: 'book',
    route: '/account/group/view/:id',
  },
  {
    id: '4',
    bpid: '1',
    name: '权限管理',
    module: 'authority',
    icon: 'select',
  },
  {
    id: '41',
    bpid: '4',
    mpid: '4',
    name: 'ACL管理',
    icon: 'usb',
    route: '/authority/acl',
  },
  {
    id: '411',
    mpid: '-1',
    bpid: '41',
    name: 'ACL详情',
    icon: 'book',
    route: '/authority/acl/view/:id',
  },
  {
    id: '42',
    bpid: '4',
    mpid: '4',
    name: '模块管理',
    icon: 'api',
    route: '/authority/module',
  },
  {
    id: '421',
    mpid: '-1',
    bpid: '42',
    name: '模块详情',
    icon: 'book',
    route: '/authority/module/view/:id',
  },
  {
    id: '43',
    bpid: '4',
    mpid: '4',
    name: '用户管理',
    icon: 'user',
    route: '/authority/user',
  },
  {
    id: '431',
    mpid: '-1',
    bpid: '43',
    name: '用户详情',
    icon: 'book',
    route: '/authority/user/view/:id',
  },
  {
    id: '5',
    bpid: '1',
    name: '系统设置',
    module: 'system',
    icon: 'setting',
  },
  {
    id: '51',
    bpid: '5',
    mpid: '5',
    name: '基本信息',
    icon: 'info-circle-o',
    route: '/system/info',
  },
]

module.exports = {

  [`GET ${apiPrefix}/menus`] (req, res) {
    const { query } = req
    const { authToken } = query
    console.log(query)

    if (authToken) {
      res.status(200).json({ list: database, errorCode: 0 })
    } else {
      res.status(200).json({ errorCode: 2 })
    }
  },
}
<commit_msg>更改文件管理图标<commit_after>const { config } = require('./common')

const { apiPrefix } = config
let database = [
  {
    id: '1',
    icon: 'laptop',
    name: '主页',
    module: 'common',
    route: '/dashboard',
  },
  {
    id: '2',
    bpid: '1',
    name: '内容管理',
    icon: 'appstore-o',
    module: 'content',
    route: '/content',
  },
  {
    id: '21',
    bpid: '2',
    mpid: '2',
    name: '文章管理',
    icon: 'file',
    route: '/content/article',
  },
  {
    id: '211',
    mpid: '-1',
    bpid: '21',
    name: '新建文章',
    icon: 'edit',
    route: '/content/article/add',
  },
  {
    id: '212',
    mpid: '-1',
    bpid: '21',
    name: '编辑文章',
    icon: 'edit',
    route: '/content/article/edit/:id',
  },
  {
    id: '213',
    mpid: '-1',
    bpid: '21',
    name: '文章详情',
    icon: 'book',
    route: '/content/article/view/:id',
  },
  {
    id: '22',
    bpid: '2',
    mpid: '2',
    name: '分类管理',
    icon: 'tags-o',
    route: '/content/catalog',
  },
  {
    id: '221',
    mpid: '-1',
    bpid: '22',
    name: '分类详情',
    icon: 'book',
    route: '/content/catalog/view/:id',
  },
  {
    id: '23',
    bpid: '2',
    mpid: '2',
    name: '链接管理',
    icon: 'share-alt',
    route: '/content/link',
  },
  {
    id: '231',
    mpid: '-1',
    bpid: '23',
    name: '链接详情',
    icon: 'book',
    route: '/content/link/view/:id',
  },
  {
    id: '24',
    bpid: '2',
    mpid: '2',
    name: '文件管理',
    icon: 'picture',
    route: '/content/media',
  },
  {
    id: '241',
    mpid: '-1',
    bpid: '24',
    name: '文件详情',
    icon: 'book',
    route: '/content/media/view/:id',
  },
  {
    id: '3',
    bpid: '1',
    name: '账号管理',
    module: 'account',
    icon: 'team',
  },
  {
    id: '31',
    bpid: '3',
    mpid: '3',
    name: '用户信息',
    icon: 'user',
    route: '/account/user',
  },
  {
    id: '311',
    mpid: '-1',
    bpid: '31',
    name: '用户详情',
    icon: 'book',
    route: '/account/user/view/:id',
  },
  {
    id: '32',
    bpid: '3',
    mpid: '3',
    name: '分组信息',
    icon: 'folder',
    route: '/account/group',
  },
  {
    id: '321',
    mpid: '-1',
    bpid: '32',
    name: '分组详情',
    icon: 'book',
    route: '/account/group/view/:id',
  },
  {
    id: '4',
    bpid: '1',
    name: '权限管理',
    module: 'authority',
    icon: 'select',
  },
  {
    id: '41',
    bpid: '4',
    mpid: '4',
    name: 'ACL管理',
    icon: 'usb',
    route: '/authority/acl',
  },
  {
    id: '411',
    mpid: '-1',
    bpid: '41',
    name: 'ACL详情',
    icon: 'book',
    route: '/authority/acl/view/:id',
  },
  {
    id: '42',
    bpid: '4',
    mpid: '4',
    name: '模块管理',
    icon: 'api',
    route: '/authority/module',
  },
  {
    id: '421',
    mpid: '-1',
    bpid: '42',
    name: '模块详情',
    icon: 'book',
    route: '/authority/module/view/:id',
  },
  {
    id: '43',
    bpid: '4',
    mpid: '4',
    name: '用户管理',
    icon: 'user',
    route: '/authority/user',
  },
  {
    id: '431',
    mpid: '-1',
    bpid: '43',
    name: '用户详情',
    icon: 'book',
    route: '/authority/user/view/:id',
  },
  {
    id: '5',
    bpid: '1',
    name: '系统设置',
    module: 'system',
    icon: 'setting',
  },
  {
    id: '51',
    bpid: '5',
    mpid: '5',
    name: '基本信息',
    icon: 'info-circle-o',
    route: '/system/info',
  },
]

module.exports = {

  [`GET ${apiPrefix}/menus`] (req, res) {
    const { query } = req
    const { authToken } = query
    console.log(query)

    if (authToken) {
      res.status(200).json({ list: database, errorCode: 0 })
    } else {
      res.status(200).json({ errorCode: 2 })
    }
  },
}
<|endoftext|>


<commit_before>

var SendGrid = require('sendgrid').SendGrid
    ,Email = require('sendgrid').Email;

var sendgrid, from;

exports.load = function(app)
{
    sendgrid = new SendGrid(app.settings.sendgrid_user, app.settings.sendgrid_key);
    from = app.settings.system_email;
};

var sendMail = exports.sendMail = function(to,body,subject,callback) {

    if(!sendgrid) {
        console.log('email not sent because it\'s off in app.js. to turn mails on set app.set("send_mails",true); ');
        callback();
        return;
    }

    console.log('sending to ' + to + ' ' + subject);

    var email = new Email({
        to:[to],
        from:from,
        fromname:'אתר מחליטים: כבוד האדם',
        subject:subject,
        html:body
    });

    sendgrid.send(email,function(success,message) {
        if(!success){
            console.error('mail was not sent');
            callback(message);
        }
        else{
            console.log('mail was sent');
            callback(null,message);
        }
    });

};

var sendMailFromTemplate = exports.sendMailFromTemplate = function(to,string,callback) {
    var parts = string.split('<!--body -->');
    var subject = parts[0] || 'אתר מחליטים: כבוד האדם';
    var body = parts[1] || parts[0];
    sendMail(to,body,subject,callback);
};<commit_msg>changed email from<commit_after>

var SendGrid = require('sendgrid').SendGrid
    ,Email = require('sendgrid').Email;

var sendgrid, from;

exports.load = function(app)
{
    sendgrid = new SendGrid(app.settings.sendgrid_user, app.settings.sendgrid_key);
    from = app.settings.system_email;
};

var sendMail = exports.sendMail = function(to,body,subject,callback) {

    if(!sendgrid) {
        console.log('email not sent because it\'s off in app.js. to turn mails on set app.set("send_mails",true); ');
        callback();
        return;
    }

    console.log('sending to ' + to + ' ' + subject);

    var email = new Email({
        to:[to],
        from:from,
        fromname:'אמנת הולכי רגל ורוכבי אופניים',
        subject:subject,
        html:body
    });

    sendgrid.send(email,function(success,message) {
        if(!success){
            console.error('mail was not sent');
            callback(message);
        }
        else{
            console.log('mail was sent');
            callback(null,message);
        }
    });

};

var sendMailFromTemplate = exports.sendMailFromTemplate = function(to,string,callback) {
    var parts = string.split('<!--body -->');
    var subject = parts[0] || 'אמנת הולכי רגל ורוכבי אופניים';
    var body = parts[1] || parts[0];
    sendMail(to,body,subject,callback);
};<|endoftext|>


<commit_before>'use babel';

import { Vue } from 'use-vue';
import { requirePackages } from 'atom-utils';
import StateMachine from 'javascript-state-machine';

import './module/use-vue-config';

import {
    DEV,
    NAME,
} from './module/constant';

import console from './module/console';

let { autoToggle } = !!atom.config.get(`${ NAME.kebab }`);
console.log('autoToggle => ', autoToggle);

let addInfo = ( detail ) => atom.notifications.addInfo(`${ NAME }`, { detail });
let showTips = () => addInfo(`Plugin require "tree-view".`);

Vue.prototype.$dispatch = function ( event, payload ) {
    return new Promise(( resolve ) => {
        this.$emit(`${ event }`, resolve, payload);
    });
};

class TreeViewSearchBar {

    /**
     * Plugin Active State
     * @type {Boolean}
     */
    active = false;

    /**
     * Plugin Commands Collection
     * @type {Object}
     */
    commands = {};

    /**
     * Define Finite State Machine Model
     * @type {StateMachine}
     * @type {String} Status | "Null" | "Dependent" | "Created" | "Actived" | "Disabled" | "Destroyed" |
     * @type {String} Event | "Setup" | "Create" | "Activate" | "Deactivate" | "Destroy" | "Teardown" |
     */
    fsm = StateMachine.create({
        initial : 'Null',
        error : null,
        events : [
            {
                from : 'Null',
                name : 'Setup',
                to : 'Dependent',
            },
            {
                from : 'Dependent',
                name : 'Create',
                to : 'Created',
            },
            {
                from : ['Created', 'Disabled'],
                name : 'Activate',
                to : 'Actived',
            },
            {
                from : 'Actived',
                name : 'Deactivate',
                to : 'Disabled',
            },
            {
                from : ['Disabled', 'Actived', 'Created', 'Dependent'],
                name : 'Destroy',
                to : 'Destroyed',
            },
            {
                from : 'Destroyed',
                name : 'Teardown',
                to : 'Null',
            },
        ],
    });

    constructor () {

        if (DEV) {
            window.test = this;
        }

        /**
         * Setup Stage
         */
        this.on('Setup', async () => {
            console.log('event => Setup');
            let [{ treeView }] = await requirePackages('tree-view');
            Vue.prototype.$treeView = treeView;

            if (treeView && treeView.isVisible()) {
                this.emit('Create');
            } else {
                showTips();
                this.add('search-bar:toggle', showTips);
                let ensureTreeViewVisible = () => {
                    console.log('ensureTreeViewVisible');
                    process.nextTick(() => {
                        if (treeView && treeView.isVisible() && atom.project.rootDirectories.length) {
                            this.emit('Create');
                        }
                    });
                };
                this.add('tree-view:show', ensureTreeViewVisible);
                this.add('tree-view:toggle', ensureTreeViewVisible);
                let projectListener = atom.project.onDidChangePaths(ensureTreeViewVisible);
                this.on('leaveDependent', () => {
                    console.log('event => leaveDependent');
                    this.remove(
                        'tree-view:show',
                        'tree-view:toggle',
                        'search-bar:toggle',
                    );
                    projectListener.disposalAction();
                });
            }
        });

        /**
         * Create Stage
         */
        this.on('Create', async () => {
            console.log('event => Create');
            let treeView = Vue.prototype.$treeView;

            atom.notifications.addSuccess(`${ NAME }`, {
                detail : 'Plugin is running!',
            });

            /**
             * Vue instance
             * @type {Vue|null}
             */
            let vm = null;
            if (DEV) {
                Vue.set(window.test, 'Vue', Vue);
                Vue.set(window.test, 'vm', {
                    get () {
                        return vm;
                    },
                });
            }

            /**
             * Plugin Placeholder
             * @type {Element}
             */
            let element = document.createElement('div');

            /**
             * Activate Stage
             */
            this.on('Activate', async () => {
                console.log('Activate');
                if (vm) {
                    await vm.$dispatch('show');
                } else {
                    if (DEV) {
                        let path = require('path');
                        let files = [
                            './views/app.vue',
                        ];
                        let Module = module.constructor;
                        for (let file of files) {
                            Module._cache[path.join(__dirname, file)] = null;
                        }
                    }
                    let app = require('./views/app.vue');
                    vm = new Vue(app);
                    treeView.element.parentNode.insertBefore(element, treeView.element);
                    vm.$mount(element);
                }
                console.log('app => show');
            });

            /**
             * Destroy Vue instance
             * @type {Function}
             */
            let clean = async () => {
                if (vm) {
                    await vm.$dispatch('hide');
                    vm = null;
                }
                console.log('app => hide');
            };

            /**
             * Deactivate Stage
             */
            this.on('Deactivate', () => {
                console.log('Deactivate');
                clean();
            });

            /**
             * Destroy Stage
             */
            this.on('Destroy', () => {
                console.log('Destroy');
                // clean();
            });

            /**
             * ensure Tree View visible
             * @param {Function} callback
             * @return {Function} handler
             */
            let requireTreeView = ( callback ) => {
                return () => {
                    if (treeView.isVisible()) {
                        callback();
                    } else {
                        showTips();
                    }
                };
            };

            this.add('search-bar:show', requireTreeView(() => {
                this.emit('Activate');
            }));
            this.add('search-bar:hide', requireTreeView(() => {
                this.emit('Deactivate');
            }));
            this.add('search-bar:focus', requireTreeView(() => {
                this.emit('Activate');
                vm.$emit('focus');
            }));
            this.add('search-bar:toggle', requireTreeView(() => {
                let current = this.fsm.current;
                this.emit('Activate');
                if (current === this.fsm.current) {
                    this.emit('Deactivate');
                }
            }));

            /**
             * autoToggle
             */
            if (autoToggle) {
                this.emit('Activate');
            }

        });

        /**
         * Teardown Stage
         */
        this.on('Teardown', () => {
            console.log('event => Teardown');
            this.remove(
                'tree-view:show',
                'tree-view:toggle',
                'search-bar:show',
                'search-bar:hide',
                'search-bar:focus',
                'search-bar:toggle',
            );
        });

    }

    /**
     * Plugin Active State
     * @return {Boolean} active
     */
    isActive () {
        return this.active;
    }

    /**
     * Atom Activate Hook
     */
    activate ( state ) {
        if (this.active) return;
        this.active = true;
        /**
         * Setup Plugin
         */
        this.emit('Setup');
    }

    /**
     * Atom Deactivate Hook
     */
    deactivate () {
        if (!this.active) return;
        this.active = false;
        /**
         * Teardown Plugin
         */
        this.emit('Teardown');
    }

    /**
     * Bind State Machine Event
     * @param {String} event
     * @param {Function} handler
     */
    on ( event, handler ) {
        this.fsm[`on${ event }`] = function ( name, from, to, payload ) {
            let event = { name, from, to };
            return handler.call(this, event, payload);
        };
    }

    /**
     * Emit State Machine Event
     * @param {String} event
     * @param {Any} payload
     */
    emit ( event, payload ) {
        if (this.fsm.can(event)) {
            this.fsm[event](payload);
        }
    }

    /**
     * Add Atom Command
     * @param {String} command
     * @param {Function} handler
     */
    add ( command, handler ) {
        console.log(`add => ${ command }`);
        this.dispose(
            command,
            atom.commands.add(
                'atom-workspace',
                {
                    [command] : handler,
                },
            ),
        );
    }

    /**
     * Remove Atom Command
     * @param {String} command
     */
     remove ( ...commands ) {
         for (let command of commands) {
             console.log(`remove => ${ command }`);
             this.dispose(command);
         }
     }

     /**
      * Add or Remove Atom Command
      * @param {String} command
      * @param {Function} handler
      */
     dispose ( command, handler ) {
         let composition = this.commands[command];
         if (composition) {
             composition.dispose();
             if (handler) {
                 this.commands[command] = handler;
             }
         }
     }

}

export default new TreeViewSearchBar;
<commit_msg>update<commit_after>'use babel';

import { Vue } from 'use-vue';
import { requirePackages } from 'atom-utils';
import StateMachine from 'javascript-state-machine';

import './module/use-vue-config';

import {
    DEV,
    NAME,
} from './module/constant';

import console from './module/console';

let { autoToggle } = !!atom.config.get(`${ NAME.kebab }`);
console.log('autoToggle => ', autoToggle);

let addInfo = ( detail ) => atom.notifications.addInfo(`${ NAME }`, { detail });
let showTips = () => addInfo(`Plugin require "tree-view".`);

Vue.prototype.$dispatch = function ( event, payload ) {
    return new Promise(( resolve ) => {
        this.$emit(`${ event }`, resolve, payload);
    });
};

class TreeViewSearchBar {

    /**
     * Plugin Active State
     * @type {Boolean}
     */
    active = false;

    /**
     * Plugin Commands Collection
     * @type {Object}
     */
    commands = {};

    /**
     * Define Finite State Machine Model
     * @type {StateMachine}
     * @type {String} Status | "Null" | "Dependent" | "Created" | "Actived" | "Disabled" | "Destroyed" |
     * @type {String} Event | "Setup" | "Create" | "Activate" | "Deactivate" | "Destroy" | "Teardown" |
     */
    fsm = StateMachine.create({
        initial : 'Null',
        error : null,
        events : [
            {
                from : 'Null',
                name : 'Setup',
                to : 'Dependent',
            },
            {
                from : 'Dependent',
                name : 'Create',
                to : 'Created',
            },
            {
                from : ['Created', 'Disabled'],
                name : 'Activate',
                to : 'Actived',
            },
            {
                from : 'Actived',
                name : 'Deactivate',
                to : 'Disabled',
            },
            {
                from : ['Disabled', 'Actived', 'Created', 'Dependent'],
                name : 'Destroy',
                to : 'Destroyed',
            },
            {
                from : 'Destroyed',
                name : 'Teardown',
                to : 'Null',
            },
        ],
    });

    constructor () {

        if (DEV) {
            window.test = this;
            this.Vue = Vue;
        }

        /**
         * Setup Stage
         */
        this.on('Setup', async () => {
            console.log('event => Setup');
            let [{ treeView }] = await requirePackages('tree-view');
            Vue.prototype.$treeView = treeView;

            if (treeView && treeView.isVisible()) {
                this.emit('Create');
            } else {
                showTips();
                this.add('search-bar:toggle', showTips);
                let ensureTreeViewVisible = () => {
                    console.log('ensureTreeViewVisible');
                    process.nextTick(() => {
                        if (treeView && treeView.isVisible() && atom.project.rootDirectories.length) {
                            this.emit('Create');
                        }
                    });
                };
                this.add('tree-view:show', ensureTreeViewVisible);
                this.add('tree-view:toggle', ensureTreeViewVisible);
                let projectListener = atom.project.onDidChangePaths(ensureTreeViewVisible);
                this.on('leaveDependent', () => {
                    console.log('event => leaveDependent');
                    this.remove(
                        'tree-view:show',
                        'tree-view:toggle',
                        'search-bar:toggle',
                    );
                    projectListener.disposalAction();
                });
            }
        });

        /**
         * Create Stage
         */
        this.on('Create', async () => {
            console.log('event => Create');
            let treeView = Vue.prototype.$treeView;

            atom.notifications.addSuccess(`${ NAME }`, {
                detail : 'Plugin is running!',
            });

            /**
             * Vue instance
             * @type {Vue|null}
             */
            let vm = null;
            if (DEV) {
                Object.defineProperty(this, 'vm', {
                    get () {
                        return vm;
                    },
                });
            }

            /**
             * Plugin Placeholder
             * @type {Element}
             */
            let element = document.createElement('div');

            /**
             * Activate Stage
             */
            this.on('Activate', async () => {
                console.log('Activate');
                if (vm) {
                    await vm.$dispatch('show');
                } else {
                    if (DEV) {
                        let path = require('path');
                        let files = [
                            './views/app.vue',
                        ];
                        let Module = module.constructor;
                        for (let file of files) {
                            Module._cache[path.join(__dirname, file)] = null;
                        }
                    }
                    let app = require('./views/app.vue');
                    vm = new Vue(app);
                    treeView.element.parentNode.insertBefore(element, treeView.element);
                    vm.$mount(element);
                }
                console.log('app => show');
            });

            /**
             * Destroy Vue instance
             * @type {Function}
             */
            let clean = async () => {
                if (vm) {
                    await vm.$dispatch('hide');
                    vm = null;
                }
                console.log('app => hide');
            };

            /**
             * Deactivate Stage
             */
            this.on('Deactivate', () => {
                console.log('Deactivate');
                clean();
            });

            /**
             * Destroy Stage
             */
            this.on('Destroy', () => {
                console.log('Destroy');
                // clean();
            });

            /**
             * ensure Tree View visible
             * @param {Function} callback
             * @return {Function} handler
             */
            let requireTreeView = ( callback ) => {
                return () => {
                    if (treeView.isVisible()) {
                        callback();
                    } else {
                        showTips();
                    }
                };
            };

            this.add('search-bar:show', requireTreeView(() => {
                this.emit('Activate');
            }));
            this.add('search-bar:hide', requireTreeView(() => {
                this.emit('Deactivate');
            }));
            this.add('search-bar:focus', requireTreeView(() => {
                this.emit('Activate');
                vm.$emit('focus');
            }));
            this.add('search-bar:toggle', requireTreeView(() => {
                let current = this.fsm.current;
                this.emit('Activate');
                if (current === this.fsm.current) {
                    this.emit('Deactivate');
                }
            }));

            /**
             * autoToggle
             */
            if (autoToggle) {
                this.emit('Activate');
            }

        });

        /**
         * Teardown Stage
         */
        this.on('Teardown', () => {
            console.log('event => Teardown');
            this.remove(
                'tree-view:show',
                'tree-view:toggle',
                'search-bar:show',
                'search-bar:hide',
                'search-bar:focus',
                'search-bar:toggle',
            );
        });

    }

    /**
     * Plugin Active State
     * @return {Boolean} active
     */
    isActive () {
        return this.active;
    }

    /**
     * Atom Activate Hook
     */
    activate ( state ) {
        if (this.active) return;
        this.active = true;
        /**
         * Setup Plugin
         */
        this.emit('Setup');
    }

    /**
     * Atom Deactivate Hook
     */
    deactivate () {
        if (!this.active) return;
        this.active = false;
        /**
         * Teardown Plugin
         */
        this.emit('Teardown');
    }

    /**
     * Bind State Machine Event
     * @param {String} event
     * @param {Function} handler
     */
    on ( event, handler ) {
        this.fsm[`on${ event }`] = function ( name, from, to, payload ) {
            let event = { name, from, to };
            return handler.call(this, event, payload);
        };
    }

    /**
     * Emit State Machine Event
     * @param {String} event
     * @param {Any} payload
     */
    emit ( event, payload ) {
        if (this.fsm.can(event)) {
            this.fsm[event](payload);
        }
    }

    /**
     * Add Atom Command
     * @param {String} command
     * @param {Function} handler
     */
    add ( command, handler ) {
        console.log(`add => ${ command }`);
        this.dispose(
            command,
            atom.commands.add(
                'atom-workspace',
                {
                    [command] : handler,
                },
            ),
        );
    }

    /**
     * Remove Atom Command
     * @param {String} command
     */
     remove ( ...commands ) {
         for (let command of commands) {
             console.log(`remove => ${ command }`);
             this.dispose(command);
         }
     }

     /**
      * Add or Remove Atom Command
      * @param {String} command
      * @param {Function} handler
      */
     dispose ( command, handler ) {
         let composition = this.commands[command];
         if (composition) {
             composition.dispose();
             if (handler) {
                 this.commands[command] = handler;
             }
         }
     }

}

export default new TreeViewSearchBar;
<|endoftext|>


<commit_before>// -*- coding: utf-8-unix -*-
enchant();

var Pane = enchant.Class.create(Group, {
    initialize: function(width, height){
        EventTarget.call(this); // これがないと boardLayout.addChild(lanePane) に失敗する。
        Group.call(this);
        this.width = width;
        this.height = height;
        sprite = new Sprite(this.width, this.height);
        surface = new Surface(this.width, this.height);
        sprite.image = surface;
        context = surface.context;
        context.beginPath();
        context.moveTo(0, 0);
        context.lineTo(this.width, 0);
        context.lineTo(this.width, this.height);
        context.lineTo(0, this.height);
        context.lineTo(0, 0);
        context.closePath();
        context.stroke();
        this.addChild(sprite);
    }
});

var LanePane = enchant.Class.create(Pane, {
    initialize: function(width, height, slotSize){
        Pane.call(this, width, height);
        this.slotSize = slotSize;
        sprite = new Sprite(this.width, this.height);
        surface = new Surface(this.width, this.height);
        sprite.image = surface;
        context = surface.context;
        for(var slotCount = 0; slotCount < slotSize; slotCount++){
            context.beginPath();
            var x = this.width / slotSize * slotCount;
            context.moveTo(x, 0);
            context.lineTo(x, this.height);
            context.closePath();
            context.stroke();
        }
        this.addChild(sprite);
    }
});

var BoxLayout = enchant.Class.create(Group, {
    initialize: function(parentGroup){
        this.parentGroup = parentGroup;
        this.child_x = 0;
        this.child_y = 0;
    },
    addChild: function(childNode){
        this.parentGroup.addChild(childNode);
        childNode.x = this.child_x;
        childNode.y = this.child_y;
        this.child_y += childNode.height;
    }
});

var HandPane = enchant.Class.create(LanePane, {
    initialize: function(width, height, slotSize, player){
        LanePane.call(this, width, height, slotSize);
        this.player = player;
        this.addEventListener(Event.ENTER_FRAME, function() {
            this.paint();
        });
    },
    paint: function() {
        var card_array = this.player.card_array;
    }
});

var PlayerModel = enchant.Class.create({
    initialize: function(){
        this.card_array = [];
        for(var i = 0; i < 10; i++){
            this.card_array.push(new CardModel(i));
        }
    }
});

var CardModel = enchant.Class.create({
    initialize: function(number){
        this.number = number;
    }
});

window.onload = function(){
    var game_x = 640;
    var game_y = 960;
    var game = new Game(game_x, game_y);

    var card_width = 64;
    var card_height = 160;

    /**
     * タイトルシーンを作り、返す関数
     */
    var createTitleScene = function() {
        var scene = new Scene();                // 新しいシーンを作る

        var label = new Label('touch to start game');
        label.x = game_x / 2;
        label.y = game_y / 2;
        scene.addChild(label);

        var north = new Label('North');
        north.x = game_x / 2;
        north.y = 0;
        scene.addChild(north);

        var south = new Label('South');
        south.x = game_x / 2;
        south.y = game_y - 15;
        scene.addChild(south);

        var east = new Label('East');
        east.x = game_x - 36;
        east.y = game_y / 2;
        scene.addChild(east);

        var west = new Label('West');
        west.x = 0;
        west.y = game_y / 2;
        scene.addChild(west);

        scene.backgroundColor = 'rgba(255, 230, 0, 1)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンをゲームシーンに置き換えます
            game.replaceScene(createGameScene());
        });
        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    /**
     * ゲームシーンを作り、返す関数
     */
    var createGameScene = function() {
        var scene = new Scene();                // 新しいシーンを作る
        scene.backgroundColor = 'rgba(255, 200, 0, 1)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンの上にゲームオーバーシーンを重ねて表示します
            game.pushScene(createGameoverScene());
        });
        var sceneLayout = new BoxLayout(scene);
        var boardPane = createBoardPane(sceneLayout);
        var handPane = createHandPane(sceneLayout);
        var scorePane = new Pane(card_width * 10, card_height);
        scorePane.addChild(new Label("scorePane"));
        sceneLayout.addChild(scorePane);

        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    function createBoardPane(sceneLayout) {
        var boardPane = new Pane(card_width * 5, card_height * 4);
        boardPane.addChild(new Label("boardPane"));
        sceneLayout.addChild(boardPane);
        var boardLayout = new BoxLayout(boardPane);
        var lanePaneArray = [
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5)
        ];
        for(var i = 0; i < lanePaneArray.length; i++){
            boardLayout.addChild(lanePaneArray[i]);
        }
        return boardPane;
    }

    function createHandPane(sceneLayout) {
        var player = new PlayerModel();
        var handPane = new HandPane(card_width * 10, card_height, 10, player);
        handPane.addChild(new Label("handPane"));
        sceneLayout.addChild(handPane);
        return handPane;
    }

    /**
     * ゲームオーバーシーンを作り、返す関数
     */
    var createGameoverScene = function() {
        var scene = new Scene();                // 新しいシーンを作る
        var label = new Label('touch to start game');
        label.x = scene.width / 3;                            // 横位置調整
        label.y = scene.height / 2;                           // 縦位置調整
        scene.addChild(label);                  // シーンにラベルに追加
        scene.backgroundColor = 'rgba(0, 0, 255, 0.5)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンを外し、直前のシーンを表示します
            game.popScene();
        });
        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    // ゲームの_rootSceneをタイトルシーンに置き換えます
    game.replaceScene(createTitleScene());

    game.start();
}
<commit_msg>little<commit_after>// -*- coding: utf-8-unix -*-
enchant();

var Pane = enchant.Class.create(Group, {
    initialize: function(width, height){
        EventTarget.call(this); // これがないと boardLayout.addChild(lanePane) に失敗する。
        Group.call(this);
        this.width = width;
        this.height = height;
        sprite = new Sprite(this.width, this.height);
        surface = new Surface(this.width, this.height);
        sprite.image = surface;
        context = surface.context;
        context.beginPath();
        context.moveTo(0, 0);
        context.lineTo(this.width, 0);
        context.lineTo(this.width, this.height);
        context.lineTo(0, this.height);
        context.lineTo(0, 0);
        context.closePath();
        context.stroke();
        this.addChild(sprite);
    }
});

var LanePane = enchant.Class.create(Pane, {
    initialize: function(width, height, slotSize){
        Pane.call(this, width, height);
        this.slotSize = slotSize;
        sprite = new Sprite(this.width, this.height);
        surface = new Surface(this.width, this.height);
        sprite.image = surface;
        context = surface.context;
        for(var slotCount = 0; slotCount < slotSize; slotCount++){
            context.beginPath();
            var x = this.width / slotSize * slotCount;
            context.moveTo(x, 0);
            context.lineTo(x, this.height);
            context.closePath();
            context.stroke();
        }
        this.addChild(sprite);
    }
});

var BoxLayout = enchant.Class.create(Group, {
    initialize: function(parentGroup){
        this.parentGroup = parentGroup;
        this.child_x = 0;
        this.child_y = 0;
    },
    addChild: function(childNode){
        this.parentGroup.addChild(childNode);
        childNode.x = this.child_x;
        childNode.y = this.child_y;
        this.child_y += childNode.height;
    }
});

var HandPane = enchant.Class.create(LanePane, {
    initialize: function(width, height, slotSize, player){
        LanePane.call(this, width, height, slotSize);
        this.player = player;
        this.addEventListener(Event.ENTER_FRAME, function() {
            this.paint();
        });
    },
    paint: function() {
        var card_array = this.player.card_array;
    }
});

var PlayerModel = enchant.Class.create({
    initialize: function(){
        this.card_array = [];
        for(var i = 0; i < 10; i++){
            this.card_array.push(new CardModel(i));
        }
    }
});

var CardModel = enchant.Class.create({
    initialize: function(number){
        this.number = number;
    }
});

window.onload = function(){
    var game_x = 640;
    var game_y = 960;
    var game = new Game(game_x, game_y);

    var card_width = 64;
    var card_height = 160;

    /**
     * タイトルシーンを作り、返す関数
     */
    var createTitleScene = function() {
        var scene = new Scene();                // 新しいシーンを作る

        var label = new Label('touch to start game');
        label.x = game_x / 2;
        label.y = game_y / 2;
        scene.addChild(label);

        var north = new Label('North');
        north.x = game_x / 2;
        north.y = 0;
        scene.addChild(north);

        var south = new Label('South');
        south.x = game_x / 2;
        south.y = game_y - 15;
        scene.addChild(south);

        var east = new Label('East');
        east.x = game_x - 36;
        east.y = game_y / 2;
        scene.addChild(east);

        var west = new Label('West');
        west.x = 0;
        west.y = game_y / 2;
        scene.addChild(west);

        scene.backgroundColor = 'rgba(255, 230, 0, 1)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンをゲームシーンに置き換えます
            game.replaceScene(createGameScene());
        });
        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    /**
     * ゲームシーンを作り、返す関数
     */
    var createGameScene = function() {
        var scene = new Scene();                // 新しいシーンを作る
        scene.backgroundColor = 'rgba(255, 200, 0, 1)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンの上にゲームオーバーシーンを重ねて表示します
            game.pushScene(createGameoverScene());
        });
        var sceneLayout = new BoxLayout(scene);
        var boardPane = createBoardPane(sceneLayout);
        var handPane = createHandPane(sceneLayout);
        var scorePane = new Pane(card_width * 10, card_height);
        scorePane.addChild(new Label("scorePane"));
        sceneLayout.addChild(scorePane);

        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    function createBoardPane(sceneLayout) {
        var boardPane = new Pane(card_width * 5, card_height * 4);
        boardPane.addChild(new Label("boardPane"));
        sceneLayout.addChild(boardPane);
        var boardLayout = new BoxLayout(boardPane);
        var lanePaneArray = [
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5),
            new LanePane(boardPane.width, boardPane.height / 4, 5)
        ];
        for(var i = 0; i < lanePaneArray.length; i++){
            boardLayout.addChild(lanePaneArray[i]);
        }
        return boardPane;
    }

    function createHandPane(sceneLayout) {
        var playerModel = new PlayerModel();
        var handPane = new HandPane(card_width * 10, card_height, 10, playerModel);
        handPane.addChild(new Label("handPane"));
        sceneLayout.addChild(handPane);
        return handPane;
    }

    /**
     * ゲームオーバーシーンを作り、返す関数
     */
    var createGameoverScene = function() {
        var scene = new Scene();                // 新しいシーンを作る
        var label = new Label('touch to start game');
        label.x = scene.width / 3;                            // 横位置調整
        label.y = scene.height / 2;                           // 縦位置調整
        scene.addChild(label);                  // シーンにラベルに追加
        scene.backgroundColor = 'rgba(0, 0, 255, 0.5)';      // シーンの背景色を設定
        scene.addEventListener(Event.TOUCH_END, function(e) { // シーンにタッチイベントを設定
            //現在表示しているシーンを外し、直前のシーンを表示します
            game.popScene();
        });
        // この関数内で作ったシーンを呼び出し元に返します(return)
        return scene;
    };

    // ゲームの_rootSceneをタイトルシーンに置き換えます
    game.replaceScene(createTitleScene());

    game.start();
}

<|endoftext|>


<commit_before>/**
 *
 * @licstart  The following is the entire license notice for the JavaScript code in this file.
 *
 * Plugin for loglevel which allows defining prefixes for log messages
 *
 * Copyright (c) 2015-2016 University Of Helsinki (The National Library Of Finland)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @licend  The above is the entire license notice
 * for the JavaScript code in this file.
 *
 **/

/* istanbul ignore next: umd wrapper */
(function (root, factory) {

  'use strict';

  if (typeof define === 'function' && define.amd) {
    define([
      'es6-polyfills/lib/polyfills/object',
      'loglevel',
      'jjv',
      'jjve',
      'json!../resources/parameters-schema.json'
    ], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory(
      require('es6-polyfills/lib/polyfills/object'),
      require('loglevel'),
      require('jjv'),
      require('jjve'),
      require('../resources/parameters-schema.json')
    );
  }

}(this, factory));

function factory(Object, log, jjv, jjve, schema)
{

  'use strict';

  return function(loglevel_obj, parameters, fn_original_factory)
  {

    function isCloneOf(obj, base)
    {
      return !Object.keys(base).some(function(key) {
        return !(obj.hasOwnProperty(key) && (typeof base[key] !== 'function' || typeof obj[key] === 'function'));
      });
    }

    function validateParameters()
    {

      var env = jjv();
      var je = jjve(env);
      var errors = env.validate(schema, parameters, {
        useDefault: true
      });

      if (errors) {
        throw new Error('Invalid configuration: ' + JSON.stringify(je(schema, parameters, errors), undefined, 4));
      }

    }

    function setPrefixesOptions()
    {

      timestamp_options.hour12 = parameters.options.timestamp.hour12;

      if (parameters.options.timestamp.hasOwnProperty('timezone')) {
        timestamp_options.timeZone = parameters.options.timestamp.timezone;
      }

      if (parameters.options.timestamp.hasOwnProperty('locale')) {
        timestamp_locale = [parameters.options.timestamp.locale];
      }

    }

    var timestamp_locale,
    timestamp_options = {};

    if (typeof loglevel_obj !== 'object' || !isCloneOf(loglevel_obj, log.getLogger('foo'))) {
      throw new Error('Argument is not a proper loglevel object');
    }

    fn_original_factory = typeof fn_original_factory === 'function' ? fn_original_factory : loglevel_obj.methodFactory;
    parameters = typeof parameters === 'object' ? parameters : {};

    validateParameters();
    setPrefixesOptions();

    loglevel_obj.methodFactory = function (method_name, log_level, logger_name)
    {

      var fn_method_raw = fn_original_factory(method_name, log_level, logger_name);

      return function(message) {

        var date = new Date();
        var prefix = parameters.prefixes.reduce(function(result, prefix_name) {

          result = result.length === 0 ? result : result + parameters.separator;

          switch (prefix_name) {
          case 'timestamp':

            /**
             * @todo date.prototype.toLocaleDateString & date.prototype.toLocaleTimeString seem to modify the options argument. Tests in browsers and report to Node.js / Browser developers
             */
            if (timestamp_locale === undefined) {
              return result + date.toLocaleDateString(JSON.parse(JSON.stringify(timestamp_options))) + ' ' + date.toLocaleTimeString(JSON.parse(JSON.stringify(timestamp_options)));
            } else {
              return result + date.toLocaleDateString(timestamp_locale, JSON.parse(JSON.stringify(timestamp_options))) + ' ' + date.toLocaleTimeString(timestamp_locale, JSON.parse(JSON.stringify(timestamp_options)));
            }

            break;

          case 'level':
            return result + method_name.toUpperCase();
          }

        }, '');

        if (parameters.staticPrefixes.length > 0) {
          prefix = parameters.staticPrefixes.reduce(function(result, prefix_static) {

            result = result.length === 0 ? result : result + parameters.separator;

            return result + prefix_static;

          }, prefix);
        } else {
          prefix = prefix.substr(0, prefix.length);
        }

        message = typeof message === 'object' ? JSON.stringify(message) :  message;
        fn_method_raw('[' + prefix + ']: ' + message);

      };

    };

    loglevel_obj.setLevel(loglevel_obj.getLevel());

    return loglevel_obj;

  };

}
<commit_msg>Remove superfluous prefix variable assignment. Fixes #8.<commit_after>/**
 *
 * @licstart  The following is the entire license notice for the JavaScript code in this file.
 *
 * Plugin for loglevel which allows defining prefixes for log messages
 *
 * Copyright (c) 2015-2016 University Of Helsinki (The National Library Of Finland)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @licend  The above is the entire license notice
 * for the JavaScript code in this file.
 *
 **/

/* istanbul ignore next: umd wrapper */
(function (root, factory) {

  'use strict';

  if (typeof define === 'function' && define.amd) {
    define([
      'es6-polyfills/lib/polyfills/object',
      'loglevel',
      'jjv',
      'jjve',
      'json!../resources/parameters-schema.json'
    ], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory(
      require('es6-polyfills/lib/polyfills/object'),
      require('loglevel'),
      require('jjv'),
      require('jjve'),
      require('../resources/parameters-schema.json')
    );
  }

}(this, factory));

function factory(Object, log, jjv, jjve, schema)
{

  'use strict';

  return function(loglevel_obj, parameters, fn_original_factory)
  {

    function isCloneOf(obj, base)
    {
      return !Object.keys(base).some(function(key) {
        return !(obj.hasOwnProperty(key) && (typeof base[key] !== 'function' || typeof obj[key] === 'function'));
      });
    }

    function validateParameters()
    {

      var env = jjv();
      var je = jjve(env);
      var errors = env.validate(schema, parameters, {
        useDefault: true
      });

      if (errors) {
        throw new Error('Invalid configuration: ' + JSON.stringify(je(schema, parameters, errors), undefined, 4));
      }

    }

    function setPrefixesOptions()
    {

      timestamp_options.hour12 = parameters.options.timestamp.hour12;

      if (parameters.options.timestamp.hasOwnProperty('timezone')) {
        timestamp_options.timeZone = parameters.options.timestamp.timezone;
      }

      if (parameters.options.timestamp.hasOwnProperty('locale')) {
        timestamp_locale = [parameters.options.timestamp.locale];
      }

    }

    var timestamp_locale,
    timestamp_options = {};

    if (typeof loglevel_obj !== 'object' || !isCloneOf(loglevel_obj, log.getLogger('foo'))) {
      throw new Error('Argument is not a proper loglevel object');
    }

    fn_original_factory = typeof fn_original_factory === 'function' ? fn_original_factory : loglevel_obj.methodFactory;
    parameters = typeof parameters === 'object' ? parameters : {};

    validateParameters();
    setPrefixesOptions();

    loglevel_obj.methodFactory = function (method_name, log_level, logger_name)
    {

      var fn_method_raw = fn_original_factory(method_name, log_level, logger_name);

      return function(message) {

        var date = new Date();
        var prefix = parameters.prefixes.reduce(function(result, prefix_name) {

          result = result.length === 0 ? result : result + parameters.separator;

          switch (prefix_name) {
          case 'timestamp':

            /**
             * @todo date.prototype.toLocaleDateString & date.prototype.toLocaleTimeString seem to modify the options argument. Tests in browsers and report to Node.js / Browser developers
             */
            if (timestamp_locale === undefined) {
              return result + date.toLocaleDateString(JSON.parse(JSON.stringify(timestamp_options))) + ' ' + date.toLocaleTimeString(JSON.parse(JSON.stringify(timestamp_options)));
            } else {
              return result + date.toLocaleDateString(timestamp_locale, JSON.parse(JSON.stringify(timestamp_options))) + ' ' + date.toLocaleTimeString(timestamp_locale, JSON.parse(JSON.stringify(timestamp_options)));
            }

            break;

          case 'level':
            return result + method_name.toUpperCase();
          }

        }, '');

        if (parameters.staticPrefixes.length > 0) {
          prefix = parameters.staticPrefixes.reduce(function(result, prefix_static) {

            result = result.length === 0 ? result : result + parameters.separator;

            return result + prefix_static;

          }, prefix);
        }

        message = typeof message === 'object' ? JSON.stringify(message) :  message;
        fn_method_raw('[' + prefix + ']: ' + message);

      };

    };

    loglevel_obj.setLevel(loglevel_obj.getLevel());

    return loglevel_obj;

  };

}
<|endoftext|>