<commit_before>/**

Donations welcome:
	BTC: 122MeuyZpYz4GSHNrF98e6dnQCXZfHJeGS
	LTC: LY1L6M6yG26b4sRkLv4BbkmHhPn8GR5fFm
		~ Thank you!

------------

MIT License (MIT)

Copyright (c) 2013 http://coinwidget.com/
Copyright (c) 2013 http://scotty.cc/

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.

*/

if (typeof CoinWidgetComCounter != 'number')
var CoinWidgetComCounter = 0;

if (typeof CoinWidgetCom != 'object')
var CoinWidgetCom = {
	source: 'http://coinwidget.com/widget/'
	, config: []
	, go :function(config) {
		config = CoinWidgetCom.validate(config);
		CoinWidgetCom.config[CoinWidgetComCounter] = config;
		CoinWidgetCom.loader.jquery();
		document.write('');
		CoinWidgetComCounter++;
	}
	, validate: function(config) {
		var $accepted = [];
		$accepted['currencies'] = ['bitcoin','litecoin'];
		$accepted['counters'] = ['count','amount','hide'];
		$accepted['alignment'] = ['al','ac','ar','bl','bc','br'];
		if (!config.currency || !CoinWidgetCom.in_array(config.currency,$accepted['currencies']))
			config.currency = 'bitcoin';
		if (!config.counter || !CoinWidgetCom.in_array(config.counter,$accepted['counters']))
			config.counter = 'count';
		if (!config.alignment || !CoinWidgetCom.in_array(config.alignment,$accepted['alignment']))
			config.alignment = 'bl';
		if (typeof config.qrcode != 'boolean')
			config.qrcode = true;
		if (typeof config.auto_show != 'boolean')
			config.auto_show = false;
		if (!config.wallet_address)
			config.wallet_address = 'My '+ config.currency +' wallet_address is missing!';
		if (!config.lbl_button)
			config.lbl_button = 'Donate';
		if (!config.lbl_address)
			config.lbl_address = 'My Bitcoin Address:';
		if (!config.lbl_count)
			config.lbl_count = 'Donation';
		if (!config.lbl_amount)
			config.lbl_amount = 'BTC';
		if (typeof config.decimals != 'number' || config.decimals < 0 || config.decimals > 10)
			config.decimals = 4;

		return config;
	}
	, init: function(){
		CoinWidgetCom.loader.stylesheet();
		$(window).resize(function(){
			CoinWidgetCom.window_resize();
		});
		setTimeout(function(){
			/* this delayed start gives the page enough time to
			   render multiple widgets before pinging for counts.
			*/
			CoinWidgetCom.build();
		},800);
	}
	, build: function(){
		$containers = $("span[data-coinwidget-instance]");
		$containers.each(function(i,v){
			$config = CoinWidgetCom.config[$(this).attr('data-coinwidget-instance')];
			$counter = $config.counter == 'hide'?'':('');
			$button = ''+$config.lbl_button+''+$counter;
			$(this).html($button);
			$(this).find('> a').unbind('click').click(function(e){
				e.preventDefault();
				CoinWidgetCom.show(this);
			});
		});
		CoinWidgetCom.counters();
	}
	, window_resize: function(){
		$.each(CoinWidgetCom.config,function(i,v){
			CoinWidgetCom.window_position(i);
		});
	}
	, window_position: function($instance){
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;

			obj = "span[data-coinwidget-instance='"+$instance+"'] > a";
			/* 	to make alignment relative to the full width of the container instead
			of just the button change this occurence of $(obj) to $(obj).parent(),
			do the same for the occurences within the switch statement. */
			$pos = $(obj).offset();
			switch ($config.alignment) {
				default:
				case 'al': /* above left */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left;
					break;
				case 'ac': /* above center */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left + ($(obj).outerWidth()/2) - ($(coin_window).outerWidth()/2);
					break;
				case 'ar': /* above right */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left + $(obj).outerWidth() - $(coin_window).outerWidth();
					break;
				case 'bl': /* bottom left */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left;
					break;
				case 'bc': /* bottom center */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left + ($(obj).outerWidth()/2) - ($(coin_window).outerWidth()/2);
					break;
				case 'br': /* bottom right */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left + $(obj).outerWidth() - $(coin_window).outerWidth();
					break;
			}
		if ($(coin_window).is(':visible')) {
			$(coin_window).stop().animate({'z-index':99999999999,'top':$top,'left':$left},150);
		} else {
			$(coin_window).stop().css({'z-index':99999999998,'top':$top,'left':$left});
		}
	}
	, counter: []
	, counters: function(){
		$addresses = [];
		$.each(CoinWidgetCom.config,function(i,v){
			$instance = i;
			$config = v;
			if ($config.counter != 'hide')
				$addresses.push($instance+'_'+$config.currency+'_'+$config.wallet_address);
			else {
				if ($config.auto_show)
					$("span[data-coinwidget-instance='"+i+"']").find('> a').click();
			}
		});
		if ($addresses.length) {
			CoinWidgetCom.loader.script({
				id: 'COINWIDGETCOM_INFO'+Math.random()
				, source: (CoinWidgetCom.source+'lookup.php?data='+$addresses.join('|'))
				, callback: function(){
					if (typeof COINWIDGETCOM_DATA == 'object') {
						CoinWidgetCom.counter = COINWIDGETCOM_DATA;
						$.each(CoinWidgetCom.counter,function(i,v){
							$config = CoinWidgetCom.config[i];
							if (!v.count || v == null) v = {count:0,amount:0};
							$("span[data-coinwidget-instance='"+i+"']").find('> span').html($config.counter=='count'?v.count:(v.amount.toFixed($config.decimals)+' '+$config.lbl_amount));
							if ($config.auto_show) {
								$("span[data-coinwidget-instance='"+i+"']").find('> a').click();
							}
						});
					}
					if ($("span[data-coinwidget-instance] > span img").length > 0) {
						setTimeout(function(){CoinWidgetCom.counters();},2500);
					}
				}
			});
		}
	}
	, show: function(obj) {
		$instance = $(obj).parent().attr('data-coinwidget-instance');
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;
		$(".COINWIDGETCOM_WINDOW").css({'z-index':99999999998});
		if (!$(coin_window).length) {

			$sel = !navigator.userAgent.match(/iPhone/i)?'onclick="this.select();"':'onclick="prompt(\'Select all and copy:\',\''+$config.wallet_address+'\');"';

			$html = ''
				  + ''+$config.lbl_address+''
				  + '<input type="text" readonly '+$sel+'  value="'+$config.wallet_address+'" />'
				  + 'CoinWidget.com'
  				  + ''
  				  + 'x'
  				  + ''
				  ;
			if ($config.counter != 'hide') {
				$html += '0'+$config.lbl_count+''
				  	  + '0.00'+$config.lbl_amount+''
				  	  ;
			}
			if ($config.qrcode) {
				$html += ''
				  	   + ''
				  	   ;
			}
			var $div = $('

');
			$('body').append($div);
			$div.attr({
				'id': 'COINWIDGETCOM_WINDOW_'+$instance
			}).addClass('COINWIDGETCOM_WINDOW COINWIDGETCOM_WINDOW_'+$config.currency.toUpperCase()+' COINWIDGETCOM_WINDOW_'+$config.alignment.toUpperCase()).html($html).unbind('click').bind('click',function(){
				$(".COINWIDGETCOM_WINDOW").css({'z-index':99999999998});
				$(this).css({'z-index':99999999999});
			});
			if ($config.qrcode) {
				$(coin_window).find('.COINWIDGETCOM_QRCODE').bind('mouseenter click',function(){
					$config = CoinWidgetCom.config[$(this).attr('data-coinwidget-instance')];
					$lrg = $(this).parent().find('.COINWIDGETCOM_QRCODE_LARGE');
					if ($lrg.is(':visible')) {
						$lrg.hide();
						return;
					}
					$lrg.attr({
						src: CoinWidgetCom.source +'qr/?address='+$config.wallet_address
					}).show();
				}).bind('mouseleave',function(){
					$lrg = $(this).parent().find('.COINWIDGETCOM_QRCODE_LARGE');
					$lrg.hide();
				});
			}
		} else {
			if ($(coin_window).is(':visible')) {
				CoinWidgetCom.hide($instance);
				return;
			}
		}
		CoinWidgetCom.window_position($instance);
		$(coin_window).show();
		$pos = $(coin_window).find('input').position();
		$(coin_window).find('img.COINWIDGET_INPUT_ICON').css({'top':$pos.top+3,'left':$pos.left+3});
		$(coin_window).find('.COINWIDGETCOM_WALLETURI').css({'top':$pos.top+3,'left':$pos.left+$(coin_window).find('input').outerWidth()+3});
		if ($config.counter != 'hide') {
			$counters = CoinWidgetCom.counter[$instance];
			if ($counters == null) {
				$counters = {
					count: 0,
					amount: 0
				};
			}
		 	if ($counters.count == null) $counters.count = 0;
		 	if ($counters.amount == null) $counters.amount = 0;
			$(coin_window).find('.COINWIDGETCOM_COUNT').html($counters.count+ ''+$config.lbl_count+'');
			$(coin_window).find('.COINWIDGETCOM_AMOUNT').html($counters.amount.toFixed($config.decimals)+ ''+$config.lbl_amount+'');
		}
		if (typeof $config.onShow == 'function')
			$config.onShow();
	}
	, hide: function($instance) {
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;
		$(coin_window).fadeOut();
		if (typeof $config.onHide == 'function') {
			$config.onHide();
		}
	}
	, in_array: function(needle,haystack) {
		for (i=0;i<haystack.length;i++) {
			if (haystack[i] == needle) {
				return true;
			}
		}
		return false;
	}
	, loader: {
		loading_jquery: false,
		script: function(obj){
			if (!document.getElementById(obj.id)) {
				var x = document.createElement('script');
				x.onreadystatechange = function(){
					switch (this.readyState) {
						case 'complete':
						case 'loaded':
							obj.callback();
							break;
					}
				};
				x.onload = function(){
					obj.callback();
				};
				x.src = obj.source;
				x.id  = obj.id;
				document.lastChild.firstChild.appendChild(x);
			}
		}
		, stylesheet_loaded: false
		, stylesheet: function(){
			if (!CoinWidgetCom.loader.stylesheet_loaded) {
				CoinWidgetCom.loader.stylesheet_loaded = true;
				var $link = $('<link/>');
				$("head").append($link);
				$link.attr({
					id 		: 'COINWIDGETCOM_STYLESHEET'
					, rel 	: 'stylesheet'
					, type 	: 'text/css'
					, href 	: CoinWidgetCom.source+'coin.css'
				});
			}
		}
		, jquery: function(){
			if (!window.jQuery && !CoinWidgetCom.loader.loading_jquery) {
				$prefix = window.location.protocol=='file:'?'http:':'';
				CoinWidgetCom.loader.script({
					id			: 'COINWIDGETCOM_JQUERY'
					, source 	: $prefix + '//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'
					, callback  : function(){
						CoinWidgetCom.init();
					}
				});
				return;
			}
			CoinWidgetCom.init();
		}
	}
};<commit_msg>Host coinwidget<commit_after>/**

Donations welcome:
	BTC: 122MeuyZpYz4GSHNrF98e6dnQCXZfHJeGS
	LTC: LY1L6M6yG26b4sRkLv4BbkmHhPn8GR5fFm
		~ Thank you!

------------

MIT License (MIT)

Copyright (c) 2013 http://coinwidget.com/
Copyright (c) 2013 http://scotty.cc/

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.

*/

if (typeof CoinWidgetComCounter != 'number')
var CoinWidgetComCounter = 0;

if (typeof CoinWidgetCom != 'object')
var CoinWidgetCom = {
	source: 'https://www.openkeychain.org/coinwidget/'
	, config: []
	, go :function(config) {
		config = CoinWidgetCom.validate(config);
		CoinWidgetCom.config[CoinWidgetComCounter] = config;
		CoinWidgetCom.loader.jquery();
		document.write('');
		CoinWidgetComCounter++;
	}
	, validate: function(config) {
		var $accepted = [];
		$accepted['currencies'] = ['bitcoin','litecoin'];
		$accepted['counters'] = ['count','amount','hide'];
		$accepted['alignment'] = ['al','ac','ar','bl','bc','br'];
		if (!config.currency || !CoinWidgetCom.in_array(config.currency,$accepted['currencies']))
			config.currency = 'bitcoin';
		if (!config.counter || !CoinWidgetCom.in_array(config.counter,$accepted['counters']))
			config.counter = 'count';
		if (!config.alignment || !CoinWidgetCom.in_array(config.alignment,$accepted['alignment']))
			config.alignment = 'bl';
		if (typeof config.qrcode != 'boolean')
			config.qrcode = true;
		if (typeof config.auto_show != 'boolean')
			config.auto_show = false;
		if (!config.wallet_address)
			config.wallet_address = 'My '+ config.currency +' wallet_address is missing!';
		if (!config.lbl_button)
			config.lbl_button = 'Donate';
		if (!config.lbl_address)
			config.lbl_address = 'My Bitcoin Address:';
		if (!config.lbl_count)
			config.lbl_count = 'Donation';
		if (!config.lbl_amount)
			config.lbl_amount = 'BTC';
		if (typeof config.decimals != 'number' || config.decimals < 0 || config.decimals > 10)
			config.decimals = 4;

		return config;
	}
	, init: function(){
		CoinWidgetCom.loader.stylesheet();
		$(window).resize(function(){
			CoinWidgetCom.window_resize();
		});
		setTimeout(function(){
			/* this delayed start gives the page enough time to
			   render multiple widgets before pinging for counts.
			*/
			CoinWidgetCom.build();
		},800);
	}
	, build: function(){
		$containers = $("span[data-coinwidget-instance]");
		$containers.each(function(i,v){
			$config = CoinWidgetCom.config[$(this).attr('data-coinwidget-instance')];
			$counter = $config.counter == 'hide'?'':('');
			$button = ''+$config.lbl_button+''+$counter;
			$(this).html($button);
			$(this).find('> a').unbind('click').click(function(e){
				e.preventDefault();
				CoinWidgetCom.show(this);
			});
		});
		CoinWidgetCom.counters();
	}
	, window_resize: function(){
		$.each(CoinWidgetCom.config,function(i,v){
			CoinWidgetCom.window_position(i);
		});
	}
	, window_position: function($instance){
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;

			obj = "span[data-coinwidget-instance='"+$instance+"'] > a";
			/* 	to make alignment relative to the full width of the container instead
			of just the button change this occurence of $(obj) to $(obj).parent(),
			do the same for the occurences within the switch statement. */
			$pos = $(obj).offset();
			switch ($config.alignment) {
				default:
				case 'al': /* above left */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left;
					break;
				case 'ac': /* above center */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left + ($(obj).outerWidth()/2) - ($(coin_window).outerWidth()/2);
					break;
				case 'ar': /* above right */
					$top = $pos.top - $(coin_window).outerHeight() - 10;
					$left = $pos.left + $(obj).outerWidth() - $(coin_window).outerWidth();
					break;
				case 'bl': /* bottom left */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left;
					break;
				case 'bc': /* bottom center */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left + ($(obj).outerWidth()/2) - ($(coin_window).outerWidth()/2);
					break;
				case 'br': /* bottom right */
					$top = $pos.top + $(obj).outerHeight() + 10;
					$left = $pos.left + $(obj).outerWidth() - $(coin_window).outerWidth();
					break;
			}
		if ($(coin_window).is(':visible')) {
			$(coin_window).stop().animate({'z-index':99999999999,'top':$top,'left':$left},150);
		} else {
			$(coin_window).stop().css({'z-index':99999999998,'top':$top,'left':$left});
		}
	}
	, counter: []
	, counters: function(){
		$addresses = [];
		$.each(CoinWidgetCom.config,function(i,v){
			$instance = i;
			$config = v;
			if ($config.counter != 'hide')
				$addresses.push($instance+'_'+$config.currency+'_'+$config.wallet_address);
			else {
				if ($config.auto_show)
					$("span[data-coinwidget-instance='"+i+"']").find('> a').click();
			}
		});
		if ($addresses.length) {
			CoinWidgetCom.loader.script({
				id: 'COINWIDGETCOM_INFO'+Math.random()
				, source: (CoinWidgetCom.source+'lookup.php?data='+$addresses.join('|'))
				, callback: function(){
					if (typeof COINWIDGETCOM_DATA == 'object') {
						CoinWidgetCom.counter = COINWIDGETCOM_DATA;
						$.each(CoinWidgetCom.counter,function(i,v){
							$config = CoinWidgetCom.config[i];
							if (!v.count || v == null) v = {count:0,amount:0};
							$("span[data-coinwidget-instance='"+i+"']").find('> span').html($config.counter=='count'?v.count:(v.amount.toFixed($config.decimals)+' '+$config.lbl_amount));
							if ($config.auto_show) {
								$("span[data-coinwidget-instance='"+i+"']").find('> a').click();
							}
						});
					}
					if ($("span[data-coinwidget-instance] > span img").length > 0) {
						setTimeout(function(){CoinWidgetCom.counters();},2500);
					}
				}
			});
		}
	}
	, show: function(obj) {
		$instance = $(obj).parent().attr('data-coinwidget-instance');
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;
		$(".COINWIDGETCOM_WINDOW").css({'z-index':99999999998});
		if (!$(coin_window).length) {

			$sel = !navigator.userAgent.match(/iPhone/i)?'onclick="this.select();"':'onclick="prompt(\'Select all and copy:\',\''+$config.wallet_address+'\');"';

			$html = ''
				  + ''+$config.lbl_address+''
				  + '<input type="text" readonly '+$sel+'  value="'+$config.wallet_address+'" />'
				  + 'CoinWidget.com'
  				  + ''
  				  + 'x'
  				  + ''
				  ;
			if ($config.counter != 'hide') {
				$html += '0'+$config.lbl_count+''
				  	  + '0.00'+$config.lbl_amount+''
				  	  ;
			}
			if ($config.qrcode) {
				$html += ''
				  	   + ''
				  	   ;
			}
			var $div = $('

');
			$('body').append($div);
			$div.attr({
				'id': 'COINWIDGETCOM_WINDOW_'+$instance
			}).addClass('COINWIDGETCOM_WINDOW COINWIDGETCOM_WINDOW_'+$config.currency.toUpperCase()+' COINWIDGETCOM_WINDOW_'+$config.alignment.toUpperCase()).html($html).unbind('click').bind('click',function(){
				$(".COINWIDGETCOM_WINDOW").css({'z-index':99999999998});
				$(this).css({'z-index':99999999999});
			});
			if ($config.qrcode) {
				$(coin_window).find('.COINWIDGETCOM_QRCODE').bind('mouseenter click',function(){
					$config = CoinWidgetCom.config[$(this).attr('data-coinwidget-instance')];
					$lrg = $(this).parent().find('.COINWIDGETCOM_QRCODE_LARGE');
					if ($lrg.is(':visible')) {
						$lrg.hide();
						return;
					}
					$lrg.attr({
						src: CoinWidgetCom.source +'qr/?address='+$config.wallet_address
					}).show();
				}).bind('mouseleave',function(){
					$lrg = $(this).parent().find('.COINWIDGETCOM_QRCODE_LARGE');
					$lrg.hide();
				});
			}
		} else {
			if ($(coin_window).is(':visible')) {
				CoinWidgetCom.hide($instance);
				return;
			}
		}
		CoinWidgetCom.window_position($instance);
		$(coin_window).show();
		$pos = $(coin_window).find('input').position();
		$(coin_window).find('img.COINWIDGET_INPUT_ICON').css({'top':$pos.top+3,'left':$pos.left+3});
		$(coin_window).find('.COINWIDGETCOM_WALLETURI').css({'top':$pos.top+3,'left':$pos.left+$(coin_window).find('input').outerWidth()+3});
		if ($config.counter != 'hide') {
			$counters = CoinWidgetCom.counter[$instance];
			if ($counters == null) {
				$counters = {
					count: 0,
					amount: 0
				};
			}
		 	if ($counters.count == null) $counters.count = 0;
		 	if ($counters.amount == null) $counters.amount = 0;
			$(coin_window).find('.COINWIDGETCOM_COUNT').html($counters.count+ ''+$config.lbl_count+'');
			$(coin_window).find('.COINWIDGETCOM_AMOUNT').html($counters.amount.toFixed($config.decimals)+ ''+$config.lbl_amount+'');
		}
		if (typeof $config.onShow == 'function')
			$config.onShow();
	}
	, hide: function($instance) {
		$config = CoinWidgetCom.config[$instance];
		coin_window = "#COINWIDGETCOM_WINDOW_"+$instance;
		$(coin_window).fadeOut();
		if (typeof $config.onHide == 'function') {
			$config.onHide();
		}
	}
	, in_array: function(needle,haystack) {
		for (i=0;i<haystack.length;i++) {
			if (haystack[i] == needle) {
				return true;
			}
		}
		return false;
	}
	, loader: {
		loading_jquery: false,
		script: function(obj){
			if (!document.getElementById(obj.id)) {
				var x = document.createElement('script');
				x.onreadystatechange = function(){
					switch (this.readyState) {
						case 'complete':
						case 'loaded':
							obj.callback();
							break;
					}
				};
				x.onload = function(){
					obj.callback();
				};
				x.src = obj.source;
				x.id  = obj.id;
				document.lastChild.firstChild.appendChild(x);
			}
		}
		, stylesheet_loaded: false
		, stylesheet: function(){
			if (!CoinWidgetCom.loader.stylesheet_loaded) {
				CoinWidgetCom.loader.stylesheet_loaded = true;
				var $link = $('<link/>');
				$("head").append($link);
				$link.attr({
					id 		: 'COINWIDGETCOM_STYLESHEET'
					, rel 	: 'stylesheet'
					, type 	: 'text/css'
					, href 	: CoinWidgetCom.source+'coin.css'
				});
			}
		}
		, jquery: function(){
			if (!window.jQuery && !CoinWidgetCom.loader.loading_jquery) {
				$prefix = window.location.protocol=='file:'?'http:':'';
				CoinWidgetCom.loader.script({
					id			: 'COINWIDGETCOM_JQUERY'
					, source 	: $prefix + '//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'
					, callback  : function(){
						CoinWidgetCom.init();
					}
				});
				return;
			}
			CoinWidgetCom.init();
		}
	}
};<|endoftext|>


<commit_before>/**
 * @module robust-notification
 * @summary: This is an implemenation of robust-notification.
 *
 * @description:
 *
 * Author: justin
 * Created On: 2015-06-21.
 * @license Apache-2.0
 */

'use strict';

var p = require('bluebird');
var _ = require('lodash');

module.exports = function construct(config, log, deps) {
  var m = {};
  config = config ? config : {};
  config = _.defaults(config, {});

  deps = deps || {}
  var emailTemplatesAsync = p.promisify(require('email-templates'));

  function sendTemplatedEmail(type, params) {
    var deferred = p.defer();
    emailTemplatesAsync(config.templateDir)
      .then(function(template) {
        var emailSendingActions = [],
          totalEmailsSendingCount = _.isArray(params.recipients) ? params.recipients.length : 1;
        var Render = function (locals) {
          if (params.locals) {
            this.locals = _.extend({}, params.locals, locals);
          } else {
            this.locals = locals;
          }

          this.send = function (err, html, text) {
            params.html = html;
            params.text = text;
            params.recipients = locals.email || locals.recipients;
            if (err) {
              log.error(err);
            } else {
              emailSendingActions.push(m.sendEmail(params)
                .catch(function (err) {
                  log.error(err);
                  // TODO: queue the email if the error was an intermittent issue.
                  throw err;
                }));
              if (totalEmailsSendingCount <= emailSendingActions.length) {
                return p.all(emailSendingActions).then(function (result) {
                  return deferred.resolve(result);
                }, function (err) {
                  return deferred.reject(err);
                });
              }
            }
          };
          this.batch = function (batch) {
            batch(this.locals, config.templateDir, this.send);
          };
        };

        // Load the template and send the emails
        template(params.template || type, true, function (err, batch) {
          if (err) {
            return deferred.reject(err);
          }

          if (_.isArray(params.recipients)) {
            for (var user in params.recipients) {
              var render = new Render(params.recipients[user]);
              render.batch(batch);
            }
          } else if (_.isString(params.recipients)) {
            var render = new Render(params);
            render.batch(batch);
          } else {
            throw 'Unknown recipients.';
          }
        });
      })
      .catch(function(err) {
        return deferred.reject(err);
      });

    return deferred.promise;
  }

  if (config.mediums.email) {
    var nodemailer = deps.nodemailer || require('nodemailer');
    var transport = nodemailer.createTransport(config.mediums.email);

    if (!deps.nodemailer) {
      transport = p.promisifyAll(transport);
    }

    /**
     * sendEmail
     *
     * @param params
     * @returns {*}
     */
    m.sendEmail = function(params) {
      log.debug('sendEmail(params)', params);
      return transport.sendMailAsync({
        from: params.from,
        to: formatRecipients(params.recipients),
        subject: params.subject,
        html: params.html || params.body,
        text: params.text
        //// generateTextFromHTML: true,
        //text: text
      });
    };
  }

  m.send = function(type, params) {
    params = reconcileConfigurationWithLocalParams(config, type, params);

    if (m.sendEmail) {
      params.recipients = formatRecipients(params.recipients);
      return sendTemplatedEmail(type, params);
    } else {
      throw 'sendEmail is not defined.';
    }

    // TODO: add robust fallbacks
    // TODO: add local-storage-fallbacks
  };

  function reconcileConfigurationWithLocalParams(config, type, params) {
    if (config.notificationTypes[type]) {
      params.recipients = params.recipients || config.notificationTypes[type].defaultRecipients;
      params.template = params.template || config.notificationTypes[type].defaultTemplate;
    }
    return params;
  }

  function formatRecipients(recipients) {
    if (_.isArray(recipients)) {
      return _.map(recipients, function(recipient) {
        return recipient.email;
      }).join(',');
    } else {
      return recipients.email;
    }
  }

  return m;
};

<commit_msg>bugfix<commit_after>/**
 * @module robust-notification
 * @summary: This is an implemenation of robust-notification.
 *
 * @description:
 *
 * Author: justin
 * Created On: 2015-06-21.
 * @license Apache-2.0
 */

'use strict';

var p = require('bluebird');
var _ = require('lodash');

module.exports = function construct(config, log, deps) {
  var m = {};
  config = config ? config : {};
  config = _.defaults(config, {});

  deps = deps || {}
  var emailTemplatesAsync = p.promisify(require('email-templates'));

  function sendTemplatedEmail(type, params) {
    var deferred = p.defer();
    emailTemplatesAsync(config.templateDir)
      .then(function(template) {
        var emailSendingActions = [],
          totalEmailsSendingCount = _.isArray(params.recipients) ? params.recipients.length : 1;
        var Render = function (locals) {
          if (params.locals) {
            this.locals = _.extend({}, params.locals, locals);
          } else {
            this.locals = locals;
          }

          this.send = function (err, html, text) {
            params.html = html;
            params.text = text;
            params.recipients = locals.email || locals.recipients;
            if (err) {
              log.error(err);
            } else {
              emailSendingActions.push(m.sendEmail(params)
                .catch(function (err) {
                  log.error(err);
                  // TODO: queue the email if the error was an intermittent issue.
                  throw err;
                }));
              if (totalEmailsSendingCount <= emailSendingActions.length) {
                return p.all(emailSendingActions).then(function (result) {
                  return deferred.resolve(result);
                }, function (err) {
                  return deferred.reject(err);
                });
              }
            }
          };
          this.batch = function (batch) {
            batch(this.locals, config.templateDir, this.send);
          };
        };

        // Load the template and send the emails
        template(params.template || type, true, function (err, batch) {
          if (err) {
            return deferred.reject(err);
          }

          if (_.isArray(params.recipients)) {
            for (var user in params.recipients) {
              var render = new Render(params.recipients[user]);
              render.batch(batch);
            }
          } else if (_.isString(params.recipients)) {
            var render = new Render(params);
            render.batch(batch);
          } else {
            throw 'Unknown recipients.';
          }
        });
      })
      .catch(function(err) {
        return deferred.reject(err);
      });

    return deferred.promise;
  }

  if (config.mediums.email) {
    var nodemailer = deps.nodemailer || require('nodemailer');
    var transport = nodemailer.createTransport(config.mediums.email);

    if (!deps.nodemailer) {
      transport = p.promisifyAll(transport);
    }

    /**
     * sendEmail
     *
     * @param params
     * @returns {*}
     */
    m.sendEmail = function(params) {
      log.debug('sendEmail(params)', params);
      return transport.sendMailAsync({
        from: params.from,
        to: formatRecipients(params.recipients),
        subject: params.subject,
        html: params.html || params.body,
        text: params.text
        //// generateTextFromHTML: true,
        //text: text
      });
    };
  }

  m.send = function(type, params) {
    params = reconcileConfigurationWithLocalParams(config, type, params);

    if (m.sendEmail) {
      params.recipients = formatRecipients(params.recipients);
      return sendTemplatedEmail(type, params);
    } else {
      throw 'sendEmail is not defined.';
    }

    // TODO: add robust fallbacks
    // TODO: add local-storage-fallbacks
  };

  function reconcileConfigurationWithLocalParams(config, type, params) {
    if (config.notificationTypes && config.notificationTypes[type]) {
      params.recipients = params.recipients || config.notificationTypes[type].defaultRecipients;
      params.template = params.template || config.notificationTypes[type].defaultTemplate;
    }
    return params;
  }

  function formatRecipients(recipients) {
    if (_.isArray(recipients)) {
      return _.map(recipients, function(recipient) {
        return recipient.email;
      }).join(',');
    } else {
      return recipients.email;
    }
  }

  return m;
};

<|endoftext|>


<commit_before>import { defaultScrollTarget } from './scrolling.js';
import * as symbols from './symbols.js';
import ReactiveElement from './ReactiveElement.js'; // eslint-disable-line no-unused-vars

/**
 * Scrolls to ensure the selected item is visible
 *
 * When the selected item in a list-like component changes, the selected item
 * should be brought into view so that the user can confirm their selection.
 *
 * This mixin expects an `items` collection, such as that provided by
 * [ContentItemsMixin](ContentItemsMixin). It also expects a
 * `state.selectedIndex` member indicating which item is curently selected. You
 * can supply that yourself, or use
 * [SingleSelectionMixin](SingleSelectionMixin).
 *
 * @module SelectionInViewMixin
 * @param {Constructor<ReactiveElement>} Base
 */
export default function SelectionInViewMixin(Base) {

  // The class prototype added by the mixin.
  class SelectionInView extends Base {

    componentDidMount() {
      if (super.componentDidMount) { super.componentDidMount(); }
      this.scrollSelectionIntoView();
    }

    componentDidUpdate(/** @type {PlainObject} */ changed) {
      if (super.componentDidUpdate) { super.componentDidUpdate(changed); }
      this.scrollSelectionIntoView();
    }

    /**
     * Scroll the selected item element completely into view, minimizing the
     * degree of scrolling performed.
     *
     * Blink has a `scrollIntoViewIfNeeded()` function that does something
     * similar, but unfortunately it's non-standard, and in any event often ends
     * up scrolling more than is absolutely necessary.
     *
     * This scrolls the containing element defined by the `scrollTarget`
     * property. By default, it will scroll the element itself.
     */
    scrollSelectionIntoView() {
      if (super.scrollSelectionIntoView) { super.scrollSelectionIntoView(); }

      const scrollTarget = this[symbols.scrollTarget];
      const { selectedIndex, items } = this.state;
      if (selectedIndex < 0 || !items) {
        return;
      }

      const selectedItem = items[selectedIndex];
      if (!selectedItem) {
        return;
      }

      // Determine the bounds of the scroll target and item. We use
      // getBoundingClientRect instead of .offsetTop, etc., because the latter
      // round values, and we want to handle fractional values.
      const scrollTargetRect = scrollTarget.getBoundingClientRect();
      const itemRect = selectedItem.getBoundingClientRect();

      // Determine how far the item is outside the viewport.
      const bottomDelta = itemRect.bottom - scrollTargetRect.bottom;
      const leftDelta = itemRect.left - scrollTargetRect.left;
      const rightDelta = itemRect.right - scrollTargetRect.right;
      const topDelta = itemRect.top - scrollTargetRect.top;

      // Scroll the target as necessary to bring the item into view.
      // Only scroll along the axis indicated by `orientation` state.
      const { orientation } = this.state;
      if (orientation === 'horizontal' || orientation === 'both') {
        if (rightDelta > 0) {
          scrollTarget.scrollLeft += rightDelta;            // Scroll right
        } else if (leftDelta < 0) {
          scrollTarget.scrollLeft += Math.ceil(leftDelta);  // Scroll left
        }
      }
      if (orientation === 'vertical' || orientation === 'both') {
        if (bottomDelta > 0) {
          scrollTarget.scrollTop += bottomDelta;            // Scroll down
        } else if (topDelta < 0) {
          scrollTarget.scrollTop += Math.ceil(topDelta);    // Scroll up
        }
      }
    }

    /**
     * The element that should be scrolled to get the selected item into view.
     *
     * By default, this uses the [defaultScrollTarget](defaultScrollTarget)
     * helper to find the most likely candidate for scrolling. You can override
     * this property to directly identify which element should be scrolled.
     *
     * See also [symbols.scrollTarget](symbols#scrollTarget).
     */
    get [symbols.scrollTarget]() {
      const base = super[symbols.scrollTarget];
      /** @type {any} */
      const element = this;
      return base || defaultScrollTarget(element);
    }
  }

  return SelectionInView;
}
<commit_msg>On scroll selection into view if selectedIndex actually changed.<commit_after>import { defaultScrollTarget } from './scrolling.js';
import * as symbols from './symbols.js';
import ReactiveElement from './ReactiveElement.js'; // eslint-disable-line no-unused-vars

/**
 * Scrolls to ensure the selected item is visible
 *
 * When the selected item in a list-like component changes, the selected item
 * should be brought into view so that the user can confirm their selection.
 *
 * This mixin expects an `items` collection, such as that provided by
 * [ContentItemsMixin](ContentItemsMixin). It also expects a
 * `state.selectedIndex` member indicating which item is curently selected. You
 * can supply that yourself, or use
 * [SingleSelectionMixin](SingleSelectionMixin).
 *
 * @module SelectionInViewMixin
 * @param {Constructor<ReactiveElement>} Base
 */
export default function SelectionInViewMixin(Base) {

  // The class prototype added by the mixin.
  class SelectionInView extends Base {

    componentDidMount() {
      if (super.componentDidMount) { super.componentDidMount(); }
      this.scrollSelectionIntoView();
    }

    componentDidUpdate(/** @type {PlainObject} */ changed) {
      if (super.componentDidUpdate) { super.componentDidUpdate(changed); }
      if (changed.selectedIndex) {
        this.scrollSelectionIntoView();
      }
    }

    /**
     * Scroll the selected item element completely into view, minimizing the
     * degree of scrolling performed.
     *
     * Blink has a `scrollIntoViewIfNeeded()` function that does something
     * similar, but unfortunately it's non-standard, and in any event often ends
     * up scrolling more than is absolutely necessary.
     *
     * This scrolls the containing element defined by the `scrollTarget`
     * property. By default, it will scroll the element itself.
     */
    scrollSelectionIntoView() {
      if (super.scrollSelectionIntoView) { super.scrollSelectionIntoView(); }

      const scrollTarget = this[symbols.scrollTarget];
      const { selectedIndex, items } = this.state;
      if (selectedIndex < 0 || !items) {
        return;
      }

      const selectedItem = items[selectedIndex];
      if (!selectedItem) {
        return;
      }

      // Determine the bounds of the scroll target and item. We use
      // getBoundingClientRect instead of .offsetTop, etc., because the latter
      // round values, and we want to handle fractional values.
      const scrollTargetRect = scrollTarget.getBoundingClientRect();
      const itemRect = selectedItem.getBoundingClientRect();

      // Determine how far the item is outside the viewport.
      const bottomDelta = itemRect.bottom - scrollTargetRect.bottom;
      const leftDelta = itemRect.left - scrollTargetRect.left;
      const rightDelta = itemRect.right - scrollTargetRect.right;
      const topDelta = itemRect.top - scrollTargetRect.top;

      // Scroll the target as necessary to bring the item into view.
      // Only scroll along the axis indicated by `orientation` state.
      const { orientation } = this.state;
      if (orientation === 'horizontal' || orientation === 'both') {
        if (rightDelta > 0) {
          scrollTarget.scrollLeft += rightDelta;            // Scroll right
        } else if (leftDelta < 0) {
          scrollTarget.scrollLeft += Math.ceil(leftDelta);  // Scroll left
        }
      }
      if (orientation === 'vertical' || orientation === 'both') {
        if (bottomDelta > 0) {
          scrollTarget.scrollTop += bottomDelta;            // Scroll down
        } else if (topDelta < 0) {
          scrollTarget.scrollTop += Math.ceil(topDelta);    // Scroll up
        }
      }
    }

    /**
     * The element that should be scrolled to get the selected item into view.
     *
     * By default, this uses the [defaultScrollTarget](defaultScrollTarget)
     * helper to find the most likely candidate for scrolling. You can override
     * this property to directly identify which element should be scrolled.
     *
     * See also [symbols.scrollTarget](symbols#scrollTarget).
     */
    get [symbols.scrollTarget]() {
      const base = super[symbols.scrollTarget];
      /** @type {any} */
      const element = this;
      return base || defaultScrollTarget(element);
    }
  }

  return SelectionInView;
}
<|endoftext|>


<commit_before>/**
 * @package admiral
 * @author Andrew Munsell <andrew@wizardapps.net>
 * @copyright 2015 WizardApps
 */

var uuid = require('node-uuid'),
    validate = require('validate.js');

exports = module.exports = function(app, config) {
    /**
     * Get the applications
     */
    app.get('/v1/applications', function(req, res) {
        config.getAsync('/applications', { recursive: true })
            .spread(function(result) {
                res
                    .header('Cache-Control', 'private, max-age=60')
                    .json((result.node.nodes || [] ).map(function(node) {
                        return JSON.parse(node.value);
                    }));
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .json([]);
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem retrieving the list of applications.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Create a new application
     */
    app.post('/v1/applications', function(req, res) {
        var constraints = {
            name: {
                presence: true,
                length: {
                    maximum: 36
                }
            }
        };

        var errors = validate(req.body, constraints);
        if(errors) {
            return res
                .status(400)
                .json(errors)
                .end();
        }

        var id = uuid.v4();

        var app = {
            id: id,
            name: req.body.name
        };

        config.setAsync('/applications/' + id, JSON.stringify(app))
            .spread(function(result) {
                res
                    .json(JSON.parse(result.node.value));
            })
            .catch(function(err) {
                res
                    .status(500)
                    .json({
                        error: 500,
                        message: 'There was a problem creating the application.'
                    });
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Get information for the specified application
     */
    app.get('/v1/applications/:id', function(req, res) {
        config.getAsync('/applications/' + req.params.id)
            .spread(function(result) {
                res
                    .header('Cache-Control', 'private, max-age=60')
                    .json(JSON.parse(result.node.value));
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .status(404)
                        .json({
                            error: 404,
                            message: 'The specified application doesn\'t exist.'
                        })
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem retrieving the applications.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Destroy the specified application
     */
    app.delete('/v1/applications/:id', function(req, res) {
        config.getAsync('/applications/' + req.params.id)
            .spread(function(result) {
                return config.delAsync('/applications/' + req.params.id);
            })
            .spread(function(result) {
                res.json({
                    ok: true
                });
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .status(404)
                        .json({
                            error: 404,
                            message: 'The specified application could not be found.'
                        });
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem deleting the specified application.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });
};

exports['@singleton'] = true;
exports['@require'] = ['app', 'config'];<commit_msg>Store the date the application was created at<commit_after>/**
 * @package admiral
 * @author Andrew Munsell <andrew@wizardapps.net>
 * @copyright 2015 WizardApps
 */

var moment = require('moment'),
    uuid = require('node-uuid'),
    validate = require('validate.js');

exports = module.exports = function(app, config) {
    /**
     * Get the applications
     */
    app.get('/v1/applications', function(req, res) {
        config.getAsync('/applications', { recursive: true })
            .spread(function(result) {
                res
                    .header('Cache-Control', 'private, max-age=60')
                    .json((result.node.nodes || [] ).map(function(node) {
                        return JSON.parse(node.value);
                    }));
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .json([]);
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem retrieving the list of applications.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Create a new application
     */
    app.post('/v1/applications', function(req, res) {
        var constraints = {
            name: {
                presence: true,
                length: {
                    maximum: 36
                }
            }
        };

        var errors = validate(req.body, constraints);
        if(errors) {
            return res
                .status(400)
                .json(errors)
                .end();
        }

        var id = uuid.v4();

        var app = {
            id: id,
            name: req.body.name,
            createdAt: moment().toISOString()
        };

        config.setAsync('/applications/' + id, JSON.stringify(app))
            .spread(function(result) {
                res
                    .json(JSON.parse(result.node.value));
            })
            .catch(function(err) {
                res
                    .status(500)
                    .json({
                        error: 500,
                        message: 'There was a problem creating the application.'
                    });
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Get information for the specified application
     */
    app.get('/v1/applications/:id', function(req, res) {
        config.getAsync('/applications/' + req.params.id)
            .spread(function(result) {
                res
                    .header('Cache-Control', 'private, max-age=60')
                    .json(JSON.parse(result.node.value));
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .status(404)
                        .json({
                            error: 404,
                            message: 'The specified application doesn\'t exist.'
                        })
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem retrieving the applications.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });

    /**
     * Destroy the specified application
     */
    app.delete('/v1/applications/:id', function(req, res) {
        config.getAsync('/applications/' + req.params.id)
            .spread(function(result) {
                return config.delAsync('/applications/' + req.params.id);
            })
            .spread(function(result) {
                res.json({
                    ok: true
                });
            })
            .catch(function(err) {
                if(err.errorCode == 100) {
                    res
                        .status(404)
                        .json({
                            error: 404,
                            message: 'The specified application could not be found.'
                        });
                } else {
                    res
                        .status(500)
                        .json({
                            error: 500,
                            message: 'There was a problem deleting the specified application.'
                        });
                }
            })
            .finally(function() {
                res.end();
            });
    });
};

exports['@singleton'] = true;
exports['@require'] = ['app', 'config'];<|endoftext|>


<commit_before>const PU = require('./preferences-util')
const PreferencesSettings = require('./preferences-settings')

class Preferences {

  static delaySettings() {
    let settingsEnabled
    const settingsTab = document.querySelector('.tab-bar [data-type="SettingsView"]')
    if (settingsTab) { settingsEnabled = settingsTab.className.includes('active') }
    if (!settingsTab || !settingsEnabled) { return }
    try {
      this.sv = document.querySelector('.settings-view')

      // NOTE i18n tab-title, placeholder before checking window.I18N.pref.done
      settingsTab.querySelector('.title').textContent = this.defS.Settings['tab-title']
      this.applyPlaceholders()
      if (window.I18N.pref.done) { return }

      this.loadAllSettingsPanels()

      PreferencesSettings.localize()

      this.applyLeftSide()

      // Add Events
      const btns = this.sv.querySelectorAll('div.section:not(.themes-panel) .search-container .btn')
      for (let btn of btns) {
        btn.addEventListener('click', this.applyInstallPanelOnSwitch)
      }

      window.I18N.pref.done = true

      // Restore the flag when the settings panel is closed
      const editorPane = atom.workspace.getActivePane()
      if (editorPane) {
        let handler
        return handler = editorPane.onDidRemoveItem(event => {
          if (event.item.uri === 'atom://config') {
            window.I18N.pref.done = false
          }
          return handler.dispose()
        })
      }
    } catch (e) {
      console.error(`I18N failed with locale ${atom.config.get('atom-i18n.locale')}: `, e)
    }
  }

  static applyPlaceholders() {
    let searchBarPlaceholder = this.sv.querySelector('.keybinding-panel>div:nth-child(3) .placeholder-text')
    if (searchBarPlaceholder) {
      searchBarPlaceholder.textContent = this.defS.Settings.keymaps['search-bar-placeholder']
    }
    this.sv.querySelectorAll('section.section .editor-container .placeholder-text').forEach(div => {
      if (div.textContent.toString().startsWith('Filter packages')) {
        div.textContent = this.defS.Settings.packages.searchBarText
      }
      if (div.textContent.toString().startsWith('Filter themes')) {
        return div.textContent = this.defS.Settings.themes.searchBarText
      }
    })
    searchBarPlaceholder = this.sv.querySelector('div.section:not(.themes-panel) .search-container .placeholder-text')
    if (searchBarPlaceholder) {
      searchBarPlaceholder.textContent = this.defS.Settings.install['searchbar-placeholder']
    }
  }

  static loadAllSettingsPanels() {
    // Load all settings panels
    const lastMenu = this.sv.querySelector('.panels-menu .active a')
    const panelMenus = this.sv.querySelectorAll('.settings-view .panels-menu li a')
    for (let pm of panelMenus) {
      pm.click()
      pm.addEventListener('click', this.applyInstallPanelOnSwitch)
    }
    // Restore last active menu
    if (lastMenu) { lastMenu.click() }
  }

  static applyLeftSide() {
    // Left-side menu
    const menu = this.sv.querySelector('.settings-view .panels-menu')
    if (!menu) { return }
    for (let d of this.defS.Settings.menu) {
      const el = menu.querySelector(`[name='${d._label}']>a`)
      if (el) { PU.applyTextWithOrg(el, d.value) }
    }

    // Left-side button
    const ext = this.sv.querySelector('.settings-view .icon-link-external')
    PU.applyTextWithOrg(ext, this.defS.Settings['btn-open-config-folder'])
  }

  static applyInstallPanelOnSwitch() {
    // NOTE localize all headings with force op
    PU.applySectionHeadings(true)
    PU.applyButtonToolbar()
  }

  static localize(defS) {
    this.defS = defS
    this.updateSettings()  // first time localize
    atom.workspace.onDidChangeActivePaneItem(item => {
      if (!item) { return }
      if (item.__proto__.constructor.name === 'SettingsView') {
        return this.updateSettings(true)
      }
    })
  }

  static updateSettings() {
    setTimeout(() => this.delaySettings(), 0)
  }
}

module.exports = Preferences
<commit_msg>Clean up "unflag"<commit_after>const PU = require('./preferences-util')
const PreferencesSettings = require('./preferences-settings')

class Preferences {

  static delaySettings() {
    let settingsEnabled
    const settingsTab = document.querySelector('.tab-bar [data-type="SettingsView"]')
    if (settingsTab) { settingsEnabled = settingsTab.className.includes('active') }
    if (!settingsTab || !settingsEnabled) { return }
    try {
      this.sv = document.querySelector('.settings-view')

      // NOTE i18n tab-title, placeholder before checking window.I18N.pref.done
      settingsTab.querySelector('.title').textContent = this.defS.Settings['tab-title']
      this.applyPlaceholders()
      if (window.I18N.pref.done) { return }

      this.loadAllSettingsPanels()

      PreferencesSettings.localize()

      this.applyLeftSide()

      // Add Events
      const btns = this.sv.querySelectorAll('div.section:not(.themes-panel) .search-container .btn')
      for (let btn of btns) {
        btn.addEventListener('click', this.applyInstallPanelOnSwitch)
      }

      window.I18N.pref.done = true

      // Restore the flag when the settings panel is closed
      const ediotrPaneItem = atom.workspace.getActivePaneItem()
      if (ediotrPaneItem.uri === 'atom://config') {
        window.I18N.pref.done = false
      }
    } catch (e) {
      console.error(`I18N failed with locale ${atom.config.get('atom-i18n.locale')}: `, e)
    }
  }

  static applyPlaceholders() {
    let searchBarPlaceholder = this.sv.querySelector('.keybinding-panel>div:nth-child(3) .placeholder-text')
    if (searchBarPlaceholder) {
      searchBarPlaceholder.textContent = this.defS.Settings.keymaps['search-bar-placeholder']
    }
    this.sv.querySelectorAll('section.section .editor-container .placeholder-text').forEach(div => {
      if (div.textContent.toString().startsWith('Filter packages')) {
        div.textContent = this.defS.Settings.packages.searchBarText
      }
      if (div.textContent.toString().startsWith('Filter themes')) {
        return div.textContent = this.defS.Settings.themes.searchBarText
      }
    })
    searchBarPlaceholder = this.sv.querySelector('div.section:not(.themes-panel) .search-container .placeholder-text')
    if (searchBarPlaceholder) {
      searchBarPlaceholder.textContent = this.defS.Settings.install['searchbar-placeholder']
    }
  }

  static loadAllSettingsPanels() {
    // Load all settings panels
    const lastMenu = this.sv.querySelector('.panels-menu .active a')
    const panelMenus = this.sv.querySelectorAll('.settings-view .panels-menu li a')
    for (let pm of panelMenus) {
      pm.click()
      pm.addEventListener('click', this.applyInstallPanelOnSwitch)
    }
    // Restore last active menu
    if (lastMenu) { lastMenu.click() }
  }

  static applyLeftSide() {
    // Left-side menu
    const menu = this.sv.querySelector('.settings-view .panels-menu')
    if (!menu) { return }
    for (let d of this.defS.Settings.menu) {
      const el = menu.querySelector(`[name='${d._label}']>a`)
      if (el) { PU.applyTextWithOrg(el, d.value) }
    }

    // Left-side button
    const ext = this.sv.querySelector('.settings-view .icon-link-external')
    PU.applyTextWithOrg(ext, this.defS.Settings['btn-open-config-folder'])
  }

  static applyInstallPanelOnSwitch() {
    // NOTE localize all headings with force op
    PU.applySectionHeadings(true)
    PU.applyButtonToolbar()
  }

  static localize(defS) {
    this.defS = defS
    this.updateSettings()  // first time localize
    atom.workspace.onDidChangeActivePaneItem(item => {
      if (!item) { return }
      if (item.__proto__.constructor.name === 'SettingsView') {
        return this.updateSettings(true)
      }
    })
  }

  static updateSettings() {
    setTimeout(() => this.delaySettings(), 0)
  }
}

module.exports = Preferences
<|endoftext|>


<commit_before>var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var Static = require('node-static');
var config = require('./config');
var Cache = require(config.paths.LIB_ROOT + 'utils/cache');

// create server object
process.mono = new EventEmitter();
process.mono.config = config;

// create caches
process.mono.cache = {
    client: Cache(),
    projects: Cache(),
    instances: Cache(),
    stores: Cache(),
    models: Cache(),
    views: Cache(),
    snippets: Cache(),
    public: Cache()
};

// error handling
process.mono.error = require(config.paths.LIB_ROOT + 'utils/error');

// static file servers
//process.mono.file = {
//    public: new Static.Server(config.paths.PUBLIC_ROOT, {cache: 604800})
//};

// setup session middleware
require(config.paths.MIDDLEWARE + 'session')(function (err) {

    // terminate process on error
    if (err) {
        throw new Error(err);
    }

    // init and cache core module instance
    require(config.paths.MODULE + 'module')();

    // emit api ready
    process.mono.emit('ready');
});
<commit_msg>removed obsolete node-static server instance<commit_after>var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var Static = require('node-static');
var config = require('./config');
var Cache = require(config.paths.LIB_ROOT + 'utils/cache');

// create server object
process.mono = new EventEmitter();
process.mono.config = config;

// create caches
process.mono.cache = {
    client: Cache(),
    projects: Cache(),
    instances: Cache(),
    stores: Cache(),
    models: Cache(),
    views: Cache(),
    snippets: Cache(),
    public: Cache()
};

// error handling
process.mono.error = require(config.paths.LIB_ROOT + 'utils/error');

// setup session middleware
require(config.paths.MIDDLEWARE + 'session')(function (err) {

    // terminate process on error
    if (err) {
        throw new Error(err);
    }

    // init and cache core module instance
    require(config.paths.MODULE + 'module')();

    // emit api ready
    process.mono.emit('ready');
});
<|endoftext|>


<commit_before>let { domainOf, allDomainsOf } = require('./domain_utils.js');
let { stringStartsWith } = require('./utils.js');
let { Matcher, PrefixMatcher, DomainNameMatcher, TextPatterMatcher } = require('./matchers.js');
let XMLHttpRequest = require('sdk/net/xhr').XMLHttpRequest;
let base64 = require("sdk/base64");
let sp = require("sdk/simple-prefs");

if (!String.prototype.eachLine) {
    String.prototype.eachLine = function eachLine(func, lineEnd) {
        lineEnd = lineEnd || "\n";

        let i, stop, lineNo = 0, startIdx = -1;
        for (i = 0; i < this.length; i++) {
            let character = this.charAt(i);
            if (character === lineEnd) {
                stop = func(this.substring(startIdx + 1, i), lineNo);
                if (stop === false) {
                    return;
                }

                startIdx = i;
                lineNo++;
            }
        }

        if (startIdx != i) {
            func(this.substring(startIdx + 1, i), lineNo);
        }
    };
} else {
    console.error("String#eachLine has been defined somewhere else!");
}

function isEmptyOrComment(line) {
    line = line.trim();
    return line.length === 0 || line.charAt(0) == '!';
}

function addValueToKey(obj, key, value) {
    let array = obj[key];
    if (!array) {
        array = [];
        obj[key] = array;
    }

    array.push(value);
}

function parseGfwList(gfwlist) {
    let whiteList = {};
    let proxyList = {};
    let DEFAULT = '__default__';

    gfwlist.eachLine(function(line, idx) {
        if (idx === 0 || isEmptyOrComment(line)) {
            return true;
        }

        let matcher, toList;
        if (stringStartsWith(line, '@@')) { // White list
            let exp = line.substring(2);
            matcher = Matcher.parse(exp);
            toList = whiteList;
        } else {
            matcher = Matcher.parse(line);
            toList = proxyList;
        }

        if (matcher instanceof TextPatterMatcher) {
            if (matcher.isRegex()) {
                addValueToKey(toList, DEFAULT, matcher);
            } else {
                addValueToKey(toList, domainOf(matcher.expression), matcher);
            }
        } else {
            addValueToKey(toList, domainOf(matcher.expression), matcher);
        }

    });

    return { whiteList: whiteList, proxyList: proxyList };
}

function saveGfwList(body) {
    sp.prefs.scriptionCache = body;
}

function getParsedRules(gfwlistURL, callback) {
    if (sp.prefs.scriptionCache) {
        console.log("Loaded subscription from cache");
        callback(parseGfwList(sp.prefs.subscriptionCache));
    } else {
        let xhr = new XMLHttpRequest();
        xhr.onload = function() {
            let responseText = xhr.responseText;
            saveGfwList(responseText);

            let text = responseText.replace(/\s/g, "");
            let gfwlist = base64.decode(text);
            callback(parseGfwList(gfwlist));
        };

        xhr.onerror = function() {
            console.error('failed to get gfwlist');
        };

        xhr.open('GET', gfwlistURL, true);
        xhr.send();
    }
}

exports.getParsedRules = getParsedRules;
<commit_msg>Subscription cache now expires after a day. Also the storage is now simple storage rather than simple preferences.<commit_after>let { domainOf, allDomainsOf } = require('./domain_utils.js');
let { stringStartsWith } = require('./utils.js');
let { Matcher, PrefixMatcher, DomainNameMatcher, TextPatterMatcher } = require('./matchers.js');
let XMLHttpRequest = require('sdk/net/xhr').XMLHttpRequest;
let base64 = require("sdk/base64");
let sp = require("sdk/simple-prefs");
var ss = require("sdk/simple-storage");
const SubscriptionExpiration = 60 * 60 * 24 * 1000; // 1 day in milliseconds.

if (!String.prototype.eachLine) {
    String.prototype.eachLine = function eachLine(func, lineEnd) {
        lineEnd = lineEnd || "\n";

        let i, stop, lineNo = 0, startIdx = -1;
        for (i = 0; i < this.length; i++) {
            let character = this.charAt(i);
            if (character === lineEnd) {
                stop = func(this.substring(startIdx + 1, i), lineNo);
                if (stop === false) {
                    return;
                }

                startIdx = i;
                lineNo++;
            }
        }

        if (startIdx != i) {
            func(this.substring(startIdx + 1, i), lineNo);
        }
    };
} else {
    console.error("String#eachLine has been defined somewhere else!");
}

function isEmptyOrComment(line) {
    line = line.trim();
    return line.length === 0 || line.charAt(0) == '!';
}

function addValueToKey(obj, key, value) {
    let array = obj[key];
    if (!array) {
        array = [];
        obj[key] = array;
    }

    array.push(value);
}

function parseGfwList(gfwlist) {
    let whiteList = {};
    let proxyList = {};
    let DEFAULT = '__default__';

    gfwlist.eachLine(function(line, idx) {
        if (idx === 0 || isEmptyOrComment(line)) {
            return true;
        }

        let matcher, toList;
        if (stringStartsWith(line, '@@')) { // White list
            let exp = line.substring(2);
            matcher = Matcher.parse(exp);
            toList = whiteList;
        } else {
            matcher = Matcher.parse(line);
            toList = proxyList;
        }

        if (matcher instanceof TextPatterMatcher) {
            if (matcher.isRegex()) {
                addValueToKey(toList, DEFAULT, matcher);
            } else {
                addValueToKey(toList, domainOf(matcher.expression), matcher);
            }
        } else {
            addValueToKey(toList, domainOf(matcher.expression), matcher);
        }

    });

    return { whiteList: whiteList, proxyList: proxyList };
}

function saveGfwList(body) {
    ss.storage.subscriptionCache = body;
    ss.storage.subscriptionCachedAt = new Date();
}

function getParsedRules(gfwlistURL, callback) {
    let cachedAt = ss.storage.subscriptionCachedAt;
    console.log('subscription was cached at: ', cachedAt, 'type: ', typeof cachedAt);

    if (cachedAt && (new Date() - new Date(cachedAt) < SubscriptionExpiration) && ss.storage.subscriptionCache) {
        console.log("Loaded subscription from cache");
        callback(parseGfwList(ss.storage.subscriptionCache));
    } else {
        console.log("Updating subscription");

        let xhr = new XMLHttpRequest();
        xhr.onload = function() {
            let responseText = xhr.responseText;
            saveGfwList(responseText);

            let text = responseText.replace(/\s/g, "");
            let gfwlist = base64.decode(text);
            callback(parseGfwList(gfwlist));
        };

        xhr.onerror = function() {
            console.error('failed to get gfwlist');
        };

        xhr.open('GET', gfwlistURL, true);
        xhr.send();
    }
}

exports.getParsedRules = getParsedRules;
<|endoftext|>


<commit_before>'use strict';
var amqp = require('amqplib/callback_api');
var fs = require('fs');
var path = require('path');

var rabbit_chat = {

  help: function () {
    var banner = fs.readFileSync(path.resolve(__dirname, '../banner.txt'));
    console.log(banner.toString());
    console.log("\n\
Usage: rabbit_chat -option [parameter] \n\n\
    options: \n\n\
        -h: Help menu \n\n\
        -v: Get rabbit_chat version \n\n\
        -a: Add a new channel \n\n\
        -g: Get existing channels \n\
            You have to set the user with --u option. \n\n\
        -l: Listen in a existing channel. \n\
            You have to set the user with --u option. \n\n\
        -w: Write a message in a channel.\n");
  },
  version: function() {
    fs.readFile(path.resolve(__dirname, '../package.json'), 'utf8', function(err, data) {
      if (err) throw err;
       console.log(JSON.parse(data).version);
    });
  },
  addChannel: function (user, ch_name) {
    fs.appendFile(path.resolve(__dirname, '..', 'data', 'users_channels', `${user}.txt`), ch_name + '\n', 'utf8', function (err) {
      if (err) throw err;
    });
  },
  getChannels: function (user) {
    fs.readFile(path.resolve(__dirname, '..', 'data', 'users_channels', `${user}.txt`), function (err, data) {
      if (err) throw err;
      var array = data.toString().split("\n");
      for (var i in array) {
        console.log(array[i]);
      }
    });
  },
  listenChannel: function(ch_name) {
    amqp.connect('amqp://localhost', function(err, connection) {
      connection.createChannel(function(err, channel) {
        var exchange = 'chat';

        channel.assertExchange(exchange, 'topic', {durable:false});

        channel.assertQueue('', {exclusive: true}, function(err, queue) {
          console.log("Waiting for messages in %s. To exit press CTRL+C", ch_name);
          ch_name.forEach(function(key) {
            channel.bindQueue(queue.queue, exchange, key);
          });
          channel.consume(queue.queue, function(msg) {
            console.log("%s", msg.content.toString());
          }, {noAck: true});
        });
      });
    });
  },
  write: function(user, key, msg) {
    // Connect to RabbitMQ Server
    amqp.connect('amqp://localhost', function(err, connection) {
      // Create channel
      connection.createChannel(function(err, channel) {
        var exchange = 'chat';

        channel.assertExchange(exchange, 'topic', {durable: false});
        channel.publish(exchange, key, new Buffer(user + ': ' + msg));
      });
      setTimeout(function() { connection.close(); process.exit(0) }, 500);
    });
  }
}

module.exports = rabbit_chat;
<commit_msg>Minor change<commit_after>'use strict';
var amqp = require('amqplib/callback_api');
var fs = require('fs');
var path = require('path');

var rabbit_chat = {

  help: function () {
    var banner = fs.readFileSync(path.resolve(__dirname, '../banner.txt'));
    console.log(banner.toString());
    console.log("\n\
Usage: rabbit_chat -option [parameter] \n\n\
    options: \n\n\
        -h: Help menu \n\n\
        -v: Get rabbit_chat version \n\n\
        -a: Add a new channel \n\n\
        -g: Get existing channels \n\
            You have to set the user with --u option. \n\n\
        -l: Listen in a existing channel. \n\
            You have to set the user with --u option. \n\n\
        -w: Write a message in a channel.\n");
  },
  version: function() {
    fs.readFile(path.resolve(__dirname, '../package.json'), 'utf8',
                function(err, data) {
                  if (err) throw err;
                  console.log(JSON.parse(data).version);
                });
  },
  addChannel: function (user, ch_name) {
    fs.appendFile(path.resolve(__dirname, '..', 'data', 'users_channels', `${user}.txt`),
                  ch_name + '\n', 'utf8', function (err) {
                    if (err) throw err;
                  });
  },
  getChannels: function (user) {
    fs.readFile(path.resolve(__dirname, '..', 'data', 'users_channels', `${user}.txt`),
                function (err, data) {
                  if (err) throw err;
                  var array = data.toString().split("\n");
                  for (var i in array) {
                    console.log(array[i]);
                  }
                });
  },
  listenChannel: function(ch_name) {
    amqp.connect('amqp://localhost', function(err, connection) {
      connection.createChannel(function(err, channel) {
        var exchange = 'chat';

        channel.assertExchange(exchange, 'topic', {durable:false});

        channel.assertQueue('', {exclusive: true}, function(err, queue) {
          console.log("Waiting for messages in %s. To exit press CTRL+C", ch_name);
          ch_name.forEach(function(key) {
            channel.bindQueue(queue.queue, exchange, key);
          });
          channel.consume(queue.queue, function(msg) {
            console.log("%s", msg.content.toString());
          }, {noAck: true});
        });
      });
    });
  },
  write: function(user, key, msg) {
    // Connect to RabbitMQ Server
    amqp.connect('amqp://localhost', function(err, connection) {
      // Create channel
      connection.createChannel(function(err, channel) {
        var exchange = 'chat';

        channel.assertExchange(exchange, 'topic', {durable: false});
        channel.publish(exchange, key, new Buffer(user + ': ' + msg));
      });
      setTimeout(function() { connection.close(); process.exit(0) }, 500);
    });
  }
}

module.exports = rabbit_chat;
<|endoftext|>


<commit_before>var symlink = require('./force_symlink')
var dirname = require('path').dirname
var relative = require('path').relative

/*
 * Relative symlink
 */

module.exports = function relSymlink (src, dest) {
  // Turn it into a relative path when not in win32.
  var rel = process.platform === 'win32'
    ? relative(dirname(dest), src)
    : src

  return symlink(rel, dest, 'junction')
}
<commit_msg>Fix symlink support<commit_after>var symlink = require('./force_symlink')
var dirname = require('path').dirname
var relative = require('path').relative

/*
 * Relative symlink
 */

module.exports = function relSymlink (src, dest) {
  // Turn it into a relative path when not in win32.
  var isWindows = process.platform === 'win32'
  var rel = isWindows ? src : relative(dirname(dest), src)

  return symlink(rel, dest, 'junction')
}
<|endoftext|>


<commit_before>"use babel";

import { CompositeDisposable } from "atom";
import { allowUnsafeNewFunction } from "loophole";
import {
  standardTransforms,
  standardDisplayOrder,
  registerTransform,
  richestMimetype
} from "@nteract/transforms";
import React from "react";
import ReactDOM from "react-dom";
import { Map as ImmutableMap } from "immutable";

import { log } from "./utils";

// Due to Atom's CSP we need to use loophole :(
let PlotlyTransform;
allowUnsafeNewFunction(() => {
  PlotlyTransform = require("@nteract/transform-plotly").default;
});

// We can easily add other transforms here:
const additionalTransforms = [PlotlyTransform];

const {
  transforms,
  displayOrder
} = additionalTransforms.reduce(registerTransform, {
  transforms: standardTransforms,
  displayOrder: standardDisplayOrder
});

export default class ResultView {
  constructor(marker) {
    this.marker = marker;
    this.element = document.createElement("div");
    this.element.classList.add("hydrogen", "output-bubble", "hidden");

    const outputContainer = document.createElement("div");
    outputContainer.classList.add("bubble-output-container");
    const onWheel = event => {
      const clientHeight = outputContainer.clientHeight;
      const scrollHeight = outputContainer.scrollHeight;
      const scrollTop = outputContainer.scrollTop;
      const atTop = scrollTop !== 0 && event.deltaY < 0;
      const atBottom =
        scrollTop !== scrollHeight - clientHeight && event.deltaY > 0;

      if (clientHeight < scrollHeight && (atTop || atBottom)) {
        event.stopPropagation();
      }
    };
    outputContainer.addEventListener("wheel", onWheel, { passive: true });
    this.element.appendChild(outputContainer);

    this.resultContainer = document.createElement("div");
    this.resultContainer.classList.add("bubble-result-container");
    outputContainer.appendChild(this.resultContainer);

    this.errorContainer = document.createElement("div");
    this.errorContainer.classList.add("bubble-error-container");
    outputContainer.appendChild(this.errorContainer);

    this.statusContainer = document.createElement("div");
    this.statusContainer.classList.add("bubble-status-container");
    this.spinner = this.buildSpinner();
    this.statusContainer.appendChild(this.spinner);
    outputContainer.appendChild(this.statusContainer);

    const richCloseButton = document.createElement("div");
    richCloseButton.classList.add("rich-close-button", "icon", "icon-x");
    richCloseButton.onclick = () => this.destroy();
    this.element.appendChild(richCloseButton);

    const actionPanel = document.createElement("div");
    actionPanel.classList.add("bubble-action-panel");
    this.element.appendChild(actionPanel);

    const closeButton = document.createElement("div");
    closeButton.classList.add(
      "action-button",
      "close-button",
      "icon",
      "icon-x"
    );
    closeButton.onclick = () => this.destroy();
    actionPanel.appendChild(closeButton);

    const padding = document.createElement("div");
    padding.classList.add("padding");
    actionPanel.appendChild(padding);

    const copyButton = document.createElement("div");
    copyButton.classList.add(
      "action-button",
      "copy-button",
      "icon",
      "icon-clippy"
    );
    copyButton.onclick = () => {
      atom.clipboard.write(this.getAllText());
      atom.notifications.addSuccess("Copied to clipboard");
    };
    actionPanel.appendChild(copyButton);

    const openButton = document.createElement("div");
    openButton.classList.add(
      "action-button",
      "open-button",
      "icon",
      "icon-file-symlink-file"
    );
    openButton.onclick = () => {
      const bubbleText = this.getAllText();
      atom.workspace.open().then(editor => editor.insertText(bubbleText));
    };
    actionPanel.appendChild(openButton);

    this.setMultiline(false);

    this.tooltips = new CompositeDisposable();
    this.addCopyTooltip(copyButton);
    this.tooltips.add(
      atom.tooltips.add(openButton, { title: "Open in new editor" })
    );

    this._hasResult = false;
    this._executionCount = null;

    return this;
  }

  addCopyTooltip(element) {
    this.tooltips.add(
      atom.tooltips.add(element, {
        title: () => {
          if (!this._executionCount) {
            return "Copy to clipboard";
          }
          return `Copy to clipboard (Out[${this._executionCount}])`;
        }
      })
    );
  }

  addResult(result) {
    let container;

    if (result.stream === "execution_count") {
      this._executionCount = result.data;
      return;
    }

    this.spinner.classList.add("hidden");
    this.element.classList.remove("hidden");

    if (result.stream === "status") {
      if (!this._hasResult && result.data === "ok") {
        log("ResultView: Show status container");
        this.statusContainer.classList.add("icon", "icon-check");
      }
      return;
    }

    log("ResultView: Add result", result);

    if (result.stream === "stderr") {
      container = this.errorContainer;
    } else if (result.stream === "stdout") {
      container = this.resultContainer;
    } else if (result.stream === "error") {
      container = this.errorContainer;
    } else {
      container = this.resultContainer;
    }

    log("ResultView: Hide status container");
    this._hasResult = true;
    this.statusContainer.classList.add("hidden");

    const bundle = new ImmutableMap(result.data);
    const mimeType = richestMimetype(bundle, displayOrder, transforms);
    const Transform = transforms.get(mimeType);

    // If transforms use unsafe eval, we might need to use loophole due to Atom's CSP:
    // allowUnsafeEval(() => {
    //   allowUnsafeNewFunction(() => {
    //     ReactDOM.render(<Transform data={bundle.get(mimeType)} />, div);
    //   });
    // });
    const div = document.createElement("div");
    ReactDOM.render(<Transform data={bundle.get(mimeType)} />, div);

    if (mimeType === "text/plain") {
      this.element.classList.remove("rich");

      const previousText = this.getAllText();
      const text = result.data["text/plain"];
      if (
        previousText === "" &&
        text.length < 50 &&
        (text.indexOf("\n") === text.length - 1 || text.indexOf("\n") === -1)
      ) {
        this.setMultiline(false);

        this.addCopyTooltip(container);

        container.onclick = () => {
          atom.clipboard.write(this.getAllText());
          atom.notifications.addSuccess("Copied to clipboard");
        };
      } else {
        this.setMultiline(true);
      }
    } else if (mimeType === "application/json") {
      this.setMultiline(true);
    } else {
      this.element.classList.add("rich");
      this.setMultiline(true);
    }

    log("ResultView: Rendering as MIME ", mimeType);
    // this.getAllText must be called after appending the htmlElement
    // in order to obtain innerText
    container.appendChild(div);

    if (mimeType === "text/html") {
      if (this.getAllText() !== "") {
        this.element.classList.remove("rich");
      }
    }

    if (mimeType === "image/svg+xml") {
      container.classList.add("svg");
    }

    if (mimeType === "text/markdown") {
      this.element.classList.add("markdown");
      this.element.classList.remove("rich");
    }

    if (mimeType === "text/latex") {
      this.element.classList.add("latex");
    }

    if (this.errorContainer.getElementsByTagName("span").length === 0) {
      this.errorContainer.classList.add("plain-error");
    } else {
      this.errorContainer.classList.remove("plain-error");
    }
  }

  getAllText() {
    let text = "";

    const resultText = this.resultContainer.innerText.trim();
    if (resultText.length > 0) {
      text += resultText;
    }

    const errorText = this.errorContainer.innerText.trim();
    if (errorText.length > 0) {
      text += `\n${errorText}`;
    }

    return text;
  }

  setMultiline(multiline) {
    if (multiline) {
      this.element.classList.add("multiline");
    } else {
      this.element.classList.remove("multiline");
    }
  }

  buildSpinner() {
    const container = document.createElement("div");
    container.classList.add("spinner");

    const rect1 = document.createElement("div");
    rect1.classList.add("rect1");
    const rect2 = document.createElement("div");
    rect2.classList.add("rect2");
    const rect3 = document.createElement("div");
    rect3.classList.add("rect3");
    const rect4 = document.createElement("div");
    rect4.classList.add("rect4");
    const rect5 = document.createElement("div");
    rect5.classList.add("rect5");

    container.appendChild(rect1);
    container.appendChild(rect2);
    container.appendChild(rect3);
    container.appendChild(rect4);
    container.appendChild(rect5);

    return container;
  }

  spin() {
    this.element.classList.remove("hidden");
    this.spinner.classList.remove("hidden");
  }

  destroy() {
    this.tooltips.dispose();
    if (this.marker) {
      this.marker.destroy();
    }
    this.element.innerHTML = "";
  }
}
<commit_msg>Fix inline output detection<commit_after>"use babel";

import { CompositeDisposable } from "atom";
import { allowUnsafeNewFunction } from "loophole";
import {
  standardTransforms,
  standardDisplayOrder,
  registerTransform,
  richestMimetype
} from "@nteract/transforms";
import React from "react";
import ReactDOM from "react-dom";
import { Map as ImmutableMap } from "immutable";

import { log } from "./utils";

// Due to Atom's CSP we need to use loophole :(
let PlotlyTransform;
allowUnsafeNewFunction(() => {
  PlotlyTransform = require("@nteract/transform-plotly").default;
});

// We can easily add other transforms here:
const additionalTransforms = [PlotlyTransform];

const {
  transforms,
  displayOrder
} = additionalTransforms.reduce(registerTransform, {
  transforms: standardTransforms,
  displayOrder: standardDisplayOrder
});

export default class ResultView {
  constructor(marker) {
    this.marker = marker;
    this.element = document.createElement("div");
    this.element.classList.add("hydrogen", "output-bubble", "hidden");

    const outputContainer = document.createElement("div");
    outputContainer.classList.add("bubble-output-container");
    const onWheel = event => {
      const clientHeight = outputContainer.clientHeight;
      const scrollHeight = outputContainer.scrollHeight;
      const scrollTop = outputContainer.scrollTop;
      const atTop = scrollTop !== 0 && event.deltaY < 0;
      const atBottom =
        scrollTop !== scrollHeight - clientHeight && event.deltaY > 0;

      if (clientHeight < scrollHeight && (atTop || atBottom)) {
        event.stopPropagation();
      }
    };
    outputContainer.addEventListener("wheel", onWheel, { passive: true });
    this.element.appendChild(outputContainer);

    this.resultContainer = document.createElement("div");
    this.resultContainer.classList.add("bubble-result-container");
    outputContainer.appendChild(this.resultContainer);

    this.errorContainer = document.createElement("div");
    this.errorContainer.classList.add("bubble-error-container");
    outputContainer.appendChild(this.errorContainer);

    this.statusContainer = document.createElement("div");
    this.statusContainer.classList.add("bubble-status-container");
    this.spinner = this.buildSpinner();
    this.statusContainer.appendChild(this.spinner);
    outputContainer.appendChild(this.statusContainer);

    const richCloseButton = document.createElement("div");
    richCloseButton.classList.add("rich-close-button", "icon", "icon-x");
    richCloseButton.onclick = () => this.destroy();
    this.element.appendChild(richCloseButton);

    const actionPanel = document.createElement("div");
    actionPanel.classList.add("bubble-action-panel");
    this.element.appendChild(actionPanel);

    const closeButton = document.createElement("div");
    closeButton.classList.add(
      "action-button",
      "close-button",
      "icon",
      "icon-x"
    );
    closeButton.onclick = () => this.destroy();
    actionPanel.appendChild(closeButton);

    const padding = document.createElement("div");
    padding.classList.add("padding");
    actionPanel.appendChild(padding);

    const copyButton = document.createElement("div");
    copyButton.classList.add(
      "action-button",
      "copy-button",
      "icon",
      "icon-clippy"
    );
    copyButton.onclick = () => {
      atom.clipboard.write(this.getAllText());
      atom.notifications.addSuccess("Copied to clipboard");
    };
    actionPanel.appendChild(copyButton);

    const openButton = document.createElement("div");
    openButton.classList.add(
      "action-button",
      "open-button",
      "icon",
      "icon-file-symlink-file"
    );
    openButton.onclick = () => {
      const bubbleText = this.getAllText();
      atom.workspace.open().then(editor => editor.insertText(bubbleText));
    };
    actionPanel.appendChild(openButton);

    this.setMultiline(false);

    this.tooltips = new CompositeDisposable();
    this.addCopyTooltip(copyButton);
    this.tooltips.add(
      atom.tooltips.add(openButton, { title: "Open in new editor" })
    );

    this._hasResult = false;
    this._executionCount = null;

    return this;
  }

  addCopyTooltip(element) {
    this.tooltips.add(
      atom.tooltips.add(element, {
        title: () => {
          if (!this._executionCount) {
            return "Copy to clipboard";
          }
          return `Copy to clipboard (Out[${this._executionCount}])`;
        }
      })
    );
  }

  addResult(result) {
    let container;

    if (result.stream === "execution_count") {
      this._executionCount = result.data;
      return;
    }

    this.spinner.classList.add("hidden");
    this.element.classList.remove("hidden");

    if (result.stream === "status") {
      if (!this._hasResult && result.data === "ok") {
        log("ResultView: Show status container");
        this.statusContainer.classList.add("icon", "icon-check");
      }
      return;
    }

    log("ResultView: Add result", result);

    if (result.stream === "stderr") {
      container = this.errorContainer;
    } else if (result.stream === "stdout") {
      container = this.resultContainer;
    } else if (result.stream === "error") {
      container = this.errorContainer;
    } else {
      container = this.resultContainer;
    }

    log("ResultView: Hide status container");
    this._hasResult = true;
    this.statusContainer.classList.add("hidden");

    const bundle = new ImmutableMap(result.data);
    const mimeType = richestMimetype(bundle, displayOrder, transforms);
    const Transform = transforms.get(mimeType);

    // If transforms use unsafe eval, we might need to use loophole due to Atom's CSP:
    // allowUnsafeEval(() => {
    //   allowUnsafeNewFunction(() => {
    //     ReactDOM.render(<Transform data={bundle.get(mimeType)} />, div);
    //   });
    // });
    const div = document.createElement("div");
    ReactDOM.render(<Transform data={bundle.get(mimeType)} />, div);

    if (mimeType === "text/plain") {
      this.element.classList.remove("rich");
      const text = result.data["text/plain"];

      if (
        this.resultContainer.innerHTML === "" &&
        this.errorContainer.innerHTML === "" &&
        text.length < 50 &&
        (text.indexOf("\n") === text.length - 1 || text.indexOf("\n") === -1)
      ) {
        this.setMultiline(false);

        this.addCopyTooltip(container);

        container.onclick = () => {
          atom.clipboard.write(this.getAllText());
          atom.notifications.addSuccess("Copied to clipboard");
        };
      } else {
        this.setMultiline(true);
      }
    } else if (mimeType === "application/json") {
      this.setMultiline(true);
    } else {
      this.element.classList.add("rich");
      this.setMultiline(true);
    }

    log("ResultView: Rendering as MIME ", mimeType);
    // this.getAllText must be called after appending the htmlElement
    // in order to obtain innerText
    container.appendChild(div);

    if (mimeType === "text/html") {
      if (this.getAllText() !== "") {
        this.element.classList.remove("rich");
      }
    }

    if (mimeType === "image/svg+xml") {
      container.classList.add("svg");
    }

    if (mimeType === "text/markdown") {
      this.element.classList.add("markdown");
      this.element.classList.remove("rich");
    }

    if (mimeType === "text/latex") {
      this.element.classList.add("latex");
    }

    if (this.errorContainer.getElementsByTagName("span").length === 0) {
      this.errorContainer.classList.add("plain-error");
    } else {
      this.errorContainer.classList.remove("plain-error");
    }
  }

  getAllText() {
    let text = "";

    const resultText = this.resultContainer.innerText.trim();
    if (resultText.length > 0) {
      text += resultText;
    }

    const errorText = this.errorContainer.innerText.trim();
    if (errorText.length > 0) {
      text += `\n${errorText}`;
    }

    return text;
  }

  setMultiline(multiline) {
    if (multiline) {
      this.element.classList.add("multiline");
    } else {
      this.element.classList.remove("multiline");
    }
  }

  buildSpinner() {
    const container = document.createElement("div");
    container.classList.add("spinner");

    const rect1 = document.createElement("div");
    rect1.classList.add("rect1");
    const rect2 = document.createElement("div");
    rect2.classList.add("rect2");
    const rect3 = document.createElement("div");
    rect3.classList.add("rect3");
    const rect4 = document.createElement("div");
    rect4.classList.add("rect4");
    const rect5 = document.createElement("div");
    rect5.classList.add("rect5");

    container.appendChild(rect1);
    container.appendChild(rect2);
    container.appendChild(rect3);
    container.appendChild(rect4);
    container.appendChild(rect5);

    return container;
  }

  spin() {
    this.element.classList.remove("hidden");
    this.spinner.classList.remove("hidden");
  }

  destroy() {
    this.tooltips.dispose();
    if (this.marker) {
      this.marker.destroy();
    }
    this.element.innerHTML = "";
  }
}
<|endoftext|>